about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/command/cmd_ac.c96
-rw-r--r--src/command/cmd_defs.c39
-rw-r--r--src/command/cmd_funcs.c207
-rw-r--r--src/command/cmd_funcs.h2
-rw-r--r--src/config/preferences.c43
-rw-r--r--src/config/preferences.h9
-rw-r--r--src/config/theme.c11
-rw-r--r--src/event/server_events.c4
-rw-r--r--src/plugins/api.c2
-rw-r--r--src/ui/chatwin.c14
-rw-r--r--src/ui/console.c46
-rw-r--r--src/ui/core.c47
-rw-r--r--src/ui/inputwin.c4
-rw-r--r--src/ui/mucwin.c19
-rw-r--r--src/ui/privwin.c4
-rw-r--r--src/ui/statusbar.c702
-rw-r--r--src/ui/statusbar.h13
-rw-r--r--src/ui/ui.h7
-rw-r--r--src/ui/win_types.h2
-rw-r--r--src/ui/window.c54
-rw-r--r--src/ui/window_list.c41
-rw-r--r--src/ui/window_list.h2
-rw-r--r--tests/unittests/ui/stub_ui.c10
-rw-r--r--themes/boothj56
24 files changed, 904 insertions, 480 deletions
diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c
index bb6e9cd6..c996d814 100644
--- a/src/command/cmd_ac.c
+++ b/src/command/cmd_ac.c
@@ -99,6 +99,7 @@ static char* _blocked_autocomplete(ProfWin *window, const char *const input, gbo
 static char* _tray_autocomplete(ProfWin *window, const char *const input, gboolean previous);
 static char* _presence_autocomplete(ProfWin *window, const char *const input, gboolean previous);
 static char* _rooms_autocomplete(ProfWin *window, const char *const input, gboolean previous);
+static char* _statusbar_autocomplete(ProfWin *window, const char *const input, gboolean previous);
 
 static char* _script_autocomplete_func(const char *const prefix, gboolean previous);
 
@@ -199,6 +200,11 @@ static Autocomplete tray_ac;
 static Autocomplete presence_ac;
 static Autocomplete presence_setting_ac;
 static Autocomplete winpos_ac;
+static Autocomplete statusbar_ac;
+static Autocomplete statusbar_self_ac;
+static Autocomplete statusbar_chat_ac;
+static Autocomplete statusbar_room_ac;
+static Autocomplete statusbar_show_ac;
 
 void
 cmd_ac_init(void)
@@ -386,8 +392,6 @@ cmd_ac_init(void)
     wins_ac = autocomplete_new();
     autocomplete_add(wins_ac, "unread");
     autocomplete_add(wins_ac, "prune");
-    autocomplete_add(wins_ac, "tidy");
-    autocomplete_add(wins_ac, "autotidy");
     autocomplete_add(wins_ac, "swap");
 
     roster_ac = autocomplete_new();
@@ -774,6 +778,34 @@ cmd_ac_init(void)
     winpos_ac = autocomplete_new();
     autocomplete_add(winpos_ac, "up");
     autocomplete_add(winpos_ac, "down");
+
+    statusbar_ac = autocomplete_new();
+    autocomplete_add(statusbar_ac, "up");
+    autocomplete_add(statusbar_ac, "down");
+    autocomplete_add(statusbar_ac, "show");
+    autocomplete_add(statusbar_ac, "hide");
+    autocomplete_add(statusbar_ac, "maxtabs");
+    autocomplete_add(statusbar_ac, "self");
+    autocomplete_add(statusbar_ac, "chat");
+    autocomplete_add(statusbar_ac, "room");
+
+    statusbar_self_ac = autocomplete_new();
+    autocomplete_add(statusbar_self_ac, "user");
+    autocomplete_add(statusbar_self_ac, "barejid");
+    autocomplete_add(statusbar_self_ac, "fulljid");
+    autocomplete_add(statusbar_self_ac, "off");
+
+    statusbar_chat_ac = autocomplete_new();
+    autocomplete_add(statusbar_chat_ac, "user");
+    autocomplete_add(statusbar_chat_ac, "jid");
+
+    statusbar_room_ac = autocomplete_new();
+    autocomplete_add(statusbar_room_ac, "room");
+    autocomplete_add(statusbar_room_ac, "jid");
+
+    statusbar_show_ac = autocomplete_new();
+    autocomplete_add(statusbar_show_ac, "name");
+    autocomplete_add(statusbar_show_ac, "number");
 }
 
 void
@@ -1055,6 +1087,11 @@ cmd_ac_reset(ProfWin *window)
     autocomplete_reset(presence_ac);
     autocomplete_reset(presence_setting_ac);
     autocomplete_reset(winpos_ac);
+    autocomplete_reset(statusbar_ac);
+    autocomplete_reset(statusbar_self_ac);
+    autocomplete_reset(statusbar_chat_ac);
+    autocomplete_reset(statusbar_room_ac);
+    autocomplete_reset(statusbar_show_ac);
 
     autocomplete_reset(script_ac);
     if (script_show_ac) {
@@ -1182,6 +1219,11 @@ cmd_ac_uninit(void)
     autocomplete_free(presence_ac);
     autocomplete_free(presence_setting_ac);
     autocomplete_free(winpos_ac);
+    autocomplete_free(statusbar_ac);
+    autocomplete_free(statusbar_self_ac);
+    autocomplete_free(statusbar_chat_ac);
+    autocomplete_free(statusbar_room_ac);
+    autocomplete_free(statusbar_show_ac);
 }
 
 char*
@@ -1301,7 +1343,7 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ
 
     // autocomplete boolean settings
     gchar *boolean_choices[] = { "/beep", "/intype", "/states", "/outtype", "/flash", "/splash", "/chlog", "/grlog",
-        "/history", "/vercheck", "/privileges", "/wrap", "/winstidy", "/carbons", "/encwarn",
+        "/history", "/vercheck", "/privileges", "/wrap", "/carbons", "/encwarn",
         "/lastactivity" };
 
     for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
@@ -1369,8 +1411,8 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ
         }
     }
 
-    gchar *cmds[] = { "/prefs", "/disco", "/room", "/autoping", "/titlebar", "/mainwin", "/statusbar", "/inputwin" };
-    Autocomplete completers[] = { prefs_ac, disco_ac, room_ac, autoping_ac, winpos_ac, winpos_ac, winpos_ac, winpos_ac };
+    gchar *cmds[] = { "/prefs", "/disco", "/room", "/autoping", "/titlebar", "/mainwin", "/inputwin" };
+    Autocomplete completers[] = { prefs_ac, disco_ac, room_ac, autoping_ac, winpos_ac, winpos_ac, winpos_ac };
 
     for (i = 0; i < ARRAY_SIZE(cmds); i++) {
         result = autocomplete_param_with_ac(input, cmds[i], completers[i], TRUE, previous);
@@ -1421,6 +1463,7 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ
     g_hash_table_insert(ac_funcs, "/tray",          _tray_autocomplete);
     g_hash_table_insert(ac_funcs, "/presence",      _presence_autocomplete);
     g_hash_table_insert(ac_funcs, "/rooms",         _rooms_autocomplete);
+    g_hash_table_insert(ac_funcs, "/statusbar",     _statusbar_autocomplete);
 
     int len = strlen(input);
     char parsed[len+1];
@@ -2632,11 +2675,6 @@ _wins_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 {
     char *result = NULL;
 
-    result = autocomplete_param_with_func(input, "/wins autotidy", prefs_autocomplete_boolean_choice, previous);
-    if (result) {
-        return result;
-    }
-
     result = autocomplete_param_with_ac(input, "/wins", wins_ac, TRUE, previous);
     if (result) {
         return result;
@@ -3181,3 +3219,41 @@ _rooms_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 
     return NULL;
 }
+
+static char*
+_statusbar_autocomplete(ProfWin *window, const char *const input, gboolean previous)
+{
+    char *found = NULL;
+
+    found = autocomplete_param_with_ac(input, "/statusbar", statusbar_ac, TRUE, previous);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/statusbar show", statusbar_show_ac, TRUE, previous);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/statusbar hide", statusbar_show_ac, TRUE, previous);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/statusbar self", statusbar_self_ac, TRUE, previous);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/statusbar chat", statusbar_chat_ac, TRUE, previous);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/statusbar room", statusbar_room_ac, TRUE, previous);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c
index cb2aa842..d6ee9be6 100644
--- a/src/command/cmd_defs.c
+++ b/src/command/cmd_defs.c
@@ -962,18 +962,14 @@ static struct cmd_t command_defs[] =
         parse_args, 0, 3, NULL,
         CMD_SUBFUNCS(
             { "unread",     cmd_wins_unread },
-            { "tidy",       cmd_wins_tidy },
             { "prune",      cmd_wins_prune },
-            { "swap",       cmd_wins_swap },
-            { "autotidy",   cmd_wins_autotidy })
+            { "swap",       cmd_wins_swap })
         CMD_MAINFUNC(cmd_wins)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
             "/wins",
             "/wins unread",
-            "/wins tidy",
-            "/wins autotidy on|off",
             "/wins prune",
             "/wins swap <source> <target>")
         CMD_DESC(
@@ -981,9 +977,7 @@ static struct cmd_t command_defs[] =
             "Passing no argument will list all currently active windows and information about their usage.")
         CMD_ARGS(
             { "unread",                 "List windows with unread messages." },
-            { "tidy",                   "Move windows so there are no gaps." },
-            { "autotidy on|off",        "Automatically remove gaps when closing windows." },
-            { "prune",                  "Close all windows with no unread messages, and then tidy so there are no gaps." },
+            { "prune",                  "Close all windows with no unread messages." },
             { "swap <source> <target>", "Swap windows, target may be an empty position." })
         CMD_NOEXAMPLES
     },
@@ -1358,20 +1352,37 @@ static struct cmd_t command_defs[] =
     },
 
     { "/statusbar",
-        parse_args, 1, 1, &cons_winpos_setting,
+        parse_args, 1, 2, &cons_statusbar_setting,
         CMD_NOSUBFUNCS
         CMD_MAINFUNC(cmd_statusbar)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
+            "/statusbar show name|number",
+            "/statusbar hide name|number",
+            "/statusbar maxtabs <value>",
+            "/statusbar self user|barejid|fulljid|off",
+            "/statusbar chat user|jid",
+            "/statusbar room room|jid",
             "/statusbar up",
             "/statusbar down")
         CMD_DESC(
-            "Move the status bar.")
-        CMD_ARGS(
-            { "up", "Move the status bar up the screen." },
-            { "down", "Move the status bar down the screen." })
-        CMD_NOEXAMPLES
+            "Manage statusbar display preferences.")
+        CMD_ARGS(
+            { "maxtabs <value>",            "Set the maximum number of tabs to display, <value> must be between 0 and 10" },
+            { "show|hide name",             "Show or hide names in tabs." },
+            { "show|hide number",           "Show or hide numbers in tabs." },
+            { "self user|barejid|fulljid",  "Show account user name, barejid, fulljid as status bar title." },
+            { "self off",                   "Disable showing self as status bar title." },
+            { "chat user|jid",              "Show users name, or the fulljid if no nick is present for chat tabs." },
+            { "room room|jid",              "Show room name, or the fulljid for room tabs." },
+            { "up",                         "Move the status bar up the screen." },
+            { "down",                       "Move the status bar down the screen." })
+        CMD_EXAMPLES(
+            "/statusbar maxtabs 5",
+            "/statusbar self user",
+            "/statusbar chat jid",
+            "/statusbar hide name")
     },
 
     { "/inputwin",
diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c
index 53c8b9ed..11f1f51c 100644
--- a/src/command/cmd_funcs.c
+++ b/src/command/cmd_funcs.c
@@ -1253,17 +1253,6 @@ cmd_wins_unread(ProfWin *window, const char *const command, gchar **args)
 }
 
 gboolean
-cmd_wins_tidy(ProfWin *window, const char *const command, gchar **args)
-{
-    if (wins_tidy()) {
-        cons_show("Windows tidied.");
-    } else {
-        cons_show("No tidy needed.");
-    }
-    return TRUE;
-}
-
-gboolean
 cmd_wins_prune(ProfWin *window, const char *const command, gchar **args)
 {
     ui_prune_wins();
@@ -1280,38 +1269,34 @@ cmd_wins_swap(ProfWin *window, const char *const command, gchar **args)
 
     int source_win = atoi(args[1]);
     int target_win = atoi(args[2]);
+
     if ((source_win == 1) || (target_win == 1)) {
         cons_show("Cannot move console window.");
-    } else if (source_win == 10 || target_win == 10) {
+        return TRUE;
+    }
+
+    if (source_win == 10 || target_win == 10) {
         cons_show("Window 10 does not exist");
-    } else if (source_win != target_win) {
-        gboolean swapped = wins_swap(source_win, target_win);
-        if (swapped) {
-            cons_show("Swapped windows %d <-> %d", source_win, target_win);
-        } else {
-            cons_show("Window %d does not exist", source_win);
-        }
-    } else {
+        return TRUE;
+    }
+
+    if (source_win == target_win) {
         cons_show("Same source and target window supplied.");
+        return TRUE;
     }
 
-    return TRUE;
-}
+    if (wins_get_by_num(source_win) == NULL) {
+        cons_show("Window %d does not exist", source_win);
+        return TRUE;
+    }
 
-gboolean
-cmd_wins_autotidy(ProfWin *window, const char *const command, gchar **args)
-{
-    if (g_strcmp0(args[1], "on") == 0) {
-        cons_show("Window autotidy enabled");
-        prefs_set_boolean(PREF_WINS_AUTO_TIDY, TRUE);
-        wins_tidy();
-    } else if (g_strcmp0(args[1], "off") == 0) {
-        cons_show("Window autotidy disabled");
-        prefs_set_boolean(PREF_WINS_AUTO_TIDY, FALSE);
-    } else {
-        cons_bad_cmd_usage(command);
+    if (wins_get_by_num(target_win) == NULL) {
+        cons_show("Window %d does not exist", target_win);
+        return TRUE;
     }
 
+    wins_swap(source_win, target_win);
+    cons_show("Swapped windows %d <-> %d", source_win, target_win);
     return TRUE;
 }
 
@@ -1407,11 +1392,7 @@ cmd_close(ProfWin *window, const char *const command, gchar **args)
         // close the window
         ui_close_win(index);
         cons_show("Closed window %d", index);
-
-        // Tidy up the window list.
-        if (prefs_get_boolean(PREF_WINS_AUTO_TIDY)) {
-            wins_tidy();
-        }
+        wins_tidy();
 
         rosterwin_roster();
         return TRUE;
@@ -1442,11 +1423,7 @@ cmd_close(ProfWin *window, const char *const command, gchar **args)
         // close the window
         ui_close_win(index);
         cons_show("Closed window %s", args[0]);
-
-        // Tidy up the window list.
-        if (prefs_get_boolean(PREF_WINS_AUTO_TIDY)) {
-            wins_tidy();
-        }
+        wins_tidy();
 
         rosterwin_roster();
         return TRUE;
@@ -2095,7 +2072,7 @@ cmd_who(ProfWin *window, const char *const command, gchar **args)
     }
 
     if (window->type != WIN_CONSOLE && window->type != WIN_MUC) {
-        status_bar_new(1);
+        status_bar_new(1, WIN_CONSOLE, "console");
     }
 
     return TRUE;
@@ -3942,6 +3919,7 @@ cmd_form(ProfWin *window, const char *const command, gchar **args)
         }
         ui_focus_win(new_current);
         wins_close_by_num(num);
+        wins_tidy();
     }
 
     return TRUE;
@@ -5792,6 +5770,145 @@ cmd_mainwin(ProfWin *window, const char *const command, gchar **args)
 gboolean
 cmd_statusbar(ProfWin *window, const char *const command, gchar **args)
 {
+    if (g_strcmp0(args[0], "show") == 0) {
+        if (g_strcmp0(args[1], "name") == 0) {
+            prefs_set_boolean(PREF_STATUSBAR_SHOW_NAME, TRUE);
+            cons_show("Enabled showing tab names.");
+            ui_resize();
+            return TRUE;
+        }
+        if (g_strcmp0(args[1], "number") == 0) {
+            prefs_set_boolean(PREF_STATUSBAR_SHOW_NUMBER, TRUE);
+            cons_show("Enabled showing tab numbers.");
+            ui_resize();
+            return TRUE;
+        }
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    if (g_strcmp0(args[0], "hide") == 0) {
+        if (g_strcmp0(args[1], "name") == 0) {
+            if (prefs_get_boolean(PREF_STATUSBAR_SHOW_NUMBER) == FALSE) {
+                cons_show("Cannot disable both names and numbers in statusbar.");
+                cons_show("Use '/statusbar maxtabs 0' to hide tabs.");
+                return TRUE;
+            }
+            prefs_set_boolean(PREF_STATUSBAR_SHOW_NAME, FALSE);
+            cons_show("Disabled showing tab names.");
+            ui_resize();
+            return TRUE;
+        }
+        if (g_strcmp0(args[1], "number") == 0) {
+            if (prefs_get_boolean(PREF_STATUSBAR_SHOW_NAME) == FALSE) {
+                cons_show("Cannot disable both names and numbers in statusbar.");
+                cons_show("Use '/statusbar maxtabs 0' to hide tabs.");
+                return TRUE;
+            }
+            prefs_set_boolean(PREF_STATUSBAR_SHOW_NUMBER, FALSE);
+            cons_show("Disabled showing tab numbers.");
+            ui_resize();
+            return TRUE;
+        }
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    if (g_strcmp0(args[0], "maxtabs") == 0) {
+        if (args[1] == NULL) {
+            cons_bad_cmd_usage(command);
+            return TRUE;
+        }
+
+        char *value = args[1];
+        int intval = 0;
+        char *err_msg = NULL;
+        gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg);
+        if (res) {
+            if (intval < 0 || intval > 10) {
+                cons_bad_cmd_usage(command);
+                return TRUE;
+            }
+
+            prefs_set_statusbartabs(intval);
+            if (intval == 0) {
+                cons_show("Status bar tabs disabled.");
+            } else {
+                cons_show("Status bar tabs set to %d.", intval);
+            }
+            ui_resize();
+            return TRUE;
+        } else {
+            cons_show(err_msg);
+            cons_bad_cmd_usage(command);
+            free(err_msg);
+            return TRUE;
+        }
+    }
+
+    if (g_strcmp0(args[0], "self") == 0) {
+        if (g_strcmp0(args[1], "barejid") == 0) {
+            prefs_set_string(PREF_STATUSBAR_SELF, "barejid");
+            cons_show("Using barejid for statusbar title.");
+            ui_resize();
+            return TRUE;
+        }
+        if (g_strcmp0(args[1], "fulljid") == 0) {
+            prefs_set_string(PREF_STATUSBAR_SELF, "fulljid");
+            cons_show("Using fulljid for statusbar title.");
+            ui_resize();
+            return TRUE;
+        }
+        if (g_strcmp0(args[1], "user") == 0) {
+            prefs_set_string(PREF_STATUSBAR_SELF, "user");
+            cons_show("Using user for statusbar title.");
+            ui_resize();
+            return TRUE;
+        }
+        if (g_strcmp0(args[1], "off") == 0) {
+            prefs_set_string(PREF_STATUSBAR_SELF, "off");
+            cons_show("Disabling statusbar title.");
+            ui_resize();
+            return TRUE;
+        }
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    if (g_strcmp0(args[0], "chat") == 0) {
+        if (g_strcmp0(args[1], "jid") == 0) {
+            prefs_set_string(PREF_STATUSBAR_CHAT, "jid");
+            cons_show("Using jid for chat tabs.");
+            ui_resize();
+            return TRUE;
+        }
+        if (g_strcmp0(args[1], "user") == 0) {
+            prefs_set_string(PREF_STATUSBAR_CHAT, "user");
+            cons_show("Using user for chat tabs.");
+            ui_resize();
+            return TRUE;
+        }
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    if (g_strcmp0(args[0], "room") == 0) {
+        if (g_strcmp0(args[1], "jid") == 0) {
+            prefs_set_string(PREF_STATUSBAR_ROOM, "jid");
+            cons_show("Using jid for room tabs.");
+            ui_resize();
+            return TRUE;
+        }
+        if (g_strcmp0(args[1], "room") == 0) {
+            prefs_set_string(PREF_STATUSBAR_ROOM, "room");
+            cons_show("Using room name for room tabs.");
+            ui_resize();
+            return TRUE;
+        }
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
     if (g_strcmp0(args[0], "up") == 0) {
         gboolean result = prefs_statusbar_pos_up();
         if (result) {
diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h
index aa703f6d..0bbf338e 100644
--- a/src/command/cmd_funcs.h
+++ b/src/command/cmd_funcs.h
@@ -205,10 +205,8 @@ gboolean cmd_otr_answer(ProfWin *window, const char *const command, gchar **args
 
 gboolean cmd_wins(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_wins_unread(ProfWin *window, const char *const command, gchar **args);
-gboolean cmd_wins_tidy(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_wins_prune(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_wins_swap(ProfWin *window, const char *const command, gchar **args);
-gboolean cmd_wins_autotidy(ProfWin *window, const char *const command, gchar **args);
 
 gboolean cmd_form_field(ProfWin *window, char *tag, gchar **args);
 
diff --git a/src/config/preferences.c b/src/config/preferences.c
index d935061c..8b2ad10a 100644
--- a/src/config/preferences.c
+++ b/src/config/preferences.c
@@ -663,6 +663,23 @@ prefs_get_tray_timer(void)
     }
 }
 
+gint
+prefs_get_statusbartabs(void)
+{
+    if (!g_key_file_has_key(prefs, PREF_GROUP_UI, "statusbar.tabs", NULL)) {
+        return 10;
+    } else {
+        return g_key_file_get_integer(prefs, PREF_GROUP_UI, "statusbar.tabs", NULL);
+    }
+}
+
+void
+prefs_set_statusbartabs(gint value)
+{
+    g_key_file_set_integer(prefs, PREF_GROUP_UI, "statusbar.tabs", value);
+    _save_prefs();
+}
+
 gchar**
 prefs_get_plugins(void)
 {
@@ -1530,7 +1547,6 @@ _get_group(preference_t pref)
         case PREF_MUC_PRIVILEGES:
         case PREF_PRESENCE:
         case PREF_WRAP:
-        case PREF_WINS_AUTO_TIDY:
         case PREF_TIME_CONSOLE:
         case PREF_TIME_CHAT:
         case PREF_TIME_MUC:
@@ -1570,6 +1586,11 @@ _get_group(preference_t pref)
         case PREF_CONSOLE_MUC:
         case PREF_CONSOLE_PRIVATE:
         case PREF_CONSOLE_CHAT:
+        case PREF_STATUSBAR_SHOW_NAME:
+        case PREF_STATUSBAR_SHOW_NUMBER:
+        case PREF_STATUSBAR_SELF:
+        case PREF_STATUSBAR_CHAT:
+        case PREF_STATUSBAR_ROOM:
             return PREF_GROUP_UI;
         case PREF_STATES:
         case PREF_OUTTYPE:
@@ -1733,8 +1754,6 @@ _get_key(preference_t pref)
             return "presence";
         case PREF_WRAP:
             return "wrap";
-        case PREF_WINS_AUTO_TIDY:
-            return "wins.autotidy";
         case PREF_TIME_CONSOLE:
             return "time.console";
         case PREF_TIME_CHAT:
@@ -1825,6 +1844,16 @@ _get_key(preference_t pref)
             return "sourcepath";
         case PREF_ROOM_LIST_CACHE:
             return "rooms.cache";
+        case PREF_STATUSBAR_SHOW_NAME:
+            return "statusbar.show.name";
+        case PREF_STATUSBAR_SHOW_NUMBER:
+            return "statusbar.show.number";
+        case PREF_STATUSBAR_SELF:
+            return "statusbar.self";
+        case PREF_STATUSBAR_CHAT:
+            return "statusbar.chat";
+        case PREF_STATUSBAR_ROOM:
+            return "statusbar.room";
         default:
             return NULL;
     }
@@ -1854,7 +1883,6 @@ _get_default_boolean(preference_t pref)
         case PREF_MUC_PRIVILEGES:
         case PREF_PRESENCE:
         case PREF_WRAP:
-        case PREF_WINS_AUTO_TIDY:
         case PREF_INPBLOCK_DYNAMIC:
         case PREF_RESOURCE_TITLE:
         case PREF_RESOURCE_MESSAGE:
@@ -1874,6 +1902,7 @@ _get_default_boolean(preference_t pref)
         case PREF_TRAY_READ:
         case PREF_BOOKMARK_INVITE:
         case PREF_ROOM_LIST_CACHE:
+        case PREF_STATUSBAR_SHOW_NUMBER:
             return TRUE;
         default:
             return FALSE;
@@ -1937,6 +1966,12 @@ _get_default_string(preference_t pref)
         case PREF_CONSOLE_PRIVATE:
         case PREF_CONSOLE_CHAT:
             return "all";
+        case PREF_STATUSBAR_SELF:
+            return "fulljid";
+        case PREF_STATUSBAR_CHAT:
+            return "user";
+        case PREF_STATUSBAR_ROOM:
+            return "room";
         default:
             return NULL;
     }
diff --git a/src/config/preferences.h b/src/config/preferences.h
index 6eb2241d..808ffafd 100644
--- a/src/config/preferences.h
+++ b/src/config/preferences.h
@@ -89,7 +89,6 @@ typedef enum {
     PREF_MUC_PRIVILEGES,
     PREF_PRESENCE,
     PREF_WRAP,
-    PREF_WINS_AUTO_TIDY,
     PREF_TIME_CONSOLE,
     PREF_TIME_CHAT,
     PREF_TIME_MUC,
@@ -144,6 +143,11 @@ typedef enum {
     PREF_BOOKMARK_INVITE,
     PREF_PLUGINS_SOURCEPATH,
     PREF_ROOM_LIST_CACHE,
+    PREF_STATUSBAR_SHOW_NAME,
+    PREF_STATUSBAR_SHOW_NUMBER,
+    PREF_STATUSBAR_SELF,
+    PREF_STATUSBAR_CHAT,
+    PREF_STATUSBAR_ROOM,
 } preference_t;
 
 typedef struct prof_alias_t {
@@ -188,6 +192,9 @@ gint prefs_get_autoping_timeout(void);
 gint prefs_get_inpblock(void);
 void prefs_set_inpblock(gint value);
 
+void prefs_set_statusbartabs(gint value);
+gint prefs_get_statusbartabs(void);
+
 void prefs_set_occupants_size(gint value);
 gint prefs_get_occupants_size(void);
 void prefs_set_roster_size(gint value);
diff --git a/src/config/theme.c b/src/config/theme.c
index 7c5937fb..24dbc9ae 100644
--- a/src/config/theme.c
+++ b/src/config/theme.c
@@ -384,7 +384,6 @@ _load_preferences(void)
     _set_boolean_preference("flash", PREF_FLASH);
     _set_boolean_preference("splash", PREF_SPLASH);
     _set_boolean_preference("wrap", PREF_WRAP);
-    _set_boolean_preference("wins.autotidy", PREF_WINS_AUTO_TIDY);
     _set_boolean_preference("resource.title", PREF_RESOURCE_TITLE);
     _set_boolean_preference("resource.message", PREF_RESOURCE_MESSAGE);
     _set_boolean_preference("occupants", PREF_OCCUPANTS);
@@ -408,6 +407,8 @@ _load_preferences(void)
     _set_boolean_preference("intype", PREF_INTYPE);
     _set_boolean_preference("enc.warn", PREF_ENC_WARN);
     _set_boolean_preference("tls.show", PREF_TLS_SHOW);
+    _set_boolean_preference("statusbar.show.name", PREF_STATUSBAR_SHOW_NAME);
+    _set_boolean_preference("statusbar.show.nuumber", PREF_STATUSBAR_SHOW_NUMBER);
 
     _set_string_preference("time.console", PREF_TIME_CONSOLE);
     _set_string_preference("time.chat", PREF_TIME_CHAT);
@@ -432,6 +433,14 @@ _load_preferences(void)
     _set_string_preference("roster.rooms.by", PREF_ROSTER_ROOMS_BY);
     _set_string_preference("roster.private", PREF_ROSTER_PRIVATE);
     _set_string_preference("roster.count", PREF_ROSTER_COUNT);
+    _set_string_preference("statusbar.self", PREF_STATUSBAR_SELF);
+    _set_string_preference("statusbar.chat", PREF_STATUSBAR_CHAT);
+    _set_string_preference("statusbar.room", PREF_STATUSBAR_ROOM);
+
+    if (g_key_file_has_key(theme, "ui", "statusbar.tabs", NULL)) {
+        gint tabs_size = g_key_file_get_integer(theme, "ui", "statusbar.tabs", NULL);
+        prefs_set_statusbartabs(tabs_size);
+    }
 
     if (g_key_file_has_key(theme, "ui", "occupants.size", NULL)) {
         gint occupants_size = g_key_file_get_integer(theme, "ui", "occupants.size", NULL);
diff --git a/src/event/server_events.c b/src/event/server_events.c
index efd8756d..b735c22f 100644
--- a/src/event/server_events.c
+++ b/src/event/server_events.c
@@ -282,7 +282,7 @@ sv_ev_room_message(const char *const room_jid, const char *const nick, const cha
     // currently in groupchat window
     if (wins_is_current(window)) {
         is_current = TRUE;
-        status_bar_active(num);
+        status_bar_active(num, WIN_MUC, mucwin->roomjid);
 
         if ((g_strcmp0(mynick, nick) != 0) && (prefs_get_boolean(PREF_BEEP))) {
             beep();
@@ -290,7 +290,7 @@ sv_ev_room_message(const char *const room_jid, const char *const nick, const cha
 
     // not currently on groupchat window
     } else {
-        status_bar_new(num);
+        status_bar_new(num, WIN_MUC, mucwin->roomjid);
 
         if ((g_strcmp0(mynick, nick) != 0) && (prefs_get_boolean(PREF_FLASH))) {
             flash();
diff --git a/src/plugins/api.c b/src/plugins/api.c
index 0ca58452..d30914dc 100644
--- a/src/plugins/api.c
+++ b/src/plugins/api.c
@@ -333,7 +333,7 @@ api_win_create(
     // set status bar active
     ProfPluginWin *pluginwin = wins_get_plugin(tag);
     int num = wins_get_num((ProfWin*)pluginwin);
-    status_bar_active(num);
+    status_bar_active(num, WIN_PLUGIN, pluginwin->tag);
 }
 
 int
diff --git a/src/ui/chatwin.c b/src/ui/chatwin.c
index ad62c6c7..31604db4 100644
--- a/src/ui/chatwin.c
+++ b/src/ui/chatwin.c
@@ -105,7 +105,7 @@ chatwin_otr_secured(ProfChatWin *chatwin, gboolean trusted)
          title_bar_switch();
     } else {
         int num = wins_get_num(window);
-        status_bar_new(num);
+        status_bar_new(num, WIN_CHAT, chatwin->barejid);
 
         int ui_index = num;
         if (ui_index == 10) {
@@ -249,11 +249,11 @@ chatwin_incoming_msg(ProfChatWin *chatwin, const char *const resource, const cha
     if (wins_is_current(window)) {
         win_print_incoming(window, timestamp, display_name, plugin_message, enc_mode);
         title_bar_set_typing(FALSE);
-        status_bar_active(num);
+        status_bar_active(num, WIN_CHAT, chatwin->barejid);
 
     // not currently viewing chat window with sender
     } else {
-        status_bar_new(num);
+        status_bar_new(num, WIN_CHAT, chatwin->barejid);
         cons_show_incoming_message(display_name, num, chatwin->unread);
 
         if (prefs_get_boolean(PREF_FLASH)) {
@@ -324,9 +324,11 @@ chatwin_outgoing_carbon(ProfChatWin *chatwin, const char *const message, prof_en
         enc_char = prefs_get_pgp_char();
     }
 
-    win_print_outgoing((ProfWin*)chatwin, enc_char, "%s", message);
-    int num = wins_get_num((ProfWin*)chatwin);
-    status_bar_active(num);
+    ProfWin *window = (ProfWin*)chatwin;
+
+    win_print_outgoing(window, enc_char, "%s", message);
+    int num = wins_get_num(window);
+    status_bar_active(num, WIN_CHAT, chatwin->barejid);
 }
 
 void
diff --git a/src/ui/console.c b/src/ui/console.c
index e646cf85..26c830fc 100644
--- a/src/ui/console.c
+++ b/src/ui/console.c
@@ -1124,15 +1124,6 @@ cons_wrap_setting(void)
 }
 
 void
-cons_winstidy_setting(void)
-{
-    if (prefs_get_boolean(PREF_WINS_AUTO_TIDY))
-        cons_show("Window Auto Tidy (/wins)            : ON");
-    else
-        cons_show("Window Auto Tidy (/wins)            : OFF");
-}
-
-void
 cons_encwarn_setting(void)
 {
     if (prefs_get_boolean(PREF_ENC_WARN)) {
@@ -1531,7 +1522,6 @@ cons_show_ui_prefs(void)
     cons_splash_setting();
     cons_winpos_setting();
     cons_wrap_setting();
-    cons_winstidy_setting();
     cons_time_setting();
     cons_resource_setting();
     cons_vercheck_setting();
@@ -1544,6 +1534,7 @@ cons_show_ui_prefs(void)
     cons_presence_setting();
     cons_inpblock_setting();
     cons_tlsshow_setting();
+    cons_statusbar_setting();
 
     cons_alert();
 }
@@ -1748,6 +1739,39 @@ cons_inpblock_setting(void)
 }
 
 void
+cons_statusbar_setting(void)
+{
+    if (prefs_get_boolean(PREF_STATUSBAR_SHOW_NAME)) {
+        cons_show("Show tab names (/statusbar)         : ON");
+    } else {
+        cons_show("Show tab names (/statusbar)         : OFF");
+    }
+    if (prefs_get_boolean(PREF_STATUSBAR_SHOW_NUMBER)) {
+        cons_show("Show tab numbers (/statusbar)       : ON");
+    } else {
+        cons_show("Show tab numbers (/statusbar)       : OFF");
+    }
+
+    cons_show("Max tabs (/statusbar)               : %d", prefs_get_statusbartabs());
+
+    char *pref_self = prefs_get_string(PREF_STATUSBAR_SELF);
+    if (g_strcmp0(pref_self, "off") == 0) {
+        cons_show("Self statusbar display (/statusbar) : OFF");
+    } else {
+        cons_show("Self statusbar display (/statusbar) : %s", pref_self);
+    }
+    prefs_free_string(pref_self);
+
+    char *pref_chat = prefs_get_string(PREF_STATUSBAR_CHAT);
+    cons_show("Chat tab display (/statusbar)       : %s", pref_chat);
+    prefs_free_string(pref_chat);
+
+    char *pref_room = prefs_get_string(PREF_STATUSBAR_ROOM);
+    cons_show("Room tab display (/statusbar)       : %s", pref_room);
+    prefs_free_string(pref_room);
+}
+
+void
 cons_winpos_setting(void)
 {
     ProfWinPlacement *placement = prefs_get_win_placement();
@@ -2161,7 +2185,7 @@ cons_alert(void)
 {
     ProfWin *current = wins_get_current();
     if (current->type != WIN_CONSOLE) {
-        status_bar_new(1);
+        status_bar_new(1, WIN_CONSOLE, "console");
     }
 }
 
diff --git a/src/ui/core.c b/src/ui/core.c
index 49c8406a..5246d06a 100644
--- a/src/ui/core.c
+++ b/src/ui/core.c
@@ -102,8 +102,8 @@ ui_init(void)
     ui_load_colours();
     refresh();
     create_title_bar();
-    create_status_bar();
-    status_bar_active(1);
+    status_bar_init();
+    status_bar_active(1, WIN_CONSOLE, "console");
     create_input_window();
     wins_init();
     notifier_initialise();
@@ -137,7 +137,7 @@ ui_update(void)
         _ui_draw_term_title();
     }
     title_bar_update_virtual();
-    status_bar_update_virtual();
+    status_bar_draw();
     inp_put_back();
     doupdate();
 
@@ -183,6 +183,7 @@ ui_close(void)
     notifier_uninit();
     wins_destroy();
     inp_close();
+    status_bar_close();
     endwin();
 }
 
@@ -286,7 +287,7 @@ ui_contact_typing(const char *const barejid, const char *const resource)
             title_bar_set_typing(TRUE);
 
             int num = wins_get_num(window);
-            status_bar_active(num);
+            status_bar_active(num, WIN_CHAT, chatwin->barejid);
        }
     }
 
@@ -387,8 +388,7 @@ ui_handle_login_account_success(ProfAccount *account, gboolean secured)
     title_bar_set_connected(TRUE);
     title_bar_set_tls(secured);
 
-    status_bar_print_message(connection_get_fulljid());
-    status_bar_update_virtual();
+    status_bar_set_fulljid(connection_get_fulljid());
 }
 
 void
@@ -481,8 +481,7 @@ ui_disconnected(void)
     title_bar_set_connected(FALSE);
     title_bar_set_tls(FALSE);
     title_bar_set_presence(CONTACT_OFFLINE);
-    status_bar_clear_message();
-    status_bar_update_virtual();
+    status_bar_clear_fulljid();
     ui_hide_roster();
 }
 
@@ -672,7 +671,10 @@ ui_focus_win(ProfWin *window)
         title_bar_switch();
     }
     status_bar_current(i);
-    status_bar_active(i);
+
+    char *identifier = win_get_tab_identifier(window);
+    status_bar_active(i, window->type, identifier);
+    free(identifier);
 }
 
 void
@@ -689,7 +691,7 @@ ui_close_win(int index)
     wins_close_by_num(index);
     title_bar_console();
     status_bar_current(1);
-    status_bar_active(1);
+    status_bar_active(1, WIN_CONSOLE, "console");
 }
 
 void
@@ -737,17 +739,19 @@ ui_print_system_msg_from_recipient(const char *const barejid, const char *messag
     if (barejid == NULL || message == NULL)
         return;
 
-    ProfWin *window = (ProfWin*)wins_get_chat(barejid);
+    ProfChatWin *chatwin = wins_get_chat(barejid);
+    ProfWin *window = (ProfWin*)chatwin;
     if (window == NULL) {
         int num = 0;
         window = wins_new_chat(barejid);
         if (window) {
+            chatwin = (ProfChatWin*)window;
             num = wins_get_num(window);
-            status_bar_active(num);
+            status_bar_active(num, WIN_CHAT, chatwin->barejid);
         } else {
             num = 0;
             window = wins_get_console();
-            status_bar_active(1);
+            status_bar_active(1, WIN_CONSOLE, "console");
         }
     }
 
@@ -757,10 +761,11 @@ ui_print_system_msg_from_recipient(const char *const barejid, const char *messag
 void
 ui_room_join(const char *const roomjid, gboolean focus)
 {
-    ProfWin *window = (ProfWin*)wins_get_muc(roomjid);
-    if (!window) {
-        window = wins_new_muc(roomjid);
+    ProfMucWin *mucwin = wins_get_muc(roomjid);
+    if (mucwin == NULL) {
+        mucwin = (ProfMucWin*)wins_new_muc(roomjid);
     }
+    ProfWin *window = (ProfWin*)mucwin;
 
     char *nick = muc_nick(roomjid);
     win_print(window, THEME_ROOMINFO, '!', "-> You have joined the room as %s", nick);
@@ -780,7 +785,7 @@ ui_room_join(const char *const roomjid, gboolean focus)
         ui_focus_win(window);
     } else {
         int num = wins_get_num(window);
-        status_bar_active(num);
+        status_bar_active(num, WIN_MUC, mucwin->roomjid);
         ProfWin *console = wins_get_console();
         char *nick = muc_nick(roomjid);
         win_println(console, THEME_TYPING, '!', "-> Autojoined %s as %s (%d).", roomjid, nick, num);
@@ -968,15 +973,14 @@ ui_win_unread(int index)
 char*
 ui_ask_password(void)
 {
-    status_bar_get_password();
-    status_bar_update_virtual();
+    status_bar_set_prompt("Enter password:");
     return inp_get_password();
 }
 
 char*
 ui_get_line(void)
 {
-    status_bar_update_virtual();
+    status_bar_draw();
     return inp_get_line();
 }
 
@@ -999,8 +1003,7 @@ ui_ask_pgp_passphrase(const char *hint, int prev_fail)
 
     ui_update();
 
-    status_bar_get_password();
-    status_bar_update_virtual();
+    status_bar_set_prompt("Enter password:");
     return inp_get_password();
 }
 
diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c
index 0173a201..654a4602 100644
--- a/src/ui/inputwin.c
+++ b/src/ui/inputwin.c
@@ -251,7 +251,7 @@ inp_get_line(void)
         line = inp_readline();
         ui_update();
     }
-    status_bar_clear();
+    status_bar_clear_prompt();
     return line;
 }
 
@@ -269,7 +269,7 @@ inp_get_password(void)
         ui_update();
     }
     get_password = FALSE;
-    status_bar_clear();
+    status_bar_clear_prompt();
     return password;
 }
 
diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c
index 15564ed8..f64a401e 100644
--- a/src/ui/mucwin.c
+++ b/src/ui/mucwin.c
@@ -519,11 +519,11 @@ mucwin_requires_config(ProfMucWin *mucwin)
 
     // currently in groupchat window
     if (wins_is_current(window)) {
-        status_bar_active(num);
+        status_bar_active(num, WIN_MUC, mucwin->roomjid);
 
     // not currently on groupchat window
     } else {
-        status_bar_new(num);
+        status_bar_new(num, WIN_MUC, mucwin->roomjid);
     }
 }
 
@@ -533,8 +533,6 @@ mucwin_subject(ProfMucWin *mucwin, const char *const nick, const char *const sub
     assert(mucwin != NULL);
 
     ProfWin *window = (ProfWin*)mucwin;
-    int num = wins_get_num(window);
-
     if (subject) {
         if (nick) {
             win_print(window, THEME_ROOMINFO, '!', "*%s has set the room subject: ", nick);
@@ -550,15 +548,6 @@ mucwin_subject(ProfMucWin *mucwin, const char *const nick, const char *const sub
             win_println(window, THEME_ROOMINFO, '!', "Room subject cleared");
         }
     }
-
-    // currently in groupchat window
-    if (wins_is_current(window)) {
-        status_bar_active(num);
-
-    // not currently on groupchat window
-    } else {
-        status_bar_active(num);
-    }
 }
 
 void
@@ -583,11 +572,11 @@ mucwin_broadcast(ProfMucWin *mucwin, const char *const message)
 
     // currently in groupchat window
     if (wins_is_current(window)) {
-        status_bar_active(num);
+        status_bar_active(num, WIN_MUC, mucwin->roomjid);
 
     // not currently on groupchat window
     } else {
-        status_bar_new(num);
+        status_bar_new(num, WIN_MUC, mucwin->roomjid);
     }
 }
 
diff --git a/src/ui/privwin.c b/src/ui/privwin.c
index 675ca061..8de59683 100644
--- a/src/ui/privwin.c
+++ b/src/ui/privwin.c
@@ -62,11 +62,11 @@ privwin_incoming_msg(ProfPrivateWin *privatewin, const char *const message, GDat
     if (wins_is_current(window)) {
         win_print_incoming(window, timestamp, jidp->resourcepart, message, PROF_MSG_PLAIN);
         title_bar_set_typing(FALSE);
-        status_bar_active(num);
+        status_bar_active(num, WIN_PRIVATE, privatewin->fulljid);
 
     // not currently viewing chat window with sender
     } else {
-        status_bar_new(num);
+        status_bar_new(num, WIN_PRIVATE, privatewin->fulljid);
         cons_show_incoming_private_message(jidp->resourcepart, jidp->barejid, num, privatewin->unread);
         win_print_incoming(window, timestamp, jidp->resourcepart, message, PROF_MSG_PLAIN);
 
diff --git a/src/ui/statusbar.c b/src/ui/statusbar.c
index a88834e3..e84e3b60 100644
--- a/src/ui/statusbar.c
+++ b/src/ui/statusbar.c
@@ -50,151 +50,111 @@
 #include "ui/statusbar.h"
 #include "ui/inputwin.h"
 #include "ui/screen.h"
+#include "xmpp/roster_list.h"
+#include "xmpp/contact.h"
+
+typedef struct _status_bar_tab_t {
+    win_type_t window_type;
+    char *identifier;
+    gboolean highlight;
+} StatusBarTab;
+
+typedef struct _status_bar_t {
+    gchar *time;
+    char *prompt;
+    char *fulljid;
+    GHashTable *tabs;
+    int current_tab;
+} StatusBar;
 
-#define TIME_CHECK 60000000
-
-static WINDOW *status_bar;
-static char *message = NULL;
-//                          1  2  3  4  5  6  7  8  9  0  >
-static char _active[34] = "[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]";
-static char *bracket = "- -";
-static int is_active[12];
-static GHashTable *remaining_active;
-static int is_new[12];
-static GHashTable *remaining_new;
 static GTimeZone *tz;
-static GDateTime *last_time;
-static int current;
-
-static void _update_win_statuses(void);
-static void _mark_new(int num);
-static void _mark_active(int num);
-static void _mark_inactive(int num);
-static void _status_bar_draw(void);
+static StatusBar *statusbar;
+static WINDOW *statusbar_win;
+
+static int _status_bar_draw_time(int pos);
+static void _status_bar_draw_maintext(int pos);
+static int _status_bar_draw_bracket(gboolean current, int pos, char* ch);
+static int _status_bar_draw_extended_tabs(int pos);
+static int _status_bar_draw_tab(StatusBarTab *tab, int pos, int num);
+static void _destroy_tab(StatusBarTab *tab);
+static int _tabs_width(void);
+static char* _display_name(StatusBarTab *tab);
+static gboolean _extended_new(void);
 
 void
-create_status_bar(void)
+status_bar_init(void)
 {
-    int i;
-    int cols = getmaxx(stdscr);
-
-    is_active[1] = TRUE;
-    is_new[1] = FALSE;
-    for (i = 2; i < 12; i++) {
-        is_active[i] = FALSE;
-        is_new[i] = FALSE;
-    }
-    remaining_active = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
-    remaining_new = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
-    current = 1;
+    tz = g_time_zone_new_local();
 
-    int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
+    statusbar = malloc(sizeof(StatusBar));
+    statusbar->time = NULL;
+    statusbar->prompt = NULL;
+    statusbar->fulljid = NULL;
+    statusbar->tabs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)_destroy_tab);
+    StatusBarTab *console = malloc(sizeof(StatusBarTab));
+    console->window_type = WIN_CONSOLE;
+    console->identifier = strdup("console");
+    g_hash_table_insert(statusbar->tabs, GINT_TO_POINTER(1), console);
+    statusbar->current_tab = 1;
 
     int row = screen_statusbar_row();
-    status_bar = newwin(1, cols, row, 0);
-    wbkgd(status_bar, theme_attrs(THEME_STATUS_TEXT));
-    wattron(status_bar, bracket_attrs);
-    mvwprintw(status_bar, 0, cols - 34, _active);
-    mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket);
-    wattroff(status_bar, bracket_attrs);
-
-    tz = g_time_zone_new_local();
-
-    if (last_time) {
-        g_date_time_unref(last_time);
-    }
-    last_time = g_date_time_new_now(tz);
+    int cols = getmaxx(stdscr);
+    statusbar_win = newwin(1, cols, row, 0);
 
-    _status_bar_draw();
+    status_bar_draw();
 }
 
 void
-status_bar_update_virtual(void)
+status_bar_close(void)
 {
-    _status_bar_draw();
+    if (tz) {
+        g_time_zone_unref(tz);
+    }
+    if (statusbar) {
+        if (statusbar->time) {
+            g_free(statusbar->time);
+        }
+        if (statusbar->prompt) {
+            free(statusbar->prompt);
+        }
+        if (statusbar->fulljid) {
+            free(statusbar->fulljid);
+        }
+        if (statusbar->tabs) {
+            g_hash_table_destroy(statusbar->tabs);
+        }
+        free(statusbar);
+    }
 }
 
 void
 status_bar_resize(void)
 {
     int cols = getmaxx(stdscr);
-
-    werase(status_bar);
-
-    int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
-
+    werase(statusbar_win);
     int row = screen_statusbar_row();
-    mvwin(status_bar, row, 0);
-    wresize(status_bar, 1, cols);
-    wbkgd(status_bar, theme_attrs(THEME_STATUS_TEXT));
-    wattron(status_bar, bracket_attrs);
-    mvwprintw(status_bar, 0, cols - 34, _active);
-    mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket);
-    wattroff(status_bar, bracket_attrs);
-
-    if (message) {
-        char *time_pref = prefs_get_string(PREF_TIME_STATUSBAR);
-
-        gchar *date_fmt = NULL;
-        if (g_strcmp0(time_pref, "off") == 0) {
-            date_fmt = g_strdup("");
-        } else {
-            date_fmt = g_date_time_format(last_time, time_pref);
-        }
-        assert(date_fmt != NULL);
-        size_t len = strlen(date_fmt);
-        g_free(date_fmt);
-        if (g_strcmp0(time_pref, "off") != 0) {
-            /* 01234567890123456
-             *  [HH:MM]  message */
-            mvwprintw(status_bar, 0, 5 + len, message);
-        } else {
-            mvwprintw(status_bar, 0, 1, message);
-        }
-        prefs_free_string(time_pref);
-    }
-    if (last_time) {
-        g_date_time_unref(last_time);
-    }
-    last_time = g_date_time_new_now_local();
+    mvwin(statusbar_win, row, 0);
+    wresize(statusbar_win, 1, cols);
 
-    _status_bar_draw();
+    status_bar_draw();
 }
 
 void
 status_bar_set_all_inactive(void)
 {
-    int i = 0;
-    for (i = 0; i < 12; i++) {
-        is_active[i] = FALSE;
-        is_new[i] = FALSE;
-        _mark_inactive(i);
-    }
-
-    g_hash_table_remove_all(remaining_active);
-    g_hash_table_remove_all(remaining_new);
-
-    _status_bar_draw();
+    g_hash_table_remove_all(statusbar->tabs);
 }
 
 void
 status_bar_current(int i)
 {
     if (i == 0) {
-        current = 10;
-    } else if (i > 10) {
-        current = 11;
+        statusbar->current_tab = 10;
     } else {
-        current = i;
+        statusbar->current_tab = i;
     }
-    int cols = getmaxx(stdscr);
-    int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
-    wattron(status_bar, bracket_attrs);
-    mvwprintw(status_bar, 0, cols - 34, _active);
-    mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket);
-    wattroff(status_bar, bracket_attrs);
 
-    _status_bar_draw();
+    status_bar_draw();
 }
 
 void
@@ -205,281 +165,417 @@ status_bar_inactive(const int win)
         true_win = 10;
     }
 
-    // extra windows
-    if (true_win > 10) {
-        g_hash_table_remove(remaining_active, GINT_TO_POINTER(true_win));
-        g_hash_table_remove(remaining_new, GINT_TO_POINTER(true_win));
-
-        // still have new windows
-        if (g_hash_table_size(remaining_new) != 0) {
-            is_active[11] = TRUE;
-            is_new[11] = TRUE;
-            _mark_new(11);
+    g_hash_table_remove(statusbar->tabs, GINT_TO_POINTER(true_win));
 
-        // still have active windows
-        } else if (g_hash_table_size(remaining_active) != 0) {
-            is_active[11] = TRUE;
-            is_new[11] = FALSE;
-            _mark_active(11);
-
-        // no active or new windows
-        } else {
-            is_active[11] = FALSE;
-            is_new[11] = FALSE;
-            _mark_inactive(11);
-        }
+    status_bar_draw();
+}
 
-    // visible window indicators
-    } else {
-        is_active[true_win] = FALSE;
-        is_new[true_win] = FALSE;
-        _mark_inactive(true_win);
+void
+status_bar_active(const int win, win_type_t wintype, char *identifier)
+{
+    int true_win = win;
+    if (true_win == 0) {
+        true_win = 10;
     }
 
-    _status_bar_draw();
+    StatusBarTab *tab = malloc(sizeof(StatusBarTab));
+    tab->identifier = strdup(identifier);
+    tab->highlight = FALSE;
+    tab->window_type = wintype;
+    g_hash_table_replace(statusbar->tabs, GINT_TO_POINTER(true_win), tab);
+
+    status_bar_draw();
 }
 
 void
-status_bar_active(const int win)
+status_bar_new(const int win, win_type_t wintype, char* identifier)
 {
     int true_win = win;
     if (true_win == 0) {
         true_win = 10;
     }
 
-    // extra windows
-    if (true_win > 10) {
-        g_hash_table_add(remaining_active, GINT_TO_POINTER(true_win));
-        g_hash_table_remove(remaining_new, GINT_TO_POINTER(true_win));
-
-        // still have new windows
-        if (g_hash_table_size(remaining_new) != 0) {
-            is_active[11] = TRUE;
-            is_new[11] = TRUE;
-            _mark_new(11);
+    StatusBarTab *tab = malloc(sizeof(StatusBarTab));
+    tab->identifier = strdup(identifier);
+    tab->highlight = TRUE;
+    tab->window_type = wintype;
+    g_hash_table_replace(statusbar->tabs, GINT_TO_POINTER(true_win), tab);
 
-        // only active windows
-        } else {
-            is_active[11] = TRUE;
-            is_new[11] = FALSE;
-            _mark_active(11);
-        }
+    status_bar_draw();
+}
 
-    // visible window indicators
-    } else {
-        is_active[true_win] = TRUE;
-        is_new[true_win] = FALSE;
-        _mark_active(true_win);
+void
+status_bar_set_prompt(const char *const prompt)
+{
+    if (statusbar->prompt) {
+        free(statusbar->prompt);
+        statusbar->prompt = NULL;
     }
+    statusbar->prompt = strdup(prompt);
 
-    _status_bar_draw();
+    status_bar_draw();
 }
 
 void
-status_bar_new(const int win)
+status_bar_clear_prompt(void)
 {
-    int true_win = win;
-    if (true_win == 0) {
-        true_win = 10;
+    if (statusbar->prompt) {
+        free(statusbar->prompt);
+        statusbar->prompt = NULL;
     }
 
-    if (true_win > 10) {
-        g_hash_table_add(remaining_active, GINT_TO_POINTER(true_win));
-        g_hash_table_add(remaining_new, GINT_TO_POINTER(true_win));
-
-        is_active[11] = TRUE;
-        is_new[11] = TRUE;
-        _mark_new(11);
+    status_bar_draw();
+}
 
-    } else {
-        is_active[true_win] = TRUE;
-        is_new[true_win] = TRUE;
-        _mark_new(true_win);
+void
+status_bar_set_fulljid(const char *const fulljid)
+{
+    if (statusbar->fulljid) {
+        free(statusbar->fulljid);
+        statusbar->fulljid = NULL;
     }
+    statusbar->fulljid = strdup(fulljid);
 
-    _status_bar_draw();
+    status_bar_draw();
 }
 
 void
-status_bar_get_password(void)
+status_bar_clear_fulljid(void)
 {
-    status_bar_print_message("Enter password:");
+    if (statusbar->fulljid) {
+        free(statusbar->fulljid);
+        statusbar->fulljid = NULL;
+    }
 
-    _status_bar_draw();
+    status_bar_draw();
 }
 
 void
-status_bar_print_message(const char *const msg)
+status_bar_draw(void)
 {
-    werase(status_bar);
+    werase(statusbar_win);
+    wbkgd(statusbar_win, theme_attrs(THEME_STATUS_TEXT));
+
+    int pos = 1;
+
+    pos = _status_bar_draw_time(pos);
 
-    if (message) {
-        free(message);
+    _status_bar_draw_maintext(pos);
+
+    pos = getmaxx(stdscr) - _tabs_width();
+    if (pos < 0) {
+        pos = 0;
+    }
+    gint max_tabs = prefs_get_statusbartabs();
+    int i = 1;
+    for (i = 1; i <= max_tabs; i++) {
+        StatusBarTab *tab = g_hash_table_lookup(statusbar->tabs, GINT_TO_POINTER(i));
+        if (tab) {
+            pos = _status_bar_draw_tab(tab, pos, i);
+        }
     }
-    message = strdup(msg);
 
-    char *time_pref = prefs_get_string(PREF_TIME_STATUSBAR);
-    gchar *date_fmt = NULL;
-    if (g_strcmp0(time_pref, "off") == 0) {
-        date_fmt = g_strdup("");
-    } else {
-        date_fmt = g_date_time_format(last_time, time_pref);
+    pos = _status_bar_draw_extended_tabs(pos);
+
+    wnoutrefresh(statusbar_win);
+    inp_put_back();
+}
+
+static gboolean
+_extended_new(void)
+{
+    gint max_tabs = prefs_get_statusbartabs();
+    int tabs_count = g_hash_table_size(statusbar->tabs);
+    if (tabs_count <= max_tabs) {
+        return FALSE;
     }
 
-    assert(date_fmt != NULL);
-    size_t len = strlen(date_fmt);
-    g_free(date_fmt);
-    if (g_strcmp0(time_pref, "off") != 0) {
-        mvwprintw(status_bar, 0, 5 + len, message);
-    } else {
-        mvwprintw(status_bar, 0, 1, message);
+    int i = 0;
+    for (i = max_tabs + 1; i <= tabs_count; i++) {
+        StatusBarTab *tab = g_hash_table_lookup(statusbar->tabs, GINT_TO_POINTER(i));
+        if (tab && tab->highlight) {
+            return TRUE;
+        }
     }
-    prefs_free_string(time_pref);
 
-    int cols = getmaxx(stdscr);
-    int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
+    return FALSE;
+}
+
+static int
+_status_bar_draw_extended_tabs(int pos)
+{
+    gint max_tabs = prefs_get_statusbartabs();
+    if (max_tabs == 0) {
+        return pos;
+    }
+
+    if (g_hash_table_size(statusbar->tabs) > max_tabs) {
+        gboolean is_current = statusbar->current_tab > max_tabs;
+
+        pos = _status_bar_draw_bracket(is_current, pos, "[");
+
+        int status_attrs = theme_attrs(THEME_STATUS_ACTIVE);
+        if (_extended_new()) {
+            status_attrs = theme_attrs(THEME_STATUS_NEW);
+        }
+        wattron(statusbar_win, status_attrs);
+        mvwprintw(statusbar_win, 0, pos, ">");
+        wattroff(statusbar_win, status_attrs);
+        pos++;
 
-    wattron(status_bar, bracket_attrs);
-    mvwprintw(status_bar, 0, cols - 34, _active);
-    mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket);
-    wattroff(status_bar, bracket_attrs);
+        pos = _status_bar_draw_bracket(is_current, pos, "]");
+    }
 
-    _status_bar_draw();
+    return pos;
 }
 
-void
-status_bar_clear(void)
+static int
+_status_bar_draw_tab(StatusBarTab *tab, int pos, int num)
 {
-    if (message) {
-        free(message);
-        message = NULL;
+    int display_num = num == 10 ? 0 : num;
+    gboolean is_current = num == statusbar->current_tab;
+
+    gboolean show_number = prefs_get_boolean(PREF_STATUSBAR_SHOW_NUMBER);
+    gboolean show_name = prefs_get_boolean(PREF_STATUSBAR_SHOW_NAME);
+
+    pos = _status_bar_draw_bracket(is_current, pos, "[");
+
+    int status_attrs = 0;
+    if (tab->highlight) {
+        status_attrs = theme_attrs(THEME_STATUS_NEW);
+    } else {
+        status_attrs = theme_attrs(THEME_STATUS_ACTIVE);
+    }
+    wattron(statusbar_win, status_attrs);
+    if (show_number) {
+        mvwprintw(statusbar_win, 0, pos, "%d", display_num);
+        pos++;
+    }
+    if (show_number && show_name) {
+        mvwprintw(statusbar_win, 0, pos, ":");
+        pos++;
+    }
+    if (show_name) {
+        char *display_name = _display_name(tab);
+        mvwprintw(statusbar_win, 0, pos, display_name);
+        pos += strlen(display_name);
+        free(display_name);
     }
+    wattroff(statusbar_win, status_attrs);
 
-    werase(status_bar);
+    pos = _status_bar_draw_bracket(is_current, pos, "]");
 
-    int cols = getmaxx(stdscr);
-    int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
+    return pos;
+}
 
-    wattron(status_bar, bracket_attrs);
-    mvwprintw(status_bar, 0, cols - 34, _active);
-    mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket);
-    wattroff(status_bar, bracket_attrs);
+static int
+_status_bar_draw_bracket(gboolean current, int pos, char* ch)
+{
+    int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
+    wattron(statusbar_win, bracket_attrs);
+    if (current) {
+        mvwprintw(statusbar_win, 0, pos, "-");
+    } else {
+        mvwprintw(statusbar_win, 0, pos, ch);
+    }
+    wattroff(statusbar_win, bracket_attrs);
+    pos++;
 
-    _status_bar_draw();
+    return pos;
 }
 
-void
-status_bar_clear_message(void)
+static int
+_status_bar_draw_time(int pos)
 {
-    if (message) {
-        free(message);
-        message = NULL;
+    char *time_pref = prefs_get_string(PREF_TIME_STATUSBAR);
+    if (g_strcmp0(time_pref, "off") == 0) {
+        prefs_free_string(time_pref);
+        return pos;
     }
 
-    werase(status_bar);
+    if (statusbar->time) {
+        g_free(statusbar->time);
+        statusbar->time = NULL;
+    }
+
+    GDateTime *datetime = g_date_time_new_now(tz);
+    statusbar->time  = g_date_time_format(datetime, time_pref);
+    assert(statusbar->time != NULL);
+    g_date_time_unref(datetime);
 
-    int cols = getmaxx(stdscr);
     int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
+    int time_attrs = theme_attrs(THEME_STATUS_TIME);
 
-    wattron(status_bar, bracket_attrs);
-    mvwprintw(status_bar, 0, cols - 34, _active);
-    mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket);
-    wattroff(status_bar, bracket_attrs);
+    size_t len = strlen(statusbar->time);
+    wattron(statusbar_win, bracket_attrs);
+    mvwaddch(statusbar_win, 0, pos, '[');
+    pos++;
+    wattroff(statusbar_win, bracket_attrs);
+    wattron(statusbar_win, time_attrs);
+    mvwprintw(statusbar_win, 0, pos, statusbar->time);
+    pos += len;
+    wattroff(statusbar_win, time_attrs);
+    wattron(statusbar_win, bracket_attrs);
+    mvwaddch(statusbar_win, 0, pos, ']');
+    wattroff(statusbar_win, bracket_attrs);
+    pos += 2;
 
-    _status_bar_draw();
+    prefs_free_string(time_pref);
+
+    return pos;
 }
 
 static void
-_update_win_statuses(void)
+_status_bar_draw_maintext(int pos)
 {
-    int i;
-    for(i = 1; i < 12; i++) {
-        if (is_new[i]) {
-            _mark_new(i);
+    if (statusbar->prompt) {
+        mvwprintw(statusbar_win, 0, pos, statusbar->prompt);
+        return;
+    }
+
+    if (statusbar->fulljid) {
+        char *pref = prefs_get_string(PREF_STATUSBAR_SELF);
+        if (g_strcmp0(pref, "off") == 0) {
+            return;
         }
-        else if (is_active[i]) {
-            _mark_active(i);
+        if (g_strcmp0(pref, "user") == 0) {
+            Jid *jidp = jid_create(statusbar->fulljid);
+            mvwprintw(statusbar_win, 0, pos, jidp->localpart);
+            jid_destroy(jidp);
+            return;
         }
-        else {
-            _mark_inactive(i);
+        if (g_strcmp0(pref, "barejid") == 0) {
+            Jid *jidp = jid_create(statusbar->fulljid);
+            mvwprintw(statusbar_win, 0, pos, jidp->barejid);
+            jid_destroy(jidp);
+            return;
         }
+        mvwprintw(statusbar_win, 0, pos, statusbar->fulljid);
     }
 }
 
 static void
-_mark_new(int num)
+_destroy_tab(StatusBarTab *tab)
 {
-    int active_pos = 1 + ((num-1) * 3);
-    int cols = getmaxx(stdscr);
-    int status_attrs = theme_attrs(THEME_STATUS_NEW);
-    wattron(status_bar, status_attrs);
-    wattron(status_bar, A_BLINK);
-    if (num == 10) {
-        mvwprintw(status_bar, 0, cols - 34 + active_pos, "0");
-    } else if (num > 10) {
-        mvwprintw(status_bar, 0, cols - 34 + active_pos, ">");
-    } else {
-        mvwprintw(status_bar, 0, cols - 34 + active_pos, "%d", num);
+    if (tab) {
+        if (tab->identifier) {
+            free(tab->identifier);
+        }
+        free(tab);
     }
-    wattroff(status_bar, status_attrs);
-    wattroff(status_bar, A_BLINK);
 }
 
-static void
-_mark_active(int num)
+static int
+_tabs_width(void)
 {
-    int active_pos = 1 + ((num-1) * 3);
-    int cols = getmaxx(stdscr);
-    int status_attrs = theme_attrs(THEME_STATUS_ACTIVE);
-    wattron(status_bar, status_attrs);
-    if (num == 10) {
-        mvwprintw(status_bar, 0, cols - 34 + active_pos, "0");
-    } else if (num > 10) {
-        mvwprintw(status_bar, 0, cols - 34 + active_pos, ">");
-    } else {
-        mvwprintw(status_bar, 0, cols - 34 + active_pos, "%d", num);
+    gboolean show_number = prefs_get_boolean(PREF_STATUSBAR_SHOW_NUMBER);
+    gboolean show_name = prefs_get_boolean(PREF_STATUSBAR_SHOW_NAME);
+    gint max_tabs = prefs_get_statusbartabs();
+
+    if (show_name && show_number) {
+        int width = g_hash_table_size(statusbar->tabs) > max_tabs ? 4 : 1;
+        int i = 0;
+        for (i = 1; i <= max_tabs; i++) {
+            StatusBarTab *tab = g_hash_table_lookup(statusbar->tabs, GINT_TO_POINTER(i));
+            if (tab) {
+                char *display_name = _display_name(tab);
+                width += strlen(display_name);
+                width += 4;
+                free(display_name);
+            }
+        }
+        return width;
     }
-    wattroff(status_bar, status_attrs);
-}
 
-static void
-_mark_inactive(int num)
-{
-    int active_pos = 1 + ((num-1) * 3);
-    int cols = getmaxx(stdscr);
-    mvwaddch(status_bar, 0, cols - 34 + active_pos, ' ');
+    if (show_name && !show_number) {
+        int width = g_hash_table_size(statusbar->tabs) > max_tabs ? 4 : 1;
+        int i = 0;
+        for (i = 1; i <= max_tabs; i++) {
+            StatusBarTab *tab = g_hash_table_lookup(statusbar->tabs, GINT_TO_POINTER(i));
+            if (tab) {
+                char *display_name = _display_name(tab);
+                width += strlen(display_name);
+                width += 2;
+                free(display_name);
+            }
+        }
+        return width;
+    }
+
+    if (g_hash_table_size(statusbar->tabs) > max_tabs) {
+        return max_tabs * 3 + (g_hash_table_size(statusbar->tabs) > max_tabs ? 4 : 1);
+    }
+    return g_hash_table_size(statusbar->tabs) * 3 + (g_hash_table_size(statusbar->tabs) > max_tabs ? 4 : 1);
 }
 
-static void
-_status_bar_draw(void)
+static char*
+_display_name(StatusBarTab *tab)
 {
-    if (last_time) {
-        g_date_time_unref(last_time);
+    if (tab->window_type == WIN_CONSOLE) {
+        return strdup("console");
     }
-    last_time = g_date_time_new_now(tz);
-
-    int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
-    int time_attrs = theme_attrs(THEME_STATUS_TIME);
-
-    char *time_pref = prefs_get_string(PREF_TIME_STATUSBAR);
-    if (g_strcmp0(time_pref, "off") != 0) {
-        gchar *date_fmt = g_date_time_format(last_time, time_pref);
-        assert(date_fmt != NULL);
-        size_t len = strlen(date_fmt);
-        wattron(status_bar, bracket_attrs);
-        mvwaddch(status_bar, 0, 1, '[');
-        wattroff(status_bar, bracket_attrs);
-        wattron(status_bar, time_attrs);
-        mvwprintw(status_bar, 0, 2, date_fmt);
-        wattroff(status_bar, time_attrs);
-        wattron(status_bar, bracket_attrs);
-        mvwaddch(status_bar, 0, 2 + len, ']');
-        wattroff(status_bar, bracket_attrs);
-        g_free(date_fmt);
+    if (tab->window_type == WIN_XML) {
+        return strdup("xmlconsole");
     }
-    prefs_free_string(time_pref);
-
-    _update_win_statuses();
-    wnoutrefresh(status_bar);
-    inp_put_back();
+    if (tab->window_type == WIN_PLUGIN) {
+        return strdup(tab->identifier);
+    }
+    if (tab->window_type == WIN_CHAT) {
+        PContact contact = roster_get_contact(tab->identifier);
+        if (contact && p_contact_name(contact)) {
+            return strdup(p_contact_name(contact));
+        }
+        char *pref = prefs_get_string(PREF_STATUSBAR_CHAT);
+        if (g_strcmp0("user", pref) == 0) {
+            Jid *jidp = jid_create(tab->identifier);
+            char *user = strdup(jidp->localpart);
+            jid_destroy(jidp);
+            return user;
+        } else {
+            return strdup(tab->identifier);
+        }
+    }
+    if (tab->window_type == WIN_MUC) {
+        char *pref = prefs_get_string(PREF_STATUSBAR_ROOM);
+        if (g_strcmp0("room", pref) == 0) {
+            Jid *jidp = jid_create(tab->identifier);
+            char *room = strdup(jidp->localpart);
+            jid_destroy(jidp);
+            return room;
+        } else {
+            return strdup(tab->identifier);
+        }
+    }
+    if (tab->window_type == WIN_MUC_CONFIG) {
+        char *pref = prefs_get_string(PREF_STATUSBAR_ROOM);
+        GString *display_str = g_string_new("");
+        if (g_strcmp0("room", pref) == 0) {
+            Jid *jidp = jid_create(tab->identifier);
+            g_string_append(display_str, jidp->localpart);
+            jid_destroy(jidp);
+        } else {
+            g_string_append(display_str, tab->identifier);
+        }
+        g_string_append(display_str, " conf");
+        char *result = strdup(display_str->str);
+        g_string_free(display_str, TRUE);
+        return result;
+    }
+    if (tab->window_type == WIN_PRIVATE) {
+        char *pref = prefs_get_string(PREF_STATUSBAR_ROOM);
+        if (g_strcmp0("room", pref) == 0) {
+            GString *display_str = g_string_new("");
+            Jid *jidp = jid_create(tab->identifier);
+            g_string_append(display_str, jidp->localpart);
+            g_string_append(display_str, "/");
+            g_string_append(display_str, jidp->resourcepart);
+            jid_destroy(jidp);
+            char *result = strdup(display_str->str);
+            g_string_free(display_str, TRUE);
+            return result;
+        } else {
+            return strdup(tab->identifier);
+        }
+    }
+    return strdup("window");
 }
diff --git a/src/ui/statusbar.h b/src/ui/statusbar.h
index def9c04b..de8b51cc 100644
--- a/src/ui/statusbar.h
+++ b/src/ui/statusbar.h
@@ -35,13 +35,14 @@
 #ifndef UI_STATUSBAR_H
 #define UI_STATUSBAR_H
 
-void create_status_bar(void);
-void status_bar_update_virtual(void);
+void status_bar_init(void);
+void status_bar_draw(void);
+void status_bar_close(void);
 void status_bar_resize(void);
-void status_bar_clear(void);
-void status_bar_clear_message(void);
-void status_bar_get_password(void);
-void status_bar_print_message(const char *const msg);
+void status_bar_set_prompt(const char *const prompt);
+void status_bar_clear_prompt(void);
+void status_bar_set_fulljid(const char *const fulljid);
+void status_bar_clear_fulljid(void);
 void status_bar_current(int i);
 
 #endif
diff --git a/src/ui/ui.h b/src/ui/ui.h
index 9168f58a..d344f855 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -297,7 +297,6 @@ void cons_occupants_setting(void);
 void cons_roster_setting(void);
 void cons_presence_setting(void);
 void cons_wrap_setting(void);
-void cons_winstidy_setting(void);
 void cons_time_setting(void);
 void cons_wintitle_setting(void);
 void cons_notify_setting(void);
@@ -318,6 +317,7 @@ void cons_autoping_setting(void);
 void cons_autoconnect_setting(void);
 void cons_room_cache_setting(void);
 void cons_inpblock_setting(void);
+void cons_statusbar_setting(void);
 void cons_winpos_setting(void);
 void cons_show_contact_online(PContact contact, Resource *resource, GDateTime *last_activity);
 void cons_show_contact_offline(PContact contact, char *resource, char *status);
@@ -331,8 +331,8 @@ void title_bar_set_presence(contact_presence_t presence);
 
 // status bar
 void status_bar_inactive(const int win);
-void status_bar_active(const int win);
-void status_bar_new(const int win);
+void status_bar_active(const int win, win_type_t wintype, char *identifier);
+void status_bar_new(const int win, win_type_t wintype, char *identifier);
 void status_bar_set_all_inactive(void);
 
 // roster window
@@ -375,6 +375,7 @@ void win_show_occupant_info(ProfWin *window, const char *const room, Occupant *o
 void win_show_contact(ProfWin *window, PContact contact);
 void win_show_info(ProfWin *window, PContact contact);
 void win_clear(ProfWin *window);
+char* win_get_tab_identifier(ProfWin *window);
 char* win_to_string(ProfWin *window);
 
 // desktop notifications
diff --git a/src/ui/win_types.h b/src/ui/win_types.h
index 3eb48b29..7fa75b34 100644
--- a/src/ui/win_types.h
+++ b/src/ui/win_types.h
@@ -194,7 +194,7 @@ typedef struct prof_xml_win_t {
 } ProfXMLWin;
 
 typedef struct prof_plugin_win_t {
-    ProfWin super;
+    ProfWin window;
     char *tag;
     char *plugin_name;
     unsigned long memcheck;
diff --git a/src/ui/window.c b/src/ui/window.c
index 2ca5621c..5543707d 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -162,7 +162,7 @@ win_create_muc(const char *const roomjid)
     int cols = getmaxx(stdscr);
 
     new_win->window.type = WIN_MUC;
-
+    new_win->window.layout = _win_create_simple_layout();
     ProfLayoutSplit *layout = malloc(sizeof(ProfLayoutSplit));
     layout->base.type = LAYOUT_SPLIT;
 
@@ -208,7 +208,6 @@ win_create_muc_config(const char *const roomjid, DataForm *form)
     ProfMucConfWin *new_win = malloc(sizeof(ProfMucConfWin));
     new_win->window.type = WIN_MUC_CONFIG;
     new_win->window.layout = _win_create_simple_layout();
-
     new_win->roomjid = strdup(roomjid);
     new_win->form = form;
 
@@ -223,7 +222,6 @@ win_create_private(const char *const fulljid)
     ProfPrivateWin *new_win = malloc(sizeof(ProfPrivateWin));
     new_win->window.type = WIN_PRIVATE;
     new_win->window.layout = _win_create_simple_layout();
-
     new_win->fulljid = strdup(fulljid);
     new_win->unread = 0;
     new_win->occupant_offline = FALSE;
@@ -250,15 +248,15 @@ ProfWin*
 win_create_plugin(const char *const plugin_name, const char *const tag)
 {
     ProfPluginWin *new_win = malloc(sizeof(ProfPluginWin));
-    new_win->super.type = WIN_PLUGIN;
-    new_win->super.layout = _win_create_simple_layout();
+    new_win->window.type = WIN_PLUGIN;
+    new_win->window.layout = _win_create_simple_layout();
 
     new_win->tag = strdup(tag);
     new_win->plugin_name = strdup(plugin_name);
 
     new_win->memcheck = PROFPLUGINWIN_MEMCHECK;
 
-    return &new_win->super;
+    return &new_win->window;
 }
 
 char*
@@ -321,6 +319,50 @@ win_get_title(ProfWin *window)
 }
 
 char*
+win_get_tab_identifier(ProfWin *window)
+{
+    assert(window != NULL);
+
+    switch (window->type) {
+        case WIN_CONSOLE:
+        {
+            return strdup("console");
+        }
+        case WIN_CHAT:
+        {
+            ProfChatWin *chatwin = (ProfChatWin*)window;
+            return strdup(chatwin->barejid);
+        }
+        case WIN_MUC:
+        {
+            ProfMucWin *mucwin = (ProfMucWin*)window;
+            return strdup(mucwin->roomjid);
+        }
+        case WIN_MUC_CONFIG:
+        {
+            ProfMucConfWin *mucconfwin = (ProfMucConfWin*)window;
+            return strdup(mucconfwin->roomjid);
+        }
+        case WIN_PRIVATE:
+        {
+            ProfPrivateWin *privwin = (ProfPrivateWin*)window;
+            return strdup(privwin->fulljid);
+        }
+        case WIN_PLUGIN:
+        {
+            ProfPluginWin *pluginwin = (ProfPluginWin*)window;
+            return strdup(pluginwin->tag);
+        }
+        case WIN_XML:
+        {
+            return strdup("xmlconsole");
+        }
+        default:
+            return strdup("UNKNOWN");
+    }
+}
+
+char*
 win_to_string(ProfWin *window)
 {
     assert(window != NULL);
diff --git a/src/ui/window_list.c b/src/ui/window_list.c
index 8c3c4739..798f4e41 100644
--- a/src/ui/window_list.c
+++ b/src/ui/window_list.c
@@ -45,7 +45,6 @@
 #include "config/theme.h"
 #include "plugins/plugins.h"
 #include "ui/ui.h"
-#include "ui/statusbar.h"
 #include "ui/window_list.h"
 #include "xmpp/xmpp.h"
 #include "xmpp/roster_list.h"
@@ -239,9 +238,7 @@ wins_close_plugin(char *tag)
     int index = wins_get_num(toclose);
     ui_close_win(index);
 
-    if (prefs_get_boolean(PREF_WINS_AUTO_TIDY)) {
-        wins_tidy();
-    }
+    wins_tidy();
 }
 
 GList*
@@ -847,7 +844,7 @@ wins_lost_connection(void)
     g_list_free(values);
 }
 
-gboolean
+void
 wins_swap(int source_win, int target_win)
 {
     ProfWin *source = g_hash_table_lookup(windows, GINT_TO_POINTER(source_win));
@@ -857,20 +854,21 @@ wins_swap(int source_win, int target_win)
         ProfWin *target = g_hash_table_lookup(windows, GINT_TO_POINTER(target_win));
 
         // target window empty
-        if (!target) {
+        if (target == NULL) {
             g_hash_table_steal(windows, GINT_TO_POINTER(source_win));
             g_hash_table_insert(windows, GINT_TO_POINTER(target_win), source);
             status_bar_inactive(source_win);
+            char *identifier = win_get_tab_identifier(source);
             if (win_unread(source) > 0) {
-                status_bar_new(target_win);
+                status_bar_new(target_win, source->type, identifier);
             } else {
-                status_bar_active(target_win);
+                status_bar_active(target_win, source->type, identifier);
             }
+            free(identifier);
             if (wins_get_current_num() == source_win) {
                 wins_set_current_by_num(target_win);
                 ui_focus_win(console);
             }
-            return TRUE;
 
         // target window occupied
         } else {
@@ -878,23 +876,24 @@ wins_swap(int source_win, int target_win)
             g_hash_table_steal(windows, GINT_TO_POINTER(target_win));
             g_hash_table_insert(windows, GINT_TO_POINTER(source_win), target);
             g_hash_table_insert(windows, GINT_TO_POINTER(target_win), source);
+            char *source_identifier = win_get_tab_identifier(source);
+            char *target_identifier = win_get_tab_identifier(target);
             if (win_unread(source) > 0) {
-                status_bar_new(target_win);
+                status_bar_new(target_win, source->type, source_identifier);
             } else {
-                status_bar_active(target_win);
+                status_bar_active(target_win, source->type, source_identifier);
             }
             if (win_unread(target) > 0) {
-                status_bar_new(source_win);
+                status_bar_new(source_win, target->type, target_identifier);
             } else {
-                status_bar_active(source_win);
+                status_bar_active(source_win, target->type, target_identifier);
             }
+            free(source_identifier);
+            free(target_identifier);
             if ((wins_get_current_num() == source_win) || (wins_get_current_num() == target_win)) {
                 ui_focus_win(console);
             }
-            return TRUE;
         }
-    } else {
-        return FALSE;
     }
 }
 
@@ -999,22 +998,24 @@ wins_tidy(void)
         GList *curr = keys;
         while (curr) {
             ProfWin *window = g_hash_table_lookup(windows, curr->data);
+            char *identifier = win_get_tab_identifier(window);
             g_hash_table_steal(windows, curr->data);
             if (num == 10) {
                 g_hash_table_insert(new_windows, GINT_TO_POINTER(0), window);
                 if (win_unread(window) > 0) {
-                    status_bar_new(0);
+                    status_bar_new(0, window->type, identifier);
                 } else {
-                    status_bar_active(0);
+                    status_bar_active(0, window->type, identifier);
                 }
             } else {
                 g_hash_table_insert(new_windows, GINT_TO_POINTER(num), window);
                 if (win_unread(window) > 0) {
-                    status_bar_new(num);
+                    status_bar_new(num, window->type, identifier);
                 } else {
-                    status_bar_active(num);
+                    status_bar_active(num, window->type, identifier);
                 }
             }
+            free(identifier);
             num++;
             curr = g_list_next(curr);
         }
diff --git a/src/ui/window_list.h b/src/ui/window_list.h
index f1a2ee24..68e72739 100644
--- a/src/ui/window_list.h
+++ b/src/ui/window_list.h
@@ -87,7 +87,7 @@ gboolean wins_tidy(void);
 GSList* wins_create_summary(gboolean unread);
 void wins_destroy(void);
 GList* wins_get_nums(void);
-gboolean wins_swap(int source_win, int target_win);
+void wins_swap(int source_win, int target_win);
 void wins_hide_subwin(ProfWin *window);
 void wins_show_subwin(ProfWin *window);
 
diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c
index 51e8d84a..420653e1 100644
--- a/tests/unittests/ui/stub_ui.c
+++ b/tests/unittests/ui/stub_ui.c
@@ -448,6 +448,7 @@ void cons_autoconnect_setting(void) {}
 void cons_rooms_cache_setting(void) {}
 void cons_inpblock_setting(void) {}
 void cons_winpos_setting(void) {}
+void cons_statusbar_setting(void) {}
 void cons_tray_setting(void) {}
 
 void cons_show_contact_online(PContact contact, Resource *resource, GDateTime *last_activity)
@@ -466,8 +467,8 @@ void title_bar_set_presence(contact_presence_t presence) {}
 
 // status bar
 void status_bar_inactive(const int win) {}
-void status_bar_active(const int win) {}
-void status_bar_new(const int win) {}
+void status_bar_active(const int win, win_type_t type, char *identifier) {}
+void status_bar_new(const int win, win_type_t type, char *identifier) {}
 void status_bar_set_all_inactive(void) {}
 
 // roster window
@@ -506,6 +507,11 @@ ProfWin* win_create_plugin(const char *const plugin_name, const char * const tag
     return NULL;
 }
 
+char* win_get_tab_identifier(ProfWin *window)
+{
+    return NULL;
+}
+
 void win_update_virtual(ProfWin *window) {}
 void win_free(ProfWin *window) {}
 gboolean win_notify_remind(ProfWin *window)
diff --git a/themes/boothj5 b/themes/boothj5
index b97a4499..2f9a94e0 100644
--- a/themes/boothj5
+++ b/themes/boothj5
@@ -142,4 +142,10 @@ titlebar.position=1
 mainwin.position=2
 statusbar.position=3
 inputwin.position=4
+statusbar.self=user
+statusbar.chat=user
+statusbar.room=room
+statusbar.tabs=8
+statusbar.show.name=true
+statusbar.show.number=true