about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/command/cmd_ac.c179
-rw-r--r--src/command/cmd_defs.c3
-rw-r--r--src/command/cmd_funcs.c45
-rw-r--r--src/config/preferences.c5
-rw-r--r--src/config/preferences.h1
-rw-r--r--src/omemo/omemo.c2
-rw-r--r--src/otr/otr.c4
-rw-r--r--src/profanity.c6
-rw-r--r--src/tools/autocomplete.c17
-rw-r--r--src/ui/chatwin.c4
-rw-r--r--src/ui/confwin.c48
-rw-r--r--src/ui/console.c14
-rw-r--r--src/ui/notifier.c2
-rw-r--r--src/ui/statusbar.c132
-rw-r--r--src/xmpp/connection.c2
-rw-r--r--src/xmpp/iq.c2
-rw-r--r--src/xmpp/ox.c2
-rw-r--r--themes/batman4
18 files changed, 283 insertions, 189 deletions
diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c
index 13c8f09d..3561449e 100644
--- a/src/command/cmd_ac.c
+++ b/src/command/cmd_ac.c
@@ -265,6 +265,7 @@ static Autocomplete statusbar_self_ac;
 static Autocomplete statusbar_chat_ac;
 static Autocomplete statusbar_room_ac;
 static Autocomplete statusbar_show_ac;
+static Autocomplete statusbar_tabmode_ac;
 static Autocomplete clear_ac;
 static Autocomplete invite_ac;
 static Autocomplete status_ac;
@@ -294,6 +295,8 @@ static Autocomplete vcard_togglable_param_ac;
 static Autocomplete vcard_toggle_ac;
 static Autocomplete vcard_address_type_ac;
 
+static GHashTable* ac_funcs = NULL;
+
 /*!
  * \brief Initialization of auto completion for commands.
  *
@@ -1030,6 +1033,7 @@ cmd_ac_init(void)
     autocomplete_add(statusbar_ac, "hide");
     autocomplete_add(statusbar_ac, "maxtabs");
     autocomplete_add(statusbar_ac, "tablen");
+    autocomplete_add(statusbar_ac, "tabmode");
     autocomplete_add(statusbar_ac, "self");
     autocomplete_add(statusbar_ac, "chat");
     autocomplete_add(statusbar_ac, "room");
@@ -1058,6 +1062,10 @@ cmd_ac_init(void)
     autocomplete_add(statusbar_show_ac, "number");
     autocomplete_add(statusbar_show_ac, "read");
 
+    statusbar_tabmode_ac = autocomplete_new();
+    autocomplete_add(statusbar_tabmode_ac, "actlist");
+    autocomplete_add(statusbar_tabmode_ac, "default");
+
     status_ac = autocomplete_new();
     autocomplete_add(status_ac, "set");
     autocomplete_add(status_ac, "get");
@@ -1299,6 +1307,78 @@ cmd_ac_init(void)
     vcard_address_type_ac = autocomplete_new();
     autocomplete_add(vcard_address_type_ac, "domestic");
     autocomplete_add(vcard_address_type_ac, "international");
+
+    if (ac_funcs != NULL)
+        g_hash_table_destroy(ac_funcs);
+    ac_funcs = g_hash_table_new(g_str_hash, g_str_equal);
+    g_hash_table_insert(ac_funcs, "/account", _account_autocomplete);
+    g_hash_table_insert(ac_funcs, "/affiliation", _affiliation_autocomplete);
+    g_hash_table_insert(ac_funcs, "/alias", _alias_autocomplete);
+    g_hash_table_insert(ac_funcs, "/autoaway", _autoaway_autocomplete);
+    g_hash_table_insert(ac_funcs, "/autoconnect", _autoconnect_autocomplete);
+    g_hash_table_insert(ac_funcs, "/avatar", _avatar_autocomplete);
+    g_hash_table_insert(ac_funcs, "/ban", _ban_autocomplete);
+    g_hash_table_insert(ac_funcs, "/blocked", _blocked_autocomplete);
+    g_hash_table_insert(ac_funcs, "/bookmark", _bookmark_autocomplete);
+    g_hash_table_insert(ac_funcs, "/clear", _clear_autocomplete);
+    g_hash_table_insert(ac_funcs, "/close", _close_autocomplete);
+    g_hash_table_insert(ac_funcs, "/cmd", _adhoc_cmd_autocomplete);
+    g_hash_table_insert(ac_funcs, "/color", _color_autocomplete);
+    g_hash_table_insert(ac_funcs, "/connect", _connect_autocomplete);
+    g_hash_table_insert(ac_funcs, "/console", _console_autocomplete);
+    g_hash_table_insert(ac_funcs, "/correct", _correct_autocomplete);
+    g_hash_table_insert(ac_funcs, "/correction", _correction_autocomplete);
+    g_hash_table_insert(ac_funcs, "/executable", _executable_autocomplete);
+    g_hash_table_insert(ac_funcs, "/form", _form_autocomplete);
+    g_hash_table_insert(ac_funcs, "/help", _help_autocomplete);
+    g_hash_table_insert(ac_funcs, "/inpblock", _inpblock_autocomplete);
+    g_hash_table_insert(ac_funcs, "/intype", _intype_autocomplete);
+    g_hash_table_insert(ac_funcs, "/invite", _invite_autocomplete);
+    g_hash_table_insert(ac_funcs, "/join", _join_autocomplete);
+    g_hash_table_insert(ac_funcs, "/kick", _kick_autocomplete);
+    g_hash_table_insert(ac_funcs, "/lastactivity", _lastactivity_autocomplete);
+    g_hash_table_insert(ac_funcs, "/log", _log_autocomplete);
+    g_hash_table_insert(ac_funcs, "/logging", _logging_autocomplete);
+    g_hash_table_insert(ac_funcs, "/mood", _mood_autocomplete);
+    g_hash_table_insert(ac_funcs, "/notify", _notify_autocomplete);
+    g_hash_table_insert(ac_funcs, "/occupants", _occupants_autocomplete);
+#ifdef HAVE_OMEMO
+    g_hash_table_insert(ac_funcs, "/omemo", _omemo_autocomplete);
+#endif
+#ifdef HAVE_LIBOTR
+    g_hash_table_insert(ac_funcs, "/otr", _otr_autocomplete);
+#endif
+#ifdef HAVE_LIBGPGME
+    g_hash_table_insert(ac_funcs, "/ox", _ox_autocomplete);
+    g_hash_table_insert(ac_funcs, "/pgp", _pgp_autocomplete);
+#endif
+    g_hash_table_insert(ac_funcs, "/plugins", _plugins_autocomplete);
+    g_hash_table_insert(ac_funcs, "/presence", _presence_autocomplete);
+    g_hash_table_insert(ac_funcs, "/receipts", _receipts_autocomplete);
+    g_hash_table_insert(ac_funcs, "/reconnect", _reconnect_autocomplete);
+    g_hash_table_insert(ac_funcs, "/resource", _resource_autocomplete);
+    g_hash_table_insert(ac_funcs, "/role", _role_autocomplete);
+    g_hash_table_insert(ac_funcs, "/rooms", _rooms_autocomplete);
+    g_hash_table_insert(ac_funcs, "/roster", _roster_autocomplete);
+    g_hash_table_insert(ac_funcs, "/script", _script_autocomplete);
+    g_hash_table_insert(ac_funcs, "/sendfile", _sendfile_autocomplete);
+    g_hash_table_insert(ac_funcs, "/software", _software_autocomplete);
+    g_hash_table_insert(ac_funcs, "/status", _status_autocomplete);
+    g_hash_table_insert(ac_funcs, "/statusbar", _statusbar_autocomplete);
+    g_hash_table_insert(ac_funcs, "/strophe", _strophe_autocomplete);
+    g_hash_table_insert(ac_funcs, "/sub", _sub_autocomplete);
+    g_hash_table_insert(ac_funcs, "/subject", _subject_autocomplete);
+    g_hash_table_insert(ac_funcs, "/theme", _theme_autocomplete);
+    g_hash_table_insert(ac_funcs, "/time", _time_autocomplete);
+    g_hash_table_insert(ac_funcs, "/titlebar", _titlebar_autocomplete);
+    g_hash_table_insert(ac_funcs, "/tls", _tls_autocomplete);
+    g_hash_table_insert(ac_funcs, "/tray", _tray_autocomplete);
+    g_hash_table_insert(ac_funcs, "/url", _url_autocomplete);
+    g_hash_table_insert(ac_funcs, "/vcard", _vcard_autocomplete);
+    g_hash_table_insert(ac_funcs, "/who", _who_autocomplete);
+    g_hash_table_insert(ac_funcs, "/win", _win_autocomplete);
+    g_hash_table_insert(ac_funcs, "/wins", _wins_autocomplete);
+    g_hash_table_insert(ac_funcs, "/wintitle", _wintitle_autocomplete);
 }
 
 void
@@ -1606,6 +1686,7 @@ cmd_ac_reset(ProfWin* window)
     autocomplete_reset(statusbar_chat_ac);
     autocomplete_reset(statusbar_room_ac);
     autocomplete_reset(statusbar_show_ac);
+    autocomplete_reset(statusbar_tabmode_ac);
     autocomplete_reset(clear_ac);
     autocomplete_reset(invite_ac);
     autocomplete_reset(status_ac);
@@ -1792,6 +1873,7 @@ cmd_ac_uninit(void)
     autocomplete_free(statusbar_chat_ac);
     autocomplete_free(statusbar_room_ac);
     autocomplete_free(statusbar_show_ac);
+    autocomplete_free(statusbar_tabmode_ac);
     autocomplete_free(clear_ac);
     autocomplete_free(invite_ac);
     autocomplete_free(status_ac);
@@ -2011,86 +2093,26 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
         }
     }
 
-    gchar* cmds[] = { "/prefs", "/disco", "/room", "/autoping", "/mainwin", "/inputwin" };
-    Autocomplete completers[] = { prefs_ac, disco_ac, room_ac, autoping_ac, winpos_ac, winpos_ac };
-
-    for (int i = 0; i < ARRAY_SIZE(cmds); i++) {
-        result = autocomplete_param_with_ac(input, cmds[i], completers[i], TRUE, previous);
+    struct
+    {
+        gchar* cmd;
+        Autocomplete completer;
+    } ac_cmds[] = {
+        { "/prefs", prefs_ac },
+        { "/disco", disco_ac },
+        { "/room", room_ac },
+        { "/autoping", autoping_ac },
+        { "/mainwin", winpos_ac },
+        { "/inputwin", winpos_ac },
+    };
+
+    for (int i = 0; i < ARRAY_SIZE(ac_cmds); i++) {
+        result = autocomplete_param_with_ac(input, ac_cmds[i].cmd, ac_cmds[i].completer, TRUE, previous);
         if (result) {
             return result;
         }
     }
 
-    GHashTable* ac_funcs = g_hash_table_new(g_str_hash, g_str_equal);
-    g_hash_table_insert(ac_funcs, "/help", _help_autocomplete);
-    g_hash_table_insert(ac_funcs, "/who", _who_autocomplete);
-    g_hash_table_insert(ac_funcs, "/sub", _sub_autocomplete);
-    g_hash_table_insert(ac_funcs, "/notify", _notify_autocomplete);
-    g_hash_table_insert(ac_funcs, "/autoaway", _autoaway_autocomplete);
-    g_hash_table_insert(ac_funcs, "/theme", _theme_autocomplete);
-    g_hash_table_insert(ac_funcs, "/log", _log_autocomplete);
-    g_hash_table_insert(ac_funcs, "/account", _account_autocomplete);
-    g_hash_table_insert(ac_funcs, "/roster", _roster_autocomplete);
-    g_hash_table_insert(ac_funcs, "/bookmark", _bookmark_autocomplete);
-    g_hash_table_insert(ac_funcs, "/autoconnect", _autoconnect_autocomplete);
-#ifdef HAVE_LIBOTR
-    g_hash_table_insert(ac_funcs, "/otr", _otr_autocomplete);
-#endif
-#ifdef HAVE_LIBGPGME
-    g_hash_table_insert(ac_funcs, "/pgp", _pgp_autocomplete);
-    g_hash_table_insert(ac_funcs, "/ox", _ox_autocomplete);
-#endif
-#ifdef HAVE_OMEMO
-    g_hash_table_insert(ac_funcs, "/omemo", _omemo_autocomplete);
-#endif
-    g_hash_table_insert(ac_funcs, "/connect", _connect_autocomplete);
-    g_hash_table_insert(ac_funcs, "/alias", _alias_autocomplete);
-    g_hash_table_insert(ac_funcs, "/join", _join_autocomplete);
-    g_hash_table_insert(ac_funcs, "/form", _form_autocomplete);
-    g_hash_table_insert(ac_funcs, "/occupants", _occupants_autocomplete);
-    g_hash_table_insert(ac_funcs, "/kick", _kick_autocomplete);
-    g_hash_table_insert(ac_funcs, "/ban", _ban_autocomplete);
-    g_hash_table_insert(ac_funcs, "/affiliation", _affiliation_autocomplete);
-    g_hash_table_insert(ac_funcs, "/role", _role_autocomplete);
-    g_hash_table_insert(ac_funcs, "/resource", _resource_autocomplete);
-    g_hash_table_insert(ac_funcs, "/wintitle", _wintitle_autocomplete);
-    g_hash_table_insert(ac_funcs, "/inpblock", _inpblock_autocomplete);
-    g_hash_table_insert(ac_funcs, "/time", _time_autocomplete);
-    g_hash_table_insert(ac_funcs, "/receipts", _receipts_autocomplete);
-    g_hash_table_insert(ac_funcs, "/reconnect", _reconnect_autocomplete);
-    g_hash_table_insert(ac_funcs, "/wins", _wins_autocomplete);
-    g_hash_table_insert(ac_funcs, "/tls", _tls_autocomplete);
-    g_hash_table_insert(ac_funcs, "/titlebar", _titlebar_autocomplete);
-    g_hash_table_insert(ac_funcs, "/script", _script_autocomplete);
-    g_hash_table_insert(ac_funcs, "/subject", _subject_autocomplete);
-    g_hash_table_insert(ac_funcs, "/console", _console_autocomplete);
-    g_hash_table_insert(ac_funcs, "/win", _win_autocomplete);
-    g_hash_table_insert(ac_funcs, "/close", _close_autocomplete);
-    g_hash_table_insert(ac_funcs, "/plugins", _plugins_autocomplete);
-    g_hash_table_insert(ac_funcs, "/sendfile", _sendfile_autocomplete);
-    g_hash_table_insert(ac_funcs, "/blocked", _blocked_autocomplete);
-    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);
-    g_hash_table_insert(ac_funcs, "/clear", _clear_autocomplete);
-    g_hash_table_insert(ac_funcs, "/invite", _invite_autocomplete);
-    g_hash_table_insert(ac_funcs, "/status", _status_autocomplete);
-    g_hash_table_insert(ac_funcs, "/logging", _logging_autocomplete);
-    g_hash_table_insert(ac_funcs, "/color", _color_autocomplete);
-    g_hash_table_insert(ac_funcs, "/avatar", _avatar_autocomplete);
-    g_hash_table_insert(ac_funcs, "/correction", _correction_autocomplete);
-    g_hash_table_insert(ac_funcs, "/correct", _correct_autocomplete);
-    g_hash_table_insert(ac_funcs, "/software", _software_autocomplete);
-    g_hash_table_insert(ac_funcs, "/url", _url_autocomplete);
-    g_hash_table_insert(ac_funcs, "/executable", _executable_autocomplete);
-    g_hash_table_insert(ac_funcs, "/lastactivity", _lastactivity_autocomplete);
-    g_hash_table_insert(ac_funcs, "/intype", _intype_autocomplete);
-    g_hash_table_insert(ac_funcs, "/mood", _mood_autocomplete);
-    g_hash_table_insert(ac_funcs, "/strophe", _strophe_autocomplete);
-    g_hash_table_insert(ac_funcs, "/cmd", _adhoc_cmd_autocomplete);
-    g_hash_table_insert(ac_funcs, "/vcard", _vcard_autocomplete);
-
     int len = strlen(input);
     char parsed[len + 1];
     int i = 0;
@@ -2108,11 +2130,9 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
     if (ac_func) {
         result = ac_func(window, input, previous);
         if (result) {
-            g_hash_table_destroy(ac_funcs);
             return result;
         }
     }
-    g_hash_table_destroy(ac_funcs);
 
     result = plugins_autocomplete(input, previous);
     if (result) {
@@ -4100,6 +4120,11 @@ _statusbar_autocomplete(ProfWin* window, const char* const input, gboolean previ
         return found;
     }
 
+    found = autocomplete_param_with_ac(input, "/statusbar tabmode", statusbar_tabmode_ac, TRUE, previous);
+    if (found) {
+        return found;
+    }
+
     found = autocomplete_param_with_ac(input, "/statusbar room", statusbar_room_ac, TRUE, previous);
 
     return found;
diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c
index 60c1c971..6f30652b 100644
--- a/src/command/cmd_defs.c
+++ b/src/command/cmd_defs.c
@@ -1293,6 +1293,7 @@ static const struct cmd_t command_defs[] = {
               "/statusbar hide name|number|read",
               "/statusbar maxtabs <value>",
               "/statusbar tablen <value>",
+              "/statusbar tabmode default|actlist",
               "/statusbar self user|barejid|fulljid|off",
               "/statusbar chat user|jid",
               "/statusbar room room|jid",
@@ -1303,6 +1304,7 @@ static const struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "maxtabs <value>", "Set the maximum number of tabs to display, <value> must be between 0 and 10." },
               { "tablen <value>", "Set the maximum number of characters to show as the tab name, 0 sets to unlimited." },
+              { "tabmode default|actlist", "Set the mode how the 'active tabs' are shown." },
               { "show|hide name", "Show or hide names in tabs." },
               { "show|hide number", "Show or hide numbers in tabs." },
               { "show|hide read", "Show or hide inactive tabs." },
@@ -1315,6 +1317,7 @@ static const struct cmd_t command_defs[] = {
       CMD_EXAMPLES(
               "/statusbar maxtabs 8",
               "/statusbar tablen 5",
+              "/statusbar tabmode actlist",
               "/statusbar self user",
               "/statusbar chat jid",
               "/statusbar hide read",
diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c
index b9ad139c..f6736156 100644
--- a/src/command/cmd_funcs.c
+++ b/src/command/cmd_funcs.c
@@ -1314,7 +1314,7 @@ cmd_disconnect(ProfWin* window, const char* const command, gchar** args)
 gboolean
 cmd_quit(ProfWin* window, const char* const command, gchar** args)
 {
-    log_info("Profanity is shutting down...");
+    log_info("Profanity is shutting down…");
     exit(0);
     return FALSE;
 }
@@ -3767,11 +3767,11 @@ cmd_form_field(ProfWin* window, char* tag, gchar** args)
             value = args[0];
             if (g_strcmp0(value, "on") == 0) {
                 form_set_value(form, tag, "1");
-                win_println(window, THEME_DEFAULT, "-", "Field updated...");
+                win_println(window, THEME_DEFAULT, "-", "Field updated…");
                 confwin_show_form_field(confwin, form, tag);
             } else if (g_strcmp0(value, "off") == 0) {
                 form_set_value(form, tag, "0");
-                win_println(window, THEME_DEFAULT, "-", "Field updated...");
+                win_println(window, THEME_DEFAULT, "-", "Field updated…");
                 confwin_show_form_field(confwin, form, tag);
             } else {
                 win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
@@ -3790,7 +3790,7 @@ cmd_form_field(ProfWin* window, char* tag, gchar** args)
                 win_println(window, THEME_DEFAULT, "-", "");
             } else {
                 form_set_value(form, tag, value);
-                win_println(window, THEME_DEFAULT, "-", "Field updated...");
+                win_println(window, THEME_DEFAULT, "-", "Field updated…");
                 confwin_show_form_field(confwin, form, tag);
             }
             break;
@@ -3802,7 +3802,7 @@ cmd_form_field(ProfWin* window, char* tag, gchar** args)
                 win_println(window, THEME_DEFAULT, "-", "");
             } else {
                 form_set_value(form, tag, value);
-                win_println(window, THEME_DEFAULT, "-", "Field updated...");
+                win_println(window, THEME_DEFAULT, "-", "Field updated…");
                 confwin_show_form_field(confwin, form, tag);
             }
             break;
@@ -3826,7 +3826,7 @@ cmd_form_field(ProfWin* window, char* tag, gchar** args)
             }
             if (g_strcmp0(cmd, "add") == 0) {
                 form_add_value(form, tag, value);
-                win_println(window, THEME_DEFAULT, "-", "Field updated...");
+                win_println(window, THEME_DEFAULT, "-", "Field updated…");
                 confwin_show_form_field(confwin, form, tag);
                 break;
             }
@@ -3854,7 +3854,7 @@ cmd_form_field(ProfWin* window, char* tag, gchar** args)
 
                 removed = form_remove_text_multi_value(form, tag, index);
                 if (removed) {
-                    win_println(window, THEME_DEFAULT, "-", "Field updated...");
+                    win_println(window, THEME_DEFAULT, "-", "Field updated…");
                     confwin_show_form_field(confwin, form, tag);
                 } else {
                     win_println(window, THEME_DEFAULT, "-", "Could not remove %s from %s", value, tag);
@@ -3883,7 +3883,7 @@ cmd_form_field(ProfWin* window, char* tag, gchar** args)
                 if (valid) {
                     added = form_add_unique_value(form, tag, value);
                     if (added) {
-                        win_println(window, THEME_DEFAULT, "-", "Field updated...");
+                        win_println(window, THEME_DEFAULT, "-", "Field updated…");
                         confwin_show_form_field(confwin, form, tag);
                     } else {
                         win_println(window, THEME_DEFAULT, "-", "Value %s already selected for %s", value, tag);
@@ -3900,7 +3900,7 @@ cmd_form_field(ProfWin* window, char* tag, gchar** args)
                 if (valid == TRUE) {
                     removed = form_remove_value(form, tag, value);
                     if (removed) {
-                        win_println(window, THEME_DEFAULT, "-", "Field updated...");
+                        win_println(window, THEME_DEFAULT, "-", "Field updated…");
                         confwin_show_form_field(confwin, form, tag);
                     } else {
                         win_println(window, THEME_DEFAULT, "-", "Value %s is not currently set for %s", value, tag);
@@ -3932,7 +3932,7 @@ cmd_form_field(ProfWin* window, char* tag, gchar** args)
             if (g_strcmp0(args[0], "add") == 0) {
                 added = form_add_unique_value(form, tag, value);
                 if (added) {
-                    win_println(window, THEME_DEFAULT, "-", "Field updated...");
+                    win_println(window, THEME_DEFAULT, "-", "Field updated…");
                     confwin_show_form_field(confwin, form, tag);
                 } else {
                     win_println(window, THEME_DEFAULT, "-", "JID %s already exists in %s", value, tag);
@@ -3942,7 +3942,7 @@ cmd_form_field(ProfWin* window, char* tag, gchar** args)
             if (g_strcmp0(args[0], "remove") == 0) {
                 removed = form_remove_value(form, tag, value);
                 if (removed) {
-                    win_println(window, THEME_DEFAULT, "-", "Field updated...");
+                    win_println(window, THEME_DEFAULT, "-", "Field updated…");
                     confwin_show_form_field(confwin, form, tag);
                 } else {
                     win_println(window, THEME_DEFAULT, "-", "Field %s does not contain %s", tag, value);
@@ -6343,6 +6343,21 @@ cmd_statusbar(ProfWin* window, const char* const command, gchar** args)
         }
     }
 
+    if (g_strcmp0(args[0], "tabmode") == 0) {
+        char* tabmode = NULL;
+        if ((g_strcmp0(args[1], "default") == 0) || (g_strcmp0(args[1], "actlist") == 0)) {
+            tabmode = args[1];
+        }
+        if (tabmode == NULL) {
+            cons_bad_cmd_usage(command);
+            return TRUE;
+        }
+        prefs_set_string(PREF_STATUSBAR_TABMODE, tabmode);
+        cons_show("Using \"%s\" tabmode for statusbar.", tabmode);
+        ui_resize();
+        return TRUE;
+    }
+
     if (g_strcmp0(args[0], "self") == 0) {
         if (g_strcmp0(args[1], "barejid") == 0) {
             prefs_set_string(PREF_STATUSBAR_SELF, "barejid");
@@ -6626,9 +6641,9 @@ cmd_ping(ProfWin* window, const char* const command, gchar** args)
     iq_send_ping(args[0]);
 
     if (args[0] == NULL) {
-        cons_show("Pinged server...");
+        cons_show("Pinged server…");
     } else {
-        cons_show("Pinged %s...", args[0]);
+        cons_show("Pinged %s…", args[0]);
     }
     return TRUE;
 }
@@ -8396,7 +8411,7 @@ cmd_command_exec(ProfWin* window, const char* const command, gchar** args)
 
     iq_command_exec(jid, args[1]);
 
-    cons_show("Execute %s...", args[1]);
+    cons_show("Execute %s…", args[1]);
     return TRUE;
 }
 
@@ -8612,7 +8627,7 @@ cmd_omemo_gen(ProfWin* window, const char* const command, gchar** args)
         return TRUE;
     }
 
-    cons_show("Generating OMEMO crytographic materials, it may take a while...");
+    cons_show("Generating OMEMO crytographic materials, it may take a while…");
     ui_update();
     ProfAccount* account = accounts_get_account(session_get_account_name());
     omemo_generate_crypto_materials(account);
diff --git a/src/config/preferences.c b/src/config/preferences.c
index f15952cd..2d975e39 100644
--- a/src/config/preferences.c
+++ b/src/config/preferences.c
@@ -1813,6 +1813,7 @@ _get_group(preference_t pref)
     case PREF_STATUSBAR_SELF:
     case PREF_STATUSBAR_CHAT:
     case PREF_STATUSBAR_ROOM:
+    case PREF_STATUSBAR_TABMODE:
     case PREF_TITLEBAR_MUC_TITLE_JID:
     case PREF_TITLEBAR_MUC_TITLE_NAME:
     case PREF_SLASH_GUARD:
@@ -2136,6 +2137,8 @@ _get_key(preference_t pref)
         return "statusbar.chat";
     case PREF_STATUSBAR_ROOM:
         return "statusbar.room";
+    case PREF_STATUSBAR_TABMODE:
+        return "statusbar.tabmode";
     case PREF_OMEMO_LOG:
         return "log";
     case PREF_OMEMO_POLICY:
@@ -2300,6 +2303,8 @@ _get_default_string(preference_t pref)
         return "user";
     case PREF_STATUSBAR_ROOM:
         return "room";
+    case PREF_STATUSBAR_TABMODE:
+        return "default";
     case PREF_OMEMO_LOG:
         return "on";
     case PREF_OMEMO_POLICY:
diff --git a/src/config/preferences.h b/src/config/preferences.h
index ca8acea4..ecb28485 100644
--- a/src/config/preferences.h
+++ b/src/config/preferences.h
@@ -186,6 +186,7 @@ typedef enum {
     PREF_STROPHE_SM_ENABLED,
     PREF_STROPHE_SM_RESEND,
     PREF_VCARD_PHOTO_CMD,
+    PREF_STATUSBAR_TABMODE,
 } preference_t;
 
 typedef struct prof_alias_t
diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c
index 9104a8cb..69a9fc30 100644
--- a/src/omemo/omemo.c
+++ b/src/omemo/omemo.c
@@ -704,7 +704,7 @@ omemo_start_device_session(const char* const jid, uint32_t device_id,
     }
 
     if (!contains_session(&jid_address, omemo_ctx.session_store)) {
-        log_debug("[OMEMO] There is no Session for %s ( %d) ,... building session.", jid_address.name, jid_address.device_id);
+        log_debug("[OMEMO] There is no Session for %s ( %d) ,… building session.", jid_address.name, jid_address.device_id);
         int res;
 
         address = malloc(sizeof(signal_protocol_address));
diff --git a/src/otr/otr.c b/src/otr/otr.c
index bbad51d5..857baa13 100644
--- a/src/otr/otr.c
+++ b/src/otr/otr.c
@@ -304,7 +304,7 @@ otr_on_message_recv(const char* const barejid, const char* const resource, const
                 }
                 memmove(whitespace_base, whitespace_base + tag_length, tag_length);
                 char* otr_query_message = otr_start_query();
-                cons_show("OTR Whitespace pattern detected. Attempting to start OTR session...");
+                cons_show("OTR Whitespace pattern detected. Attempting to start OTR session…");
                 char* id = message_send_chat_otr(barejid, otr_query_message, FALSE, NULL);
                 free(id);
             }
@@ -318,7 +318,7 @@ otr_on_message_recv(const char* const barejid, const char* const resource, const
 
     if (policy == PROF_OTRPOLICY_ALWAYS && *decrypted == FALSE && !whitespace_base) {
         char* otr_query_message = otr_start_query();
-        cons_show("Attempting to start OTR session...");
+        cons_show("Attempting to start OTR session…");
         char* id = message_send_chat_otr(barejid, otr_query_message, FALSE, NULL);
         free(id);
     }
diff --git a/src/profanity.c b/src/profanity.c
index 869ab561..2c6ad12d 100644
--- a/src/profanity.c
+++ b/src/profanity.c
@@ -183,12 +183,12 @@ _init(char* log_level, char* config_file, char* log_file, char* theme_name)
 
     if (strcmp(PACKAGE_STATUS, "development") == 0) {
 #ifdef HAVE_GIT_VERSION
-        log_info("Starting Profanity (%sdev.%s.%s)...", PACKAGE_VERSION, PROF_GIT_BRANCH, PROF_GIT_REVISION);
+        log_info("Starting Profanity (%sdev.%s.%s)…", PACKAGE_VERSION, PROF_GIT_BRANCH, PROF_GIT_REVISION);
 #else
-        log_info("Starting Profanity (%sdev)...", PACKAGE_VERSION);
+        log_info("Starting Profanity (%sdev)…", PACKAGE_VERSION);
 #endif
     } else {
-        log_info("Starting Profanity (%s)...", PACKAGE_VERSION);
+        log_info("Starting Profanity (%s)…", PACKAGE_VERSION);
     }
 
     chat_log_init();
diff --git a/src/tools/autocomplete.c b/src/tools/autocomplete.c
index 227b79e0..27532081 100644
--- a/src/tools/autocomplete.c
+++ b/src/tools/autocomplete.c
@@ -314,11 +314,8 @@ autocomplete_complete(Autocomplete ac, const gchar* search_str, gboolean quote,
 static char*
 _autocomplete_param_common(const char* const input, char* command, autocomplete_func func, Autocomplete ac, gboolean quote, gboolean previous, void* context)
 {
-    char* command_cpy;
-    char* result = NULL;
     int len;
-
-    command_cpy = g_strdup_printf("%s ", command);
+    auto_char char* command_cpy = g_strdup_printf("%s ", command);
     if (!command_cpy) {
         return NULL;
     }
@@ -327,8 +324,11 @@ _autocomplete_param_common(const char* const input, char* command, autocomplete_
 
     if (strncmp(input, command_cpy, len) == 0) {
         int inp_len = strlen(input);
-        char prefix[inp_len];
-        char* found;
+        auto_char char* found = NULL;
+        auto_char char* prefix = malloc(inp_len + 1);
+        if (!prefix) {
+            return NULL;
+        }
 
         for (int i = len; i < inp_len; i++) {
             prefix[i - len] = input[i];
@@ -343,12 +343,11 @@ _autocomplete_param_common(const char* const input, char* command, autocomplete_
         }
 
         if (found) {
-            result = g_strdup_printf("%s%s", command_cpy, found);
+            return g_strdup_printf("%s%s", command_cpy, found);
         }
     }
-    free(command_cpy);
 
-    return result;
+    return NULL;
 }
 
 char*
diff --git a/src/ui/chatwin.c b/src/ui/chatwin.c
index ff425c0f..0c540998 100644
--- a/src/ui/chatwin.c
+++ b/src/ui/chatwin.c
@@ -246,10 +246,10 @@ chatwin_otr_smp_event(ProfChatWin* chatwin, prof_otr_smp_event_t event, void* da
         win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "%s failed to authenticate you.", chatwin->barejid);
         break;
     case PROF_OTR_SMP_AUTH:
-        win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "Authenticating %s...", chatwin->barejid);
+        win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "Authenticating %s…", chatwin->barejid);
         break;
     case PROF_OTR_SMP_AUTH_WAIT:
-        win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "Awaiting authentication from %s...", chatwin->barejid);
+        win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "Awaiting authentication from %s…", chatwin->barejid);
         break;
     default:
         break;
diff --git a/src/ui/confwin.c b/src/ui/confwin.c
index d74c6d86..85abe748 100644
--- a/src/ui/confwin.c
+++ b/src/ui/confwin.c
@@ -215,8 +215,8 @@ _confwin_form_field(ProfWin* window, char* tag, FormField* field)
         win_append(window, THEME_DEFAULT, ": ");
     }
 
-    GSList* values = field->values;
-    GSList* curr_value = values;
+    GSList* curr_value = field->values;
+    GSList* curr_option;
 
     switch (field->type_t) {
     case FIELD_HIDDEN:
@@ -272,36 +272,30 @@ _confwin_form_field(ProfWin* window, char* tag, FormField* field)
         }
         break;
     case FIELD_LIST_SINGLE:
-        if (curr_value) {
-            win_newline(window);
-            char* value = curr_value->data;
-            GSList* options = field->options;
-            GSList* curr_option = options;
-            while (curr_option) {
-                FormOption* option = curr_option->data;
-                if (g_strcmp0(option->value, value) == 0) {
-                    win_println(window, THEME_ONLINE, "-", "  [%s] %s", option->value, option->label);
-                } else {
-                    win_println(window, THEME_OFFLINE, "-", "  [%s] %s", option->value, option->label);
-                }
-                curr_option = g_slist_next(curr_option);
+        win_newline(window);
+        char* value = curr_value ? curr_value->data : NULL;
+        curr_option = field->options;
+        while (curr_option) {
+            FormOption* option = curr_option->data;
+            if (g_strcmp0(option->value, value) == 0) {
+                win_println(window, THEME_ONLINE, "-", "  [%s] %s", option->value, option->label);
+            } else {
+                win_println(window, THEME_OFFLINE, "-", "  [%s] %s", option->value, option->label);
             }
+            curr_option = g_slist_next(curr_option);
         }
         break;
     case FIELD_LIST_MULTI:
-        if (curr_value) {
-            win_newline(window);
-            GSList* options = field->options;
-            GSList* curr_option = options;
-            while (curr_option) {
-                FormOption* option = curr_option->data;
-                if (g_slist_find_custom(curr_value, option->value, (GCompareFunc)g_strcmp0)) {
-                    win_println(window, THEME_ONLINE, "-", "  [%s] %s", option->value, option->label);
-                } else {
-                    win_println(window, THEME_OFFLINE, "-", "  [%s] %s", option->value, option->label);
-                }
-                curr_option = g_slist_next(curr_option);
+        win_newline(window);
+        curr_option = field->options;
+        while (curr_option) {
+            FormOption* option = curr_option->data;
+            if (g_slist_find_custom(curr_value, option->value, (GCompareFunc)g_strcmp0)) {
+                win_println(window, THEME_ONLINE, "-", "  [%s] %s", option->value, option->label);
+            } else {
+                win_println(window, THEME_OFFLINE, "-", "  [%s] %s", option->value, option->label);
             }
+            curr_option = g_slist_next(curr_option);
         }
         break;
     case FIELD_JID_SINGLE:
diff --git a/src/ui/console.c b/src/ui/console.c
index 12b126c3..d26e559f 100644
--- a/src/ui/console.c
+++ b/src/ui/console.c
@@ -293,7 +293,7 @@ cons_show_typing(const char* const barejid)
         display_usr = barejid;
     }
 
-    win_println(console, THEME_TYPING, "-", "!! %s is typing a message...", display_usr);
+    win_println(console, THEME_TYPING, "-", "!! %s is typing a message…", display_usr);
     cons_alert(NULL);
 }
 
@@ -2008,21 +2008,21 @@ cons_statusbar_setting(void)
         cons_show("Max tab length (/statusbar)                 : %d", pref_len);
     }
 
-    char* pref_self = prefs_get_string(PREF_STATUSBAR_SELF);
+    auto_gchar gchar* 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);
     }
-    g_free(pref_self);
 
-    char* pref_chat = prefs_get_string(PREF_STATUSBAR_CHAT);
+    auto_gchar gchar* pref_chat = prefs_get_string(PREF_STATUSBAR_CHAT);
     cons_show("Chat tab display (/statusbar)               : %s", pref_chat);
-    g_free(pref_chat);
 
-    char* pref_room = prefs_get_string(PREF_STATUSBAR_ROOM);
+    auto_gchar gchar* pref_room = prefs_get_string(PREF_STATUSBAR_ROOM);
     cons_show("Room tab display (/statusbar)               : %s", pref_room);
-    g_free(pref_room);
+
+    auto_gchar gchar* pref_tabmode = prefs_get_string(PREF_STATUSBAR_TABMODE);
+    cons_show("Tab mode (/statusbar)                       : %s", pref_tabmode);
 }
 
 void
diff --git a/src/ui/notifier.c b/src/ui/notifier.c
index 07a542af..36ed73c4 100644
--- a/src/ui/notifier.c
+++ b/src/ui/notifier.c
@@ -77,7 +77,7 @@ notifier_uninit(void)
 void
 notify_typing(const char* const name)
 {
-    gchar* message = g_strdup_printf("%s: typing...", name);
+    gchar* message = g_strdup_printf("%s: typing…", name);
     notify(message, 10000, "Incoming message");
     g_free(message);
 }
diff --git a/src/ui/statusbar.c b/src/ui/statusbar.c
index e447e7d5..38d28c31 100644
--- a/src/ui/statusbar.c
+++ b/src/ui/statusbar.c
@@ -79,14 +79,15 @@ 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_maintext(int pos);
+static int _status_bar_draw_bracket(gboolean current, int pos, const 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);
+static gboolean _tabmode_is_actlist(void);
 
 void
 status_bar_init(void)
@@ -289,21 +290,59 @@ status_bar_draw(void)
 
     pos = _status_bar_draw_time(pos);
 
-    _status_bar_draw_maintext(pos);
+    pos = _status_bar_draw_maintext(pos);
 
-    pos = getmaxx(stdscr) - _tabs_width();
-    if (pos < 0) {
-        pos = 0;
-    }
-    gint max_tabs = prefs_get_statusbartabs();
-    for (int 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);
+    if (!_tabmode_is_actlist()) {
+        pos = getmaxx(stdscr) - _tabs_width();
+        if (pos < 0) {
+            pos = 0;
+        }
+        gint max_tabs = prefs_get_statusbartabs();
+        for (int 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);
+            }
         }
-    }
 
-    _status_bar_draw_extended_tabs(pos);
+        _status_bar_draw_extended_tabs(pos);
+    } else {
+        pos++;
+        guint print_act = 0;
+        guint tabnum = g_hash_table_size(statusbar->tabs);
+        for (guint i = 1; i <= tabnum; ++i) {
+            StatusBarTab* tab = g_hash_table_lookup(statusbar->tabs, GINT_TO_POINTER(i));
+            if (tab && tab->highlight) {
+                print_act++;
+            }
+        }
+        if (print_act) {
+            pos = _status_bar_draw_bracket(FALSE, pos, "[");
+            mvwprintw(statusbar_win, 0, pos, "Act: ");
+            pos += 5;
+            int status_attrs = theme_attrs(THEME_STATUS_NEW);
+
+            wattron(statusbar_win, status_attrs);
+            for (guint i = 1; i <= tabnum && print_act; ++i) {
+                StatusBarTab* tab = g_hash_table_lookup(statusbar->tabs, GINT_TO_POINTER(i));
+                if (tab && tab->highlight) {
+                    if (print_act == 1) {
+                        mvwprintw(statusbar_win, 0, pos, "%d", i);
+                        pos++;
+                    } else {
+                        mvwprintw(statusbar_win, 0, pos, "%d,", i);
+                        pos += 2;
+                    }
+                    for (guint limit = 10; i >= limit; limit *= 10) {
+                        pos++;
+                    }
+                    print_act--;
+                }
+            }
+            wattroff(statusbar_win, status_attrs);
+            pos = _status_bar_draw_bracket(FALSE, pos, "]");
+        }
+    }
 
     wnoutrefresh(statusbar_win);
     inp_put_back();
@@ -410,7 +449,7 @@ _status_bar_draw_tab(StatusBarTab* tab, int pos, int num)
 }
 
 static int
-_status_bar_draw_bracket(gboolean current, int pos, char* ch)
+_status_bar_draw_bracket(gboolean current, int pos, const char* ch)
 {
     int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
     wattron(statusbar_win, bracket_attrs);
@@ -466,39 +505,52 @@ _status_bar_draw_time(int pos)
     return pos;
 }
 
-static void
+static gboolean
+_tabmode_is_actlist(void)
+{
+    auto_char char* tabmode = prefs_get_string(PREF_STATUSBAR_TABMODE);
+    return g_strcmp0(tabmode, "actlist") == 0;
+}
+
+static int
 _status_bar_draw_maintext(int pos)
 {
+    const char* maintext = NULL;
+    auto_jid Jid* jidp = NULL;
+    auto_char char* self = prefs_get_string(PREF_STATUSBAR_SELF);
     if (statusbar->prompt) {
         mvwprintw(statusbar_win, 0, pos, "%s", statusbar->prompt);
-        return;
+        return utf8_display_len(statusbar->prompt);
+    } else if (g_strcmp0(self, "off") == 0) {
+        return pos;
+    } else if (statusbar->fulljid) {
+        jidp = jid_create(statusbar->fulljid);
+        if (g_strcmp0(self, "user") == 0) {
+            maintext = jidp->localpart;
+        } else if (g_strcmp0(self, "barejid") == 0) {
+            maintext = jidp->barejid;
+        } else {
+            maintext = statusbar->fulljid;
+        }
     }
 
-    gboolean stop = FALSE;
-
-    if (statusbar->fulljid) {
-        char* pref = prefs_get_string(PREF_STATUSBAR_SELF);
-
-        if (g_strcmp0(pref, "off") == 0) {
-            stop = true;
-        } else if (g_strcmp0(pref, "user") == 0) {
-            Jid* jidp = jid_create(statusbar->fulljid);
-            mvwprintw(statusbar_win, 0, pos, "%s", jidp->localpart);
-            jid_destroy(jidp);
-            stop = true;
-        } else if (g_strcmp0(pref, "barejid") == 0) {
-            Jid* jidp = jid_create(statusbar->fulljid);
-            mvwprintw(statusbar_win, 0, pos, "%s", jidp->barejid);
-            jid_destroy(jidp);
-            stop = true;
-        }
+    if (maintext == NULL) {
+        return pos;
+    }
 
-        g_free(pref);
-        if (stop) {
-            return;
-        }
-        mvwprintw(statusbar_win, 0, pos, "%s", statusbar->fulljid);
+    gboolean actlist_tabmode = _tabmode_is_actlist();
+    auto_gchar gchar* maintext_ = NULL;
+    if (actlist_tabmode) {
+        pos = _status_bar_draw_bracket(FALSE, pos, "[");
+        maintext_ = g_strdup_printf("%d:%s", statusbar->current_tab, maintext);
+        maintext = maintext_;
     }
+    mvwprintw(statusbar_win, 0, pos, "%s", maintext);
+    pos += utf8_display_len(maintext);
+    if (actlist_tabmode) {
+        pos = _status_bar_draw_bracket(FALSE, pos, "]");
+    }
+    return pos;
 }
 
 static void
diff --git a/src/xmpp/connection.c b/src/xmpp/connection.c
index 3eca29c4..9c398c73 100644
--- a/src/xmpp/connection.c
+++ b/src/xmpp/connection.c
@@ -414,7 +414,7 @@ _register_handle_features(xmpp_conn_t* xmpp_conn, xmpp_stanza_t* stanza, void* u
     /* secure connection if possible */
     child = xmpp_stanza_get_child_by_name(stanza, "starttls");
     if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0)) {
-        log_debug("Server supports TLS. Attempting to establish...");
+        log_debug("Server supports TLS. Attempting to establish…");
         child = xmpp_stanza_new(ctx);
         xmpp_stanza_set_name(child, "starttls");
         xmpp_stanza_set_ns(child, XMPP_NS_TLS);
diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c
index f898914b..e48d187a 100644
--- a/src/xmpp/iq.c
+++ b/src/xmpp/iq.c
@@ -2610,7 +2610,7 @@ static int
 _mam_buffer_commit_handler(xmpp_stanza_t* const stanza, void* const userdata)
 {
     ProfChatWin* chatwin = (ProfChatWin*)userdata;
-    // Remove the "Loading messages ..." message
+    // Remove the "Loading messages …" message
     buffer_remove_entry(((ProfWin*)chatwin)->layout->buffer, 0);
     chatwin_db_history(chatwin, NULL, NULL, TRUE);
     return 0;
diff --git a/src/xmpp/ox.c b/src/xmpp/ox.c
index c0e20744..85fef800 100644
--- a/src/xmpp/ox.c
+++ b/src/xmpp/ox.c
@@ -91,7 +91,7 @@ ox_announce_public_key(const char* const filename)
 {
     assert(filename);
 
-    cons_show("Announce OpenPGP Key for OX %s ...", filename);
+    cons_show("Announce OpenPGP Key for OX %s …", filename);
     log_info("[OX] Announce OpenPGP Key of OX: %s", filename);
 
     // key the key and the fingerprint via GnuPG from file
diff --git a/themes/batman b/themes/batman
index fa7e7f18..b0b7a9ba 100644
--- a/themes/batman
+++ b/themes/batman
@@ -27,7 +27,7 @@ incoming=yellow
 mention=cyan
 trigger=cyan
 roominfo=green
-me=black_bold
+me=bold_black
 them=yellow
 titlebar.unencrypted=red
 titlebar.encrypted=green
@@ -47,7 +47,7 @@ titlebar.xa=magenta
 main.text.me=white
 main.text.them=white
 subscribed=magenta
-unsubscribed=black_bold
+unsubscribed=bold_black
 roommention=cyan
 roommention.term=cyan
 roomtrigger=cyan