summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common.h2
-rw-r--r--src/core/ignore.h6
-rw-r--r--src/core/levels.c21
-rw-r--r--src/core/levels.h4
-rw-r--r--src/core/misc.c7
-rw-r--r--src/core/network-openssl.c38
-rw-r--r--src/core/settings.c10
-rw-r--r--src/core/settings.h7
-rw-r--r--src/core/special-vars.c4
-rw-r--r--src/fe-common/core/Makefile.am1
-rw-r--r--src/fe-common/core/command-history.c233
-rw-r--r--src/fe-common/core/command-history.h19
-rw-r--r--src/fe-common/core/completion.c18
-rw-r--r--src/fe-common/core/fe-channels.c2
-rw-r--r--src/fe-common/core/fe-common-core.c51
-rw-r--r--src/fe-common/core/fe-exec.c2
-rw-r--r--src/fe-common/core/fe-server.c2
-rw-r--r--src/fe-common/core/fe-settings.c7
-rw-r--r--src/fe-common/core/fe-settings.h6
-rw-r--r--src/fe-common/core/fe-windows.c4
-rw-r--r--src/fe-common/core/fe-windows.h8
-rw-r--r--src/fe-common/core/formats.c57
-rw-r--r--src/fe-common/core/hilight-text.c7
-rw-r--r--src/fe-common/core/window-commands.c7
-rw-r--r--src/fe-common/core/window-items.c2
-rw-r--r--src/fe-common/irc/fe-ircnet.c2
-rw-r--r--src/fe-common/irc/fe-netjoin.c5
-rw-r--r--src/fe-common/irc/fe-netsplit.c9
-rw-r--r--src/fe-fuzz/irssi.c2
-rw-r--r--src/fe-text/gui-printtext.c43
-rw-r--r--src/fe-text/gui-printtext.h1
-rw-r--r--src/fe-text/gui-readline.c41
-rw-r--r--src/fe-text/gui-windows.c18
-rw-r--r--src/fe-text/irssi.c52
-rw-r--r--src/fe-text/mainwindows-layout.c169
-rw-r--r--src/fe-text/mainwindows.c1148
-rw-r--r--src/fe-text/mainwindows.h22
-rw-r--r--src/fe-text/module-formats.c26
-rw-r--r--src/fe-text/module-formats.h7
-rw-r--r--src/fe-text/statusbar-items.c23
-rw-r--r--src/fe-text/statusbar.c72
-rw-r--r--src/fe-text/statusbar.h6
-rw-r--r--src/fe-text/term-terminfo.c110
-rw-r--r--src/fe-text/term.h4
-rw-r--r--src/fe-text/textbuffer-commands.c21
-rw-r--r--src/fe-text/textbuffer-view.c188
-rw-r--r--src/fe-text/textbuffer-view.h36
-rw-r--r--src/fe-text/textbuffer.c1
-rw-r--r--src/fe-text/textbuffer.h2
-rw-r--r--src/irc/core/channel-events.c8
-rw-r--r--src/irc/core/irc-nicklist.c19
-rw-r--r--src/irc/core/irc-servers-setup.c11
-rw-r--r--src/irc/core/irc.c34
-rw-r--r--src/irc/core/sasl.c6
-rw-r--r--src/perl/Makefile.am2
-rw-r--r--src/perl/common/Expando.xs3
-rw-r--r--src/perl/textui/Statusbar.xs4
-rw-r--r--src/perl/textui/TextUI.xs1
-rw-r--r--src/perl/ui/Window.xs144
59 files changed, 2230 insertions, 535 deletions
diff --git a/src/common.h b/src/common.h
index 159f7124..ba5557e6 100644
--- a/src/common.h
+++ b/src/common.h
@@ -6,7 +6,7 @@
#define IRSSI_GLOBAL_CONFIG "irssi.conf" /* config file name in /etc/ */
#define IRSSI_HOME_CONFIG "config" /* config file name in ~/.irssi/ */
-#define IRSSI_ABI_VERSION 11
+#define IRSSI_ABI_VERSION 13
#define DEFAULT_SERVER_ADD_PORT 6667
#define DEFAULT_SERVER_ADD_TLS_PORT 6697
diff --git a/src/core/ignore.h b/src/core/ignore.h
index e18be3c4..31171b58 100644
--- a/src/core/ignore.h
+++ b/src/core/ignore.h
@@ -27,14 +27,14 @@ int ignore_check(SERVER_REC *server, const char *nick, const char *host,
const char *channel, const char *text, int level);
enum {
- IGNORE_FIND_PATTERN = 0x01, // Match the pattern
- IGNORE_FIND_NOACT = 0x02, // Exclude the targets with NOACT level
+ IGNORE_FIND_PATTERN = 0x01, /* Match the pattern */
+ IGNORE_FIND_NOACT = 0x02, /* Exclude the targets with NOACT level */
};
IGNORE_REC *ignore_find_full (const char *servertag, const char *mask, const char *pattern,
char **channels, const int flags);
-// Convenience wrappers around ignore_find_full, for compatibility purpose
+/* Convenience wrappers around ignore_find_full, for compatibility purpose */
IGNORE_REC *ignore_find(const char *servertag, const char *mask, char **channels);
IGNORE_REC *ignore_find_noact(const char *servertag, const char *mask, char **channels, int noact);
diff --git a/src/core/levels.c b/src/core/levels.c
index e623c4de..eb7efcf7 100644
--- a/src/core/levels.c
+++ b/src/core/levels.c
@@ -21,6 +21,7 @@
#include "module.h"
#include "levels.h"
+/* the order of these levels must match the bits in levels.h */
static const char *levels[] = {
"CRAP",
"MSGS",
@@ -44,9 +45,6 @@ static const char *levels[] = {
"CLIENTCRAP",
"CLIENTERRORS",
"HILIGHTS",
-
- "NOHILIGHT",
- "NO_ACT",
NULL
};
@@ -63,6 +61,9 @@ int level_get(const char *level)
if (g_ascii_strcasecmp(level, "NO_ACT") == 0)
return MSGLEVEL_NO_ACT;
+ if (g_ascii_strcasecmp(level, "HIDDEN") == 0)
+ return MSGLEVEL_HIDDEN;
+
len = strlen(level);
if (len == 0) return 0;
@@ -138,17 +139,13 @@ char *bits2level(int bits)
str = g_string_new(NULL);
- if (bits & MSGLEVEL_NEVER) {
+ if (bits & MSGLEVEL_NEVER)
g_string_append(str, "NEVER ");
- bits &= ~MSGLEVEL_NEVER;
- }
- if (bits & MSGLEVEL_NO_ACT) {
+ if (bits & MSGLEVEL_NO_ACT)
g_string_append(str, "NO_ACT ");
- bits &= ~MSGLEVEL_NO_ACT;
- }
- if (bits == MSGLEVEL_ALL) {
+ if ((bits & MSGLEVEL_ALL) == MSGLEVEL_ALL) {
g_string_append(str, "ALL ");
} else {
for (n = 0; levels[n] != NULL; n++) {
@@ -156,6 +153,10 @@ char *bits2level(int bits)
g_string_append_printf(str, "%s ", levels[n]);
}
}
+
+ if (bits & MSGLEVEL_HIDDEN)
+ g_string_append(str, "HIDDEN ");
+
if (str->len > 0)
g_string_truncate(str, str->len-1);
diff --git a/src/core/levels.h b/src/core/levels.h
index 9f7e588f..b0ebafba 100644
--- a/src/core/levels.h
+++ b/src/core/levels.h
@@ -36,7 +36,9 @@ enum {
MSGLEVEL_NOHILIGHT = 0x1000000, /* Don't highlight this message */
MSGLEVEL_NO_ACT = 0x2000000, /* Don't trigger channel activity */
MSGLEVEL_NEVER = 0x4000000, /* never ignore / never log */
- MSGLEVEL_LASTLOG = 0x8000000 /* never ignore / never log */
+ MSGLEVEL_LASTLOG = 0x8000000, /* used for /lastlog */
+
+ MSGLEVEL_HIDDEN = 0x10000000 /* Hidden from view */
};
int level_get(const char *level);
diff --git a/src/core/misc.c b/src/core/misc.c
index e589b8c5..4e9f4bbe 100644
--- a/src/core/misc.c
+++ b/src/core/misc.c
@@ -703,8 +703,11 @@ int expand_escape(const char **data)
*data += 2;
return strtol(digit, NULL, 16);
case 'c':
- /* control character (\cA = ^A) */
- (*data)++;
+ /* check for end of string */
+ if ((*data)[1] == '\0')
+ return 0;
+ /* control character (\cA = ^A) */
+ (*data)++;
return i_toupper(**data) - 64;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
diff --git a/src/core/network-openssl.c b/src/core/network-openssl.c
index 7ec902fb..c7ce4b43 100644
--- a/src/core/network-openssl.c
+++ b/src/core/network-openssl.c
@@ -583,9 +583,6 @@ static void set_cipher_info(TLS_REC *tls, SSL *ssl)
static void set_pubkey_info(TLS_REC *tls, X509 *cert, unsigned char *cert_fingerprint, size_t cert_fingerprint_size, unsigned char *public_key_fingerprint, size_t public_key_fingerprint_size)
{
- g_return_if_fail(tls != NULL);
- g_return_if_fail(cert != NULL);
-
EVP_PKEY *pubkey = NULL;
char *cert_fingerprint_hex = NULL;
char *public_key_fingerprint_hex = NULL;
@@ -594,13 +591,16 @@ static void set_pubkey_info(TLS_REC *tls, X509 *cert, unsigned char *cert_finger
char buffer[128];
size_t length;
+ g_return_if_fail(tls != NULL);
+ g_return_if_fail(cert != NULL);
+
pubkey = X509_get_pubkey(cert);
cert_fingerprint_hex = binary_to_hex(cert_fingerprint, cert_fingerprint_size);
tls_rec_set_certificate_fingerprint(tls, cert_fingerprint_hex);
tls_rec_set_certificate_fingerprint_algorithm(tls, "SHA256");
- // Show algorithm.
+ /* Show algorithm. */
switch (EVP_PKEY_id(pubkey)) {
case EVP_PKEY_RSA:
tls_rec_set_public_key_algorithm(tls, "RSA");
@@ -624,7 +624,7 @@ static void set_pubkey_info(TLS_REC *tls, X509 *cert, unsigned char *cert_finger
tls_rec_set_public_key_size(tls, EVP_PKEY_bits(pubkey));
tls_rec_set_public_key_fingerprint_algorithm(tls, "SHA256");
- // Read the NotBefore timestamp.
+ /* Read the NotBefore timestamp. */
bio = BIO_new(BIO_s_mem());
ASN1_TIME_print(bio, X509_get_notBefore(cert));
length = BIO_read(bio, buffer, sizeof(buffer));
@@ -632,7 +632,7 @@ static void set_pubkey_info(TLS_REC *tls, X509 *cert, unsigned char *cert_finger
BIO_free(bio);
tls_rec_set_not_before(tls, buffer);
- // Read the NotAfter timestamp.
+ /* Read the NotAfter timestamp. */
bio = BIO_new(BIO_s_mem());
ASN1_TIME_print(bio, X509_get_notAfter(cert));
length = BIO_read(bio, buffer, sizeof(buffer));
@@ -647,9 +647,6 @@ static void set_pubkey_info(TLS_REC *tls, X509 *cert, unsigned char *cert_finger
static void set_peer_cert_chain_info(TLS_REC *tls, SSL *ssl)
{
- g_return_if_fail(tls != NULL);
- g_return_if_fail(ssl != NULL);
-
int nid;
char *key = NULL;
char *value = NULL;
@@ -662,6 +659,9 @@ static void set_peer_cert_chain_info(TLS_REC *tls, SSL *ssl)
TLS_CERT_ENTRY_REC *tls_cert_entry_rec = NULL;
ASN1_STRING *data = NULL;
+ g_return_if_fail(tls != NULL);
+ g_return_if_fail(ssl != NULL);
+
chain = SSL_get_peer_cert_chain(ssl);
if (chain == NULL)
@@ -670,7 +670,7 @@ static void set_peer_cert_chain_info(TLS_REC *tls, SSL *ssl)
for (i = 0; i < sk_X509_num(chain); i++) {
cert_rec = tls_cert_create_rec();
- // Subject.
+ /* Subject. */
name = X509_get_subject_name(sk_X509_value(chain, i));
for (j = 0; j < X509_NAME_entry_count(name); j++) {
@@ -689,7 +689,7 @@ static void set_peer_cert_chain_info(TLS_REC *tls, SSL *ssl)
tls_cert_rec_append_subject_entry(cert_rec, tls_cert_entry_rec);
}
- // Issuer.
+ /* Issuer. */
name = X509_get_issuer_name(sk_X509_value(chain, i));
for (j = 0; j < X509_NAME_entry_count(name); j++) {
@@ -714,14 +714,11 @@ static void set_peer_cert_chain_info(TLS_REC *tls, SSL *ssl)
static void set_server_temporary_key_info(TLS_REC *tls, SSL *ssl)
{
- g_return_if_fail(tls != NULL);
- g_return_if_fail(ssl != NULL);
-
#ifdef SSL_get_server_tmp_key
- // Show ephemeral key information.
+ /* Show ephemeral key information. */
EVP_PKEY *ephemeral_key = NULL;
- // OPENSSL_NO_EC is for solaris 11.3 (2016), github ticket #598
+ /* OPENSSL_NO_EC is for solaris 11.3 (2016), github ticket #598 */
#ifndef OPENSSL_NO_EC
EC_KEY *ec_key = NULL;
#endif
@@ -729,6 +726,9 @@ static void set_server_temporary_key_info(TLS_REC *tls, SSL *ssl)
char *cname = NULL;
int nid;
+ g_return_if_fail(tls != NULL);
+ g_return_if_fail(ssl != NULL);
+
if (SSL_get_server_tmp_key(ssl, &ephemeral_key)) {
switch (EVP_PKEY_id(ephemeral_key)) {
case EVP_PKEY_DH:
@@ -759,7 +759,7 @@ static void set_server_temporary_key_info(TLS_REC *tls, SSL *ssl)
EVP_PKEY_free(ephemeral_key);
}
-#endif // SSL_get_server_tmp_key.
+#endif /* SSL_get_server_tmp_key. */
}
GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, SERVER_REC *server)
@@ -866,7 +866,7 @@ int irssi_ssl_handshake(GIOChannel *handle)
set_peer_cert_chain_info(tls, chan->ssl);
set_server_temporary_key_info(tls, chan->ssl);
- // Emit the TLS rec.
+ /* Emit the TLS rec. */
signal_emit("tls handshake finished", 2, chan->server, tls);
ret = 1;
@@ -893,7 +893,7 @@ int irssi_ssl_handshake(GIOChannel *handle)
ret = irssi_ssl_verify(chan->ssl, chan->ctx, chan->server->connrec->address, chan->port, cert, chan->server, tls);
if (! ret) {
- // irssi_ssl_verify emits a warning itself.
+ /* irssi_ssl_verify emits a warning itself. */
goto done;
}
}
diff --git a/src/core/settings.c b/src/core/settings.c
index 4e0717cd..3ebb9e4a 100644
--- a/src/core/settings.c
+++ b/src/core/settings.c
@@ -39,6 +39,7 @@ static GString *last_errors;
static GSList *last_invalid_modules;
static int fe_initialized;
static int config_changed; /* FIXME: remove after .98 (unless needed again) */
+static unsigned int user_settings_changed;
static GHashTable *settings;
static int timeout_tag;
@@ -464,6 +465,11 @@ SETTINGS_REC *settings_get_record(const char *key)
return g_hash_table_lookup(settings, key);
}
+static void sig_init_userinfo_changed(gpointer changedp)
+{
+ user_settings_changed |= GPOINTER_TO_UINT(changedp);
+}
+
static void sig_init_finished(void)
{
fe_initialized = TRUE;
@@ -479,6 +485,8 @@ static void sig_init_finished(void)
"updated, please /SAVE");
signal_emit("setup changed", 0);
}
+
+ signal_emit("settings userinfo changed", 1, GUINT_TO_POINTER(user_settings_changed));
}
static void settings_clean_invalid_module(const char *module)
@@ -875,6 +883,7 @@ void settings_init(void)
timeout_tag = g_timeout_add(SETTINGS_AUTOSAVE_TIMEOUT,
(GSourceFunc) sig_autosave, NULL);
signal_add("irssi init finished", (SIGNAL_FUNC) sig_init_finished);
+ signal_add("irssi init userinfo changed", (SIGNAL_FUNC) sig_init_userinfo_changed);
signal_add("gui exit", (SIGNAL_FUNC) sig_autosave);
}
@@ -887,6 +896,7 @@ void settings_deinit(void)
{
g_source_remove(timeout_tag);
signal_remove("irssi init finished", (SIGNAL_FUNC) sig_init_finished);
+ signal_remove("irssi init userinfo changed", (SIGNAL_FUNC) sig_init_userinfo_changed);
signal_remove("gui exit", (SIGNAL_FUNC) sig_autosave);
g_slist_foreach(last_invalid_modules, (GFunc) g_free, NULL);
diff --git a/src/core/settings.h b/src/core/settings.h
index d174f250..b67a9e44 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -30,6 +30,13 @@ typedef struct {
char **choices;
} SETTINGS_REC;
+enum {
+ USER_SETTINGS_REAL_NAME = 0x1,
+ USER_SETTINGS_USER_NAME = 0x2,
+ USER_SETTINGS_NICK = 0x4,
+ USER_SETTINGS_HOSTNAME = 0x8,
+};
+
/* macros for handling the default Irssi configuration */
#define iconfig_get_str(a, b, c) config_get_str(mainconfig, a, b, c)
#define iconfig_get_int(a, b, c) config_get_int(mainconfig, a, b, c)
diff --git a/src/core/special-vars.c b/src/core/special-vars.c
index aaf8da8f..f254c200 100644
--- a/src/core/special-vars.c
+++ b/src/core/special-vars.c
@@ -384,6 +384,7 @@ char *parse_special(char **cmd, SERVER_REC *server, void *item,
}
nest_free = FALSE; nest_value = NULL;
+#if 0 /* this code is disabled due to security issues until it is fixed */
if (**cmd == '(' && (*cmd)[1] != '\0') {
/* subvariable */
int toplevel = nested_orig_cmd == NULL;
@@ -412,6 +413,9 @@ char *parse_special(char **cmd, SERVER_REC *server, void *item,
if (toplevel) nested_orig_cmd = NULL;
}
+#else
+ if (nested_orig_cmd) nested_orig_cmd = NULL;
+#endif
if (**cmd != '{')
brackets = FALSE;
diff --git a/src/fe-common/core/Makefile.am b/src/fe-common/core/Makefile.am
index 29cc941a..cf4e8ee3 100644
--- a/src/fe-common/core/Makefile.am
+++ b/src/fe-common/core/Makefile.am
@@ -55,6 +55,7 @@ pkginc_fe_common_core_HEADERS = \
fe-exec.h \
fe-messages.h \
fe-queries.h \
+ fe-settings.h \
fe-tls.h \
formats.h \
hilight-text.h \
diff --git a/src/fe-common/core/command-history.c b/src/fe-common/core/command-history.c
index 55474b1b..32d7adaa 100644
--- a/src/fe-common/core/command-history.c
+++ b/src/fe-common/core/command-history.c
@@ -30,10 +30,93 @@
#include "command-history.h"
/* command history */
+static GList *history_entries;
static HISTORY_REC *global_history;
static int window_history;
static GSList *histories;
+static HISTORY_ENTRY_REC *history_entry_new(HISTORY_REC *history, const char *text)
+{
+ HISTORY_ENTRY_REC *entry;
+
+ entry = g_new0(HISTORY_ENTRY_REC, 1);
+ entry->text = g_strdup(text);
+ entry->history = history;
+ entry->time = time(NULL);
+
+ return entry;
+}
+
+static void history_entry_destroy(HISTORY_ENTRY_REC *entry)
+{
+ g_free((char *)entry->text);
+ g_free(entry);
+}
+
+GList *command_history_list_last(HISTORY_REC *history)
+{
+ GList *link;
+
+ link = g_list_last(history_entries);
+ while (link != NULL && history != NULL && ((HISTORY_ENTRY_REC *)link->data)->history != history) {
+ link = link->prev;
+ }
+
+ return link;
+}
+
+GList *command_history_list_first(HISTORY_REC *history)
+{
+ GList *link;
+
+ link = history_entries;
+ while (link != NULL && history != NULL && ((HISTORY_ENTRY_REC *)link->data)->history != history) {
+ link = link->next;
+ }
+
+ return link;
+}
+
+GList *command_history_list_prev(HISTORY_REC *history, GList *pos)
+{
+ GList *link;
+
+ link = pos != NULL ? pos->prev : NULL;
+ while (link != NULL && history != NULL && ((HISTORY_ENTRY_REC *)link->data)->history != history) {
+ link = link->prev;
+ }
+
+ return link;
+}
+
+GList *command_history_list_next(HISTORY_REC *history, GList *pos)
+{
+ GList *link;
+
+ link = pos != NULL ? pos->next : NULL;
+ while (link != NULL && history != NULL && ((HISTORY_ENTRY_REC *)link->data)->history != history) {
+ link = link->next;
+ }
+
+ return link;
+}
+
+static void command_history_clear_pos_for_unlink_func(HISTORY_REC *history, GList* link)
+{
+ if (history->pos == link) {
+ history->pos = command_history_list_next(history, link);
+ history->redo = 1;
+ }
+}
+
+static void history_list_delete_link_and_destroy(GList *link)
+{
+ g_slist_foreach(histories,
+ (GFunc) command_history_clear_pos_for_unlink_func, link);
+ history_entry_destroy(link->data);
+ history_entries = g_list_delete_link(history_entries, link);
+}
+
void command_history_add(HISTORY_REC *history, const char *text)
{
GList *link;
@@ -41,21 +124,19 @@ void command_history_add(HISTORY_REC *history, const char *text)
g_return_if_fail(history != NULL);
g_return_if_fail(text != NULL);
- link = g_list_last(history->list);
- if (link != NULL && g_strcmp0(link->data, text) == 0)
- return; /* same as previous entry */
+ link = command_history_list_last(history);
+ if (link != NULL && g_strcmp0(((HISTORY_ENTRY_REC *)link->data)->text, text) == 0)
+ return; /* same as previous entry */
if (settings_get_int("max_command_history") < 1 ||
history->lines < settings_get_int("max_command_history"))
history->lines++;
else {
- link = history->list;
- g_free(link->data);
- history->list = g_list_remove_link(history->list, link);
- g_list_free_1(link);
+ link = command_history_list_first(history);
+ history_list_delete_link_and_destroy(link);
}
- history->list = g_list_append(history->list, g_strdup(text));
+ history_entries = g_list_append(history_entries, history_entry_new(history, text));
}
HISTORY_REC *command_history_find(HISTORY_REC *history)
@@ -87,6 +168,61 @@ HISTORY_REC *command_history_find_name(const char *name)
return NULL;
}
+static int history_entry_after_time_sort(const HISTORY_ENTRY_REC *a, const HISTORY_ENTRY_REC *b)
+{
+ return a->time == b->time ? 1 : a->time - b->time;
+}
+
+void command_history_load_entry(time_t history_time, HISTORY_REC *history, const char *text)
+{
+ HISTORY_ENTRY_REC *entry;
+
+ g_return_if_fail(history != NULL);
+ g_return_if_fail(text != NULL);
+
+ entry = g_new0(HISTORY_ENTRY_REC, 1);
+ entry->text = g_strdup(text);
+ entry->history = history;
+ entry->time = history_time;
+
+ history->lines++;
+
+ history_entries = g_list_insert_sorted(history_entries, entry, (GCompareFunc)history_entry_after_time_sort);
+}
+
+static int history_entry_find_func(const HISTORY_ENTRY_REC *data, const HISTORY_ENTRY_REC *user_data)
+{
+ if ((user_data->time == -1 || (data->time == user_data->time)) &&
+ (user_data->history == NULL || (data->history == user_data->history)) &&
+ g_strcmp0(data->text, user_data->text) == 0) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+gboolean command_history_delete_entry(time_t history_time, HISTORY_REC *history, const char *text)
+{
+ GList *link;
+ HISTORY_ENTRY_REC entry;
+
+ g_return_val_if_fail(history != NULL, FALSE);
+ g_return_val_if_fail(text != NULL, FALSE);
+
+ entry.text = text;
+ entry.history = history;
+ entry.time = history_time;
+
+ link = g_list_find_custom(history_entries, &entry, (GCompareFunc)history_entry_find_func);
+ if (link != NULL) {
+ ((HISTORY_ENTRY_REC *)link->data)->history->lines--;
+ history_list_delete_link_and_destroy(link);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
HISTORY_REC *command_history_current(WINDOW_REC *window)
{
HISTORY_REC *rec;
@@ -104,32 +240,44 @@ HISTORY_REC *command_history_current(WINDOW_REC *window)
return global_history;
}
-const char *command_history_prev(WINDOW_REC *window, const char *text)
+static const char *command_history_prev_int(WINDOW_REC *window, const char *text, gboolean global)
{
HISTORY_REC *history;
GList *pos;
history = command_history_current(window);
pos = history->pos;
+ history->redo = 0;
if (pos != NULL) {
/* don't go past the first entry (no wrap around) */
- if (history->pos->prev != NULL)
- history->pos = history->pos->prev;
+ GList *prev = command_history_list_prev(global ? NULL : history, history->pos);
+ if (prev != NULL)
+ history->pos = prev;
} else {
- history->pos = g_list_last(history->list);
+ history->pos = command_history_list_last(global ? NULL : history);
}
if (*text != '\0' &&
- (pos == NULL || g_strcmp0(pos->data, text) != 0)) {
+ (pos == NULL || g_strcmp0(((HISTORY_ENTRY_REC *)pos->data)->text, text) != 0)) {
/* save the old entry to history */
command_history_add(history, text);
}
- return history->pos == NULL ? text : history->pos->data;
+ return history->pos == NULL ? text : ((HISTORY_ENTRY_REC *)history->pos->data)->text;
}
-const char *command_history_next(WINDOW_REC *window, const char *text)
+const char *command_history_prev(WINDOW_REC *window, const char *text)
+{
+ return command_history_prev_int(window, text, FALSE);
+}
+
+const char *command_global_history_prev(WINDOW_REC *window, const char *text)
+{
+ return command_history_prev_int(window, text, TRUE);
+}
+
+static const char *command_history_next_int(WINDOW_REC *window, const char *text, gboolean global)
{
HISTORY_REC *history;
GList *pos;
@@ -137,15 +285,43 @@ const char *command_history_next(WINDOW_REC *window, const char *text)
history = command_history_current(window);
pos = history->pos;
- if (pos != NULL)
- history->pos = history->pos->next;
+ if (!(history->redo) && pos != NULL)
+ history->pos = command_history_list_next(global ? NULL : history, history->pos);
+ history->redo = 0;
if (*text != '\0' &&
- (pos == NULL || g_strcmp0(pos->data, text) != 0)) {
+ (pos == NULL || g_strcmp0(((HISTORY_ENTRY_REC *)pos->data)->text, text) != 0)) {
/* save the old entry to history */
command_history_add(history, text);
}
- return history->pos == NULL ? "" : history->pos->data;
+ return history->pos == NULL ? "" : ((HISTORY_ENTRY_REC *)history->pos->data)->text;
+}
+
+const char *command_history_next(WINDOW_REC *window, const char *text)
+{
+ return command_history_next_int(window, text, FALSE);
+}
+
+const char *command_global_history_next(WINDOW_REC *window, const char *text)
+{
+ return command_history_next_int(window, text, TRUE);
+}
+
+const char *command_history_delete_current(WINDOW_REC *window, const char *text)
+{
+ HISTORY_REC *history;
+ GList *pos;
+
+ history = command_history_current(window);
+ pos = history->pos;
+
+ if (pos != NULL && g_strcmp0(((HISTORY_ENTRY_REC *)pos->data)->text, text) == 0) {
+ ((HISTORY_ENTRY_REC *)pos->data)->history->lines--;
+ history_list_delete_link_and_destroy(pos);
+ }
+
+ history->redo = 0;
+ return history->pos == NULL ? "" : ((HISTORY_ENTRY_REC *)history->pos->data)->text;
}
void command_history_clear_pos_func(HISTORY_REC *history, gpointer user_data)
@@ -175,12 +351,17 @@ HISTORY_REC *command_history_create(const char *name)
void command_history_clear(HISTORY_REC *history)
{
+ GList *link, *next;
+
g_return_if_fail(history != NULL);
command_history_clear_pos_func(history, NULL);
- g_list_foreach(history->list, (GFunc) g_free, NULL);
- g_list_free(history->list);
- history->list = NULL;
+ link = command_history_list_first(history);
+ while (link != NULL) {
+ next = command_history_list_next(history, link);
+ history_list_delete_link_and_destroy(link);
+ link = next;
+ }
history->lines = 0;
}
@@ -264,8 +445,8 @@ static char *special_history_func(const char *text, void *item, int *free_ret)
ret = NULL;
history = command_history_current(window);
- for (tmp = history->list; tmp != NULL; tmp = tmp->next) {
- const char *line = tmp->data;
+ for (tmp = command_history_list_first(history); tmp != NULL; tmp = command_history_list_next(history, tmp)) {
+ const char *line = ((HISTORY_ENTRY_REC *)tmp->data)->text;
if (match_wildcards(findtext, line)) {
*free_ret = TRUE;
@@ -289,6 +470,8 @@ void command_history_init(void)
special_history_func_set(special_history_func);
+ history_entries = NULL;
+
global_history = command_history_create(NULL);
read_settings();
@@ -308,4 +491,6 @@ void command_history_deinit(void)
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
command_history_destroy(global_history);
+
+ g_list_free_full(history_entries, (GDestroyNotify) history_entry_destroy);
}
diff --git a/src/fe-common/core/command-history.h b/src/fe-common/core/command-history.h
index 45126092..ed093415 100644
--- a/src/fe-common/core/command-history.h
+++ b/src/fe-common/core/command-history.h
@@ -6,12 +6,19 @@
typedef struct {
char *name;
- GList *list, *pos;
+ GList *pos;
int lines;
int refcount;
+ int redo:1;
} HISTORY_REC;
+typedef struct {
+ const char *text;
+ HISTORY_REC *history;
+ time_t time;
+} HISTORY_ENTRY_REC;
+
HISTORY_REC *command_history_find(HISTORY_REC *history);
HISTORY_REC *command_history_find_name(const char *name);
@@ -21,9 +28,19 @@ void command_history_init(void);
void command_history_deinit(void);
void command_history_add(HISTORY_REC *history, const char *text);
+void command_history_load_entry(time_t time, HISTORY_REC *history, const char *text);
+gboolean command_history_delete_entry(time_t history_time, HISTORY_REC *history, const char *text);
+
+GList *command_history_list_last(HISTORY_REC *history);
+GList *command_history_list_first(HISTORY_REC *history);
+GList *command_history_list_prev(HISTORY_REC *history, GList *pos);
+GList *command_history_list_next(HISTORY_REC *history, GList *pos);
const char *command_history_prev(WINDOW_REC *window, const char *text);
const char *command_history_next(WINDOW_REC *window, const char *text);
+const char *command_global_history_prev(WINDOW_REC *window, const char *text);
+const char *command_global_history_next(WINDOW_REC *window, const char *text);
+const char *command_history_delete_current(WINDOW_REC *window, const char *text);
void command_history_clear_pos(WINDOW_REC *window);
diff --git a/src/fe-common/core/completion.c b/src/fe-common/core/completion.c
index e78fe7d5..fd452e5c 100644
--- a/src/fe-common/core/completion.c
+++ b/src/fe-common/core/completion.c
@@ -187,12 +187,18 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i
char *old;
old = linestart;
- linestart = *linestart == '\0' ?
- g_strdup(word) :
- g_strdup_printf("%s%c%s",
- /* do not accidentally duplicate the word separator */
- line == wordstart - 1 ? "" : linestart,
- old_wordstart[-1], word);
+ /* we want to move word into linestart */
+ if (*linestart == '\0') {
+ linestart = g_strdup(word);
+ } else {
+ GString *str = g_string_new(linestart);
+ if (old_wordstart[-1] != str->str[str->len - 1]) {
+ /* do not accidentally duplicate the word separator */
+ g_string_append_c(str, old_wordstart[-1]);
+ }
+ g_string_append(str, word);
+ linestart = g_string_free(str, FALSE);
+ }
g_free(old);
g_free(word);
diff --git a/src/fe-common/core/fe-channels.c b/src/fe-common/core/fe-channels.c
index 8e434ab5..5cad51a7 100644
--- a/src/fe-common/core/fe-channels.c
+++ b/src/fe-common/core/fe-channels.c
@@ -278,9 +278,9 @@ static void cmd_channel_add_modify(const char *data, gboolean add)
rec = channel_setup_find(channel, chatnet);
if (rec == NULL) {
if (add == FALSE) {
- cmd_params_free(free_arg);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
TXT_CHANSETUP_NOT_FOUND, channel, chatnet);
+ cmd_params_free(free_arg);
return;
}
diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c
index a3b7364c..209c2d9e 100644
--- a/src/fe-common/core/fe-common-core.c
+++ b/src/fe-common/core/fe-common-core.c
@@ -470,26 +470,49 @@ void fe_common_core_finish_init(void)
gboolean strarray_find_dest(char **array, const TEXT_DEST_REC *dest)
{
+ WI_ITEM_REC *item;
+ int server_tag_len, channel_type, query_type;
+ char **tmp;
+
+ channel_type = module_get_uniq_id_str("WINDOW ITEM TYPE", "CHANNEL");
+ query_type = module_get_uniq_id_str("WINDOW ITEM TYPE", "QUERY");
+
g_return_val_if_fail(array != NULL, FALSE);
+ g_return_val_if_fail(dest != NULL, FALSE);
+ g_return_val_if_fail(dest->window != NULL, FALSE);
+ g_return_val_if_fail(dest->target != NULL, FALSE);
- if (strarray_find(array, "*") != -1)
- return TRUE;
+ item = window_item_find_window(dest->window, dest->server, dest->target);
+ if (item == NULL) {
+ return FALSE;
+ }
- if (strarray_find(array, dest->target) != -1)
- return TRUE;
+ server_tag_len = dest->server_tag != NULL ? strlen(dest->server_tag) : 0;
+ for (tmp = array; *tmp != NULL; tmp++) {
+ char *str = *tmp;
+ if (*str == '\0') {
+ continue;
+ }
- if (dest->server_tag != NULL) {
- char *tagtarget = g_strdup_printf("%s/%s", dest->server_tag, "*");
- int ret = strarray_find(array, tagtarget);
- g_free(tagtarget);
- if (ret != -1)
- return TRUE;
+ if (server_tag_len &&
+ g_ascii_strncasecmp(str, dest->server_tag, server_tag_len) == 0 &&
+ str[server_tag_len] == '/') {
+ str += server_tag_len + 1;
+ }
- tagtarget = g_strdup_printf("%s/%s", dest->server_tag, dest->target);
- ret = strarray_find(array, tagtarget);
- g_free(tagtarget);
- if (ret != -1)
+ if (g_strcmp0(str, "") == 0 || g_strcmp0(str, "::all") == 0) {
return TRUE;
+ } else if (g_ascii_strcasecmp(str, dest->target) == 0) {
+ return TRUE;
+ } else if (item->type == query_type &&
+ g_strcmp0(str, dest->target[0] == '=' ? "::dccqueries" :
+ "::queries") == 0) {
+ return TRUE;
+ } else if (item->type == channel_type &&
+ g_strcmp0(str, "::channels") == 0) {
+ return TRUE;
+ }
}
+
return FALSE;
}
diff --git a/src/fe-common/core/fe-exec.c b/src/fe-common/core/fe-exec.c
index 36990866..c1739d39 100644
--- a/src/fe-common/core/fe-exec.c
+++ b/src/fe-common/core/fe-exec.c
@@ -613,7 +613,7 @@ static void sig_exec_input(PROCESS_REC *rec, const char *text)
str = g_strconcat(rec->target_nick ? "-nick " :
rec->target_channel ? "-channel " : "",
- rec->target, " ", text, NULL);
+ rec->target, " ", *text == '\0' ? " " : text, NULL);
signal_emit(rec->notice ? "command notice" : "command msg",
3, str, server, item);
g_free(str);
diff --git a/src/fe-common/core/fe-server.c b/src/fe-common/core/fe-server.c
index 810afe83..074a83f3 100644
--- a/src/fe-common/core/fe-server.c
+++ b/src/fe-common/core/fe-server.c
@@ -136,9 +136,9 @@ static void cmd_server_add_modify(const char *data, gboolean add)
if (rec == NULL) {
if (add == FALSE) {
- cmd_params_free(free_arg);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
TXT_SETUPSERVER_NOT_FOUND, addr, port);
+ cmd_params_free(free_arg);
return;
}
diff --git a/src/fe-common/core/fe-settings.c b/src/fe-common/core/fe-settings.c
index abbd45a8..de9f67a1 100644
--- a/src/fe-common/core/fe-settings.c
+++ b/src/fe-common/core/fe-settings.c
@@ -26,7 +26,7 @@
#include "misc.h"
#include "lib-config/iconfig.h"
#include "settings.h"
-
+#include "fe-settings.h"
#include "levels.h"
#include "printtext.h"
#include "keyboard.h"
@@ -41,6 +41,11 @@ static void set_print(SETTINGS_REC *rec)
g_free(value);
}
+void fe_settings_set_print(const char *key)
+{
+ set_print(settings_get_record(key));
+}
+
static void set_print_pattern(const char *pattern)
{
GSList *sets, *tmp;
diff --git a/src/fe-common/core/fe-settings.h b/src/fe-common/core/fe-settings.h
new file mode 100644
index 00000000..dd33f223
--- /dev/null
+++ b/src/fe-common/core/fe-settings.h
@@ -0,0 +1,6 @@
+#ifndef __FE_CHANNELS_H
+#define __FE_CHANNELS_H
+
+void fe_settings_set_print(const char *key);
+
+#endif
diff --git a/src/fe-common/core/fe-windows.c b/src/fe-common/core/fe-windows.c
index 0afa2914..93f2e3f3 100644
--- a/src/fe-common/core/fe-windows.c
+++ b/src/fe-common/core/fe-windows.c
@@ -563,8 +563,10 @@ GSList *windows_get_sorted(void)
begin = windows_seq_begin();
while (iter != begin) {
+ WINDOW_REC *rec;
+
iter = g_sequence_iter_prev(iter);
- WINDOW_REC *rec = g_sequence_get(iter);
+ rec = g_sequence_get(iter);
sorted = g_slist_prepend(sorted, rec);
}
diff --git a/src/fe-common/core/fe-windows.h b/src/fe-common/core/fe-windows.h
index 32d6cfcd..aaa773c8 100644
--- a/src/fe-common/core/fe-windows.h
+++ b/src/fe-common/core/fe-windows.h
@@ -11,6 +11,14 @@ enum {
DATA_LEVEL_HILIGHT
};
+enum {
+ MAIN_WINDOW_TYPE_NONE = -1,
+ MAIN_WINDOW_TYPE_DEFAULT = 0,
+ MAIN_WINDOW_TYPE_HIDDEN = 1,
+ MAIN_WINDOW_TYPE_SPLIT = 2,
+ MAIN_WINDOW_TYPE_RSPLIT = 3
+};
+
typedef struct {
char *servertag;
char *name;
diff --git a/src/fe-common/core/formats.c b/src/fe-common/core/formats.c
index 005e6fb7..4c819c2d 100644
--- a/src/fe-common/core/formats.c
+++ b/src/fe-common/core/formats.c
@@ -480,27 +480,30 @@ int format_real_length(const char *str, int len)
start = str;
tmp = g_string_new(NULL);
- while (*str != '\0' && len > 0) {
+ while (*str != '\0') {
+ oldstr = str;
if (*str == '%' && str[1] != '\0') {
str++;
if (*str != '%') {
adv = format_expand_styles(tmp, &str, NULL);
- str += adv;
- if (adv)
- continue;
- }
-
- /* %% or unknown %code, written as-is */
- if (*str != '%') {
- if (--len == 0)
- break;
+ if (adv) {
+ str += adv;
+ continue;
+ }
+ /* discount for unknown % */
+ if (--len < 0) {
+ str = oldstr;
+ break;
+ }
+ oldstr = str;
}
}
- oldstr = str;
len -= string_advance(&str, utf8);
- if (len < 0)
+ if (len < 0) {
str = oldstr;
+ break;
+ }
}
g_string_free(tmp, TRUE);
@@ -1072,31 +1075,27 @@ static void get_mirc_color(const char **str, int *fg_ret, int *bg_ret)
fg = fg_ret == NULL ? -1 : *fg_ret;
bg = bg_ret == NULL ? -1 : *bg_ret;
- if (!i_isdigit(**str) && **str != ',') {
+ if (!i_isdigit(**str)) {
+ /* turn off color */
fg = -1;
bg = -1;
} else {
/* foreground color */
- if (**str != ',') {
- fg = **str-'0';
+ fg = **str-'0';
+ (*str)++;
+ if (i_isdigit(**str)) {
+ fg = fg*10 + (**str-'0');
(*str)++;
- if (i_isdigit(**str)) {
- fg = fg*10 + (**str-'0');
- (*str)++;
- }
}
- if (**str == ',') {
+
+ if ((*str)[0] == ',' && i_isdigit((*str)[1])) {
/* background color */
- if (!i_isdigit((*str)[1]))
- bg = -1;
- else {
- (*str)++;
- bg = **str-'0';
+ (*str)++;
+ bg = **str-'0';
+ (*str)++;
+ if (i_isdigit(**str)) {
+ bg = bg*10 + (**str-'0');
(*str)++;
- if (i_isdigit(**str)) {
- bg = bg*10 + (**str-'0');
- (*str)++;
- }
}
}
}
diff --git a/src/fe-common/core/hilight-text.c b/src/fe-common/core/hilight-text.c
index 62e6f0de..b9912457 100644
--- a/src/fe-common/core/hilight-text.c
+++ b/src/fe-common/core/hilight-text.c
@@ -106,6 +106,7 @@ static void hilight_destroy(HILIGHT_REC *rec)
if (rec->channels != NULL) g_strfreev(rec->channels);
g_free_not_null(rec->color);
g_free_not_null(rec->act_color);
+ g_free_not_null(rec->servertag);
g_free(rec->text);
g_free(rec);
}
@@ -424,7 +425,7 @@ static void read_hilight_config(void)
CONFIG_NODE *node;
HILIGHT_REC *rec;
GSList *tmp;
- char *text, *color;
+ char *text, *color, *servertag;
hilights_destroy_all();
@@ -467,7 +468,9 @@ static void read_hilight_config(void)
rec->nickmask = config_node_get_bool(node, "mask", FALSE);
rec->fullword = config_node_get_bool(node, "fullword", FALSE);
rec->regexp = config_node_get_bool(node, "regexp", FALSE);
- rec->servertag = config_node_get_str(node, "servertag", NULL);
+ servertag = config_node_get_str(node, "servertag", NULL);
+ rec->servertag = servertag == NULL || *servertag == '\0' ? NULL :
+ g_strdup(servertag);
hilight_init_rec(rec);
node = iconfig_node_section(node, "channels", -1);
diff --git a/src/fe-common/core/window-commands.c b/src/fe-common/core/window-commands.c
index 57c81ac2..a81c0180 100644
--- a/src/fe-common/core/window-commands.c
+++ b/src/fe-common/core/window-commands.c
@@ -169,7 +169,7 @@ static void cmd_window(const char *data, void *server, WI_ITEM_REC *item)
command_runsub("window", data, server, item);
}
-/* SYNTAX: WINDOW NEW [HIDDEN|SPLIT] */
+/* SYNTAX: WINDOW NEW [HIDDEN|SPLIT|RSPLIT] */
static void cmd_window_new(const char *data, void *server, WI_ITEM_REC *item)
{
WINDOW_REC *window;
@@ -177,8 +177,9 @@ static void cmd_window_new(const char *data, void *server, WI_ITEM_REC *item)
g_return_if_fail(data != NULL);
- type = (g_ascii_strncasecmp(data, "hid", 3) == 0 || g_ascii_strcasecmp(data, "tab") == 0) ? 1 :
- (g_ascii_strcasecmp(data, "split") == 0 ? 2 : 0);
+ type = (g_ascii_strncasecmp(data, "hid", 3) == 0 || g_ascii_strcasecmp(data, "tab") == 0) ? MAIN_WINDOW_TYPE_HIDDEN :
+ g_ascii_strcasecmp(data, "split") == 0 ? MAIN_WINDOW_TYPE_SPLIT :
+ g_ascii_strncasecmp(data, "rs", 2) == 0 ? MAIN_WINDOW_TYPE_RSPLIT : MAIN_WINDOW_TYPE_DEFAULT;
signal_emit("gui window create override", 1, GINT_TO_POINTER(type));
window = window_create(NULL, FALSE);
diff --git a/src/fe-common/core/window-items.c b/src/fe-common/core/window-items.c
index bd6ae5e9..8eab7124 100644
--- a/src/fe-common/core/window-items.c
+++ b/src/fe-common/core/window-items.c
@@ -314,7 +314,7 @@ void window_item_create(WI_ITEM_REC *item, int automatic)
/* create new window to use */
if (settings_get_bool("autocreate_split_windows")) {
signal_emit("gui window create override", 1,
- GINT_TO_POINTER(0));
+ GINT_TO_POINTER(MAIN_WINDOW_TYPE_SPLIT));
}
window = window_create(item, automatic);
} else {
diff --git a/src/fe-common/irc/fe-ircnet.c b/src/fe-common/irc/fe-ircnet.c
index 8f1d2efd..5ae5ac05 100644
--- a/src/fe-common/irc/fe-ircnet.c
+++ b/src/fe-common/irc/fe-ircnet.c
@@ -106,9 +106,9 @@ static void cmd_network_add_modify(const char *data, gboolean add)
rec = ircnet_find(name);
if (rec == NULL) {
if (add == FALSE) {
- cmd_params_free(free_arg);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
IRCTXT_NETWORK_NOT_FOUND, name);
+ cmd_params_free(free_arg);
return;
}
diff --git a/src/fe-common/irc/fe-netjoin.c b/src/fe-common/irc/fe-netjoin.c
index 8272093f..bc39b27c 100644
--- a/src/fe-common/irc/fe-netjoin.c
+++ b/src/fe-common/irc/fe-netjoin.c
@@ -253,15 +253,12 @@ static void sig_print_starting(TEXT_DEST_REC *dest)
if (!IS_IRC_SERVER(dest->server))
return;
- if (!(dest->level & MSGLEVEL_PUBLIC))
- return;
-
if (!server_ischannel(dest->server, dest->target))
return;
rec = netjoin_find_server(IRC_SERVER(dest->server));
if (rec != NULL && rec->netjoins != NULL)
- print_netjoins(rec, dest->target);
+ print_netjoins(rec, NULL);
}
static int sig_check_netjoins(void)
diff --git a/src/fe-common/irc/fe-netsplit.c b/src/fe-common/irc/fe-netsplit.c
index 4c69dd10..ac3330e5 100644
--- a/src/fe-common/irc/fe-netsplit.c
+++ b/src/fe-common/irc/fe-netsplit.c
@@ -199,7 +199,7 @@ static void temp_split_chan_free(TEMP_SPLIT_CHAN_REC *rec)
g_free(rec);
}
-static void print_splits(IRC_SERVER_REC *server, const char *channel)
+static void print_splits(IRC_SERVER_REC *server, const char *filter_channel)
{
TEMP_SPLIT_REC temp;
GSList *servers;
@@ -218,7 +218,7 @@ static void print_splits(IRC_SERVER_REC *server, const char *channel)
g_hash_table_foreach(server->splits,
(GHFunc) get_server_splits, &temp);
- print_server_splits(server, &temp, channel);
+ print_server_splits(server, &temp, filter_channel);
g_slist_foreach(temp.channels,
(GFunc) temp_split_chan_free, NULL);
@@ -255,15 +255,12 @@ static void sig_print_starting(TEXT_DEST_REC *dest)
if (!IS_IRC_SERVER(dest->server))
return;
- if (!(dest->level & MSGLEVEL_PUBLIC))
- return;
-
if (!server_ischannel(dest->server, dest->target))
return;
rec = IRC_SERVER(dest->server);
if (rec->split_servers != NULL)
- print_splits(rec, dest->target);
+ print_splits(rec, NULL);
}
static int sig_check_splits(void)
diff --git a/src/fe-fuzz/irssi.c b/src/fe-fuzz/irssi.c
index 77892aaf..c1b2ca9b 100644
--- a/src/fe-fuzz/irssi.c
+++ b/src/fe-fuzz/irssi.c
@@ -21,7 +21,7 @@
#include "module.h"
#include "modules-load.h"
#include "levels.h"
-#include "../fe-text/module-formats.h" // need to explicitly grab from fe-text
+#include "../fe-text/module-formats.h" /* need to explicitly grab from fe-text */
#include "themes.h"
#include "core.h"
#include "fe-common-core.h"
diff --git a/src/fe-text/gui-printtext.c b/src/fe-text/gui-printtext.c
index a07451fa..c52f9ced 100644
--- a/src/fe-text/gui-printtext.c
+++ b/src/fe-text/gui-printtext.c
@@ -24,6 +24,7 @@
#include "formats.h"
#include "printtext.h"
+#include "themes.h"
#include "term.h"
#include "gui-printtext.h"
@@ -138,6 +139,39 @@ void gui_printtext_after(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str)
gui_printtext_after_time(dest, prev, str, 0);
}
+void gui_printtext_window_border(int x, int y)
+{
+ char *v0, *v1;
+ int len;
+ if (current_theme != NULL) {
+ v1 = theme_format_expand(current_theme, "{window_border} ");
+ len = format_real_length(v1, 1);
+ v1[len] = '\0';
+ }
+ else {
+ v1 = g_strdup(" ");
+ }
+
+ if (*v1 == '\0') {
+ g_free(v1);
+ v1 = g_strdup(" ");
+ }
+
+ if (clrtoeol_info->color != NULL) {
+ char *color = g_strdup(clrtoeol_info->color);
+ len = format_real_length(color, 0);
+ color[len] = '\0';
+ v0 = g_strconcat(color, v1, NULL);
+ g_free(color);
+ g_free(v1);
+ } else {
+ v0 = v1;
+ }
+
+ gui_printtext(x, y, v0);
+ g_free(v0);
+}
+
static void remove_old_lines(TEXT_BUFFER_VIEW_REC *view)
{
LINE_REC *line;
@@ -236,8 +270,13 @@ static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor,
term_set_color2(root_window, attr, fg, bg);
term_move(root_window, next_xpos, next_ypos);
- if (flags & GUI_PRINT_FLAG_CLRTOEOL)
- term_clrtoeol(root_window);
+ if (flags & GUI_PRINT_FLAG_CLRTOEOL) {
+ if (clrtoeol_info->window != NULL) {
+ term_window_clrtoeol_abs(clrtoeol_info->window, next_ypos);
+ } else {
+ term_clrtoeol(root_window);
+ }
+ }
next_xpos += term_addstr(root_window, str);
return;
}
diff --git a/src/fe-text/gui-printtext.h b/src/fe-text/gui-printtext.h
index d2671497..64595bbe 100644
--- a/src/fe-text/gui-printtext.h
+++ b/src/fe-text/gui-printtext.h
@@ -20,5 +20,6 @@ void gui_printtext(int xpos, int ypos, const char *str);
void gui_printtext_internal(int xpos, int ypos, const char *str);
void gui_printtext_after(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str);
void gui_printtext_after_time(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str, time_t time);
+void gui_printtext_window_border(int xpos, int ypos);
#endif
diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c
index 3688f15e..b3a78396 100644
--- a/src/fe-text/gui-readline.c
+++ b/src/fe-text/gui-readline.c
@@ -530,6 +530,39 @@ static void key_forward_history(void)
g_free(line);
}
+static void key_backward_global_history(void)
+{
+ const char *text;
+ char *line;
+
+ line = gui_entry_get_text(active_entry);
+ text = command_global_history_prev(active_win, line);
+ gui_entry_set_text(active_entry, text);
+ g_free(line);
+}
+
+static void key_forward_global_history(void)
+{
+ const char *text;
+ char *line;
+
+ line = gui_entry_get_text(active_entry);
+ text = command_global_history_next(active_win, line);
+ gui_entry_set_text(active_entry, text);
+ g_free(line);
+}
+
+static void key_erase_history_entry(void)
+{
+ const char *text;
+ char *line;
+
+ line = gui_entry_get_text(active_entry);
+ text = command_history_delete_current(active_win, line);
+ gui_entry_set_text(active_entry, text);
+ g_free(line);
+}
+
static void key_beginning_of_line(void)
{
gui_entry_set_pos(active_entry, 0);
@@ -1176,6 +1209,8 @@ void gui_readline_init(void)
key_bind("key", NULL, "meta2-5C", "cright", (SIGNAL_FUNC) key_combo);
key_bind("key", NULL, "meta2-1;5D", "cleft", (SIGNAL_FUNC) key_combo);
key_bind("key", NULL, "meta2-1;5C", "cright", (SIGNAL_FUNC) key_combo);
+ key_bind("key", NULL, "meta2-1;5A", "cup", (SIGNAL_FUNC) key_combo);
+ key_bind("key", NULL, "meta2-1;5B", "cdown", (SIGNAL_FUNC) key_combo);
key_bind("key", NULL, "meta2-1;3A", "mup", (SIGNAL_FUNC) key_combo);
key_bind("key", NULL, "meta2-1;3B", "mdown", (SIGNAL_FUNC) key_combo);
@@ -1217,6 +1252,9 @@ void gui_readline_init(void)
/* history */
key_bind("backward_history", "Go back one line in the history", "up", NULL, (SIGNAL_FUNC) key_backward_history);
key_bind("forward_history", "Go forward one line in the history", "down", NULL, (SIGNAL_FUNC) key_forward_history);
+ key_bind("backward_global_history", "Go back one line in the global history", "cup", NULL, (SIGNAL_FUNC) key_backward_global_history);
+ key_bind("forward_global_history", "Go forward one line in the global history", "cdown", NULL, (SIGNAL_FUNC) key_forward_global_history);
+ key_bind("erase_history_entry", "Erase the currently active entry from the history", NULL, NULL, (SIGNAL_FUNC) key_erase_history_entry);
/* line editing */
key_bind("backspace", "Delete the previous character", "backspace", NULL, (SIGNAL_FUNC) key_backspace);
@@ -1310,6 +1348,9 @@ void gui_readline_deinit(void)
key_unbind("backward_history", (SIGNAL_FUNC) key_backward_history);
key_unbind("forward_history", (SIGNAL_FUNC) key_forward_history);
+ key_unbind("backward_global_history", (SIGNAL_FUNC) key_backward_global_history);
+ key_unbind("forward_global_history", (SIGNAL_FUNC) key_forward_global_history);
+ key_unbind("erase_history_entry", (SIGNAL_FUNC) key_erase_history_entry);
key_unbind("backspace", (SIGNAL_FUNC) key_backspace);
key_unbind("delete_character", (SIGNAL_FUNC) key_delete_character);
diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c
index c63c495c..3efb9803 100644
--- a/src/fe-text/gui-windows.c
+++ b/src/fe-text/gui-windows.c
@@ -23,6 +23,7 @@
#include "misc.h"
#include "settings.h"
#include "special-vars.h"
+#include "levels.h"
#include "term.h"
#include "gui-entry.h"
@@ -50,6 +51,7 @@ static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window,
!settings_get_bool("indent_always"),
get_default_indent_func());
textbuffer_view_set_break_wide(gui->view, settings_get_bool("break_wide"));
+ textbuffer_view_set_hidden_level(gui->view, MSGLEVEL_HIDDEN);
if (parent->active == window)
textbuffer_view_set_window(gui->view, parent->screen_win);
return gui;
@@ -73,17 +75,18 @@ static void gui_window_created(WINDOW_REC *window, void *automatic)
g_return_if_fail(window != NULL);
- new_parent = window_create_override == 0 ||
- window_create_override == 2 ||
+ new_parent = window_create_override == MAIN_WINDOW_TYPE_DEFAULT ||
+ window_create_override == MAIN_WINDOW_TYPE_SPLIT ||
+ window_create_override == MAIN_WINDOW_TYPE_RSPLIT ||
active_win == NULL || WINDOW_GUI(active_win) == NULL;
- parent = !new_parent ? WINDOW_MAIN(active_win) : mainwindow_create();
+ parent = !new_parent ? WINDOW_MAIN(active_win) : mainwindow_create(window_create_override == MAIN_WINDOW_TYPE_RSPLIT);
if (parent == NULL) {
/* not enough space for new window, but we really can't
abort creation of the window anymore, so create hidden
window instead. */
parent = WINDOW_MAIN(active_win);
}
- window_create_override = -1;
+ window_create_override = MAIN_WINDOW_TYPE_NONE;
if (parent->active == NULL) parent->active = window;
window->gui_data = gui_window_init(window, parent);
@@ -204,6 +207,8 @@ void gui_windows_reset_settings(void)
WINDOW_REC *rec = tmp->data;
GUI_WINDOW_REC *gui = WINDOW_GUI(rec);
+ textbuffer_view_set_hidden_level(gui->view, MSGLEVEL_HIDDEN);
+
textbuffer_view_set_break_wide(gui->view, settings_get_bool("break_wide"));
textbuffer_view_set_default_indent(gui->view,
@@ -281,13 +286,14 @@ static void read_settings(void)
void gui_windows_init(void)
{
- settings_add_bool("lookandfeel", "autostick_split_windows", TRUE);
+ settings_add_bool("lookandfeel", "autostick_split_windows", FALSE);
+ settings_add_bool("lookandfeel", "autounstick_windows", TRUE);
settings_add_int("lookandfeel", "indent", 10);
settings_add_bool("lookandfeel", "indent_always", FALSE);
settings_add_bool("lookandfeel", "break_wide", FALSE);
settings_add_bool("lookandfeel", "scroll", TRUE);
- window_create_override = -1;
+ window_create_override = MAIN_WINDOW_TYPE_NONE;
read_settings();
signal_add("gui window create override", (SIGNAL_FUNC) sig_window_create_override);
diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c
index b5df47c9..0288e4f1 100644
--- a/src/fe-text/irssi.c
+++ b/src/fe-text/irssi.c
@@ -31,6 +31,7 @@
#include "printtext.h"
#include "fe-common-core.h"
+#include "fe-settings.h"
#include "themes.h"
#include "term.h"
@@ -79,25 +80,8 @@ static int dirty, full_redraw;
static GMainLoop *main_loop;
int quitting;
-static const char *banner_text =
- " ___ _\n"
- "|_ _|_ _ _____(_)\n"
- " | || '_(_-<_-< |\n"
- "|___|_| /__/__/_|\n"
- "Irssi v" PACKAGE_VERSION " - http://www.irssi.org";
-
-static const char *firsttimer_text =
- "- - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"
- "Hi there! If this is your first time using Irssi, you\n"
- "might want to go to our website and read the startup\n"
- "documentation to get you going.\n\n"
- "Our community and staff are available to assist you or\n"
- "to answer any questions you may have.\n\n"
- "Use the /HELP command to get detailed information about\n"
- "the available commands.\n"
- "- - - - - - - - - - - - - - - - - - - - - - - - - - - -";
-
static int display_firsttimer = FALSE;
+static unsigned int user_settings_changed = 0;
static void sig_exit(void)
@@ -105,6 +89,11 @@ static void sig_exit(void)
quitting = TRUE;
}
+static void sig_settings_userinfo_changed(gpointer changedp)
+{
+ user_settings_changed = GPOINTER_TO_UINT(changedp);
+}
+
/* redraw irssi's screen.. */
void irssi_redraw(void)
{
@@ -161,6 +150,7 @@ static void textui_init(void)
fe_common_irc_init();
theme_register(gui_text_formats);
+ signal_add("settings userinfo changed", (SIGNAL_FUNC) sig_settings_userinfo_changed);
signal_add_last("gui exit", (SIGNAL_FUNC) sig_exit);
}
@@ -199,14 +189,26 @@ static void textui_finish_init(void)
statusbar_redraw(NULL, TRUE);
if (servers == NULL && lookup_servers == NULL) {
- printtext(NULL, NULL, MSGLEVEL_CRAP|MSGLEVEL_NO_ACT,
- "%s", banner_text);
+ printformat(NULL, NULL, MSGLEVEL_CRAP|MSGLEVEL_NO_ACT, TXT_IRSSI_BANNER);
}
if (display_firsttimer) {
- printtext(NULL, NULL, MSGLEVEL_CRAP|MSGLEVEL_NO_ACT,
- "%s", firsttimer_text);
+ printformat(NULL, NULL, MSGLEVEL_CRAP|MSGLEVEL_NO_ACT, TXT_WELCOME_FIRSTTIME);
}
+
+ /* see irc-servers-setup.c:init_userinfo */
+ if (user_settings_changed)
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_WELCOME_INIT_SETTINGS);
+ if (user_settings_changed & USER_SETTINGS_REAL_NAME)
+ fe_settings_set_print("real_name");
+ if (user_settings_changed & USER_SETTINGS_USER_NAME)
+ fe_settings_set_print("user_name");
+ if (user_settings_changed & USER_SETTINGS_NICK)
+ fe_settings_set_print("nick");
+ if (user_settings_changed & USER_SETTINGS_HOSTNAME)
+ fe_settings_set_print("hostname");
+
+ term_environment_check();
}
static void textui_deinit(void)
@@ -222,7 +224,8 @@ static void textui_deinit(void)
fe_perl_deinit();
#endif
- dirty_check(); /* one last time to print any quit messages */
+ dirty_check(); /* one last time to print any quit messages */
+ signal_remove("settings userinfo changed", (SIGNAL_FUNC) sig_settings_userinfo_changed);
signal_remove("gui exit", (SIGNAL_FUNC) sig_exit);
lastlog_deinit();
@@ -259,12 +262,11 @@ static void check_files(void)
}
}
-
int main(int argc, char **argv)
{
static int version = 0;
static GOptionEntry options[] = {
- { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Display irssi version", NULL },
+ { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Display Irssi version", NULL },
{ NULL }
};
int loglev;
diff --git a/src/fe-text/mainwindows-layout.c b/src/fe-text/mainwindows-layout.c
index fae02539..17c6647b 100644
--- a/src/fe-text/mainwindows-layout.c
+++ b/src/fe-text/mainwindows-layout.c
@@ -23,6 +23,7 @@
#include "misc.h"
#include "lib-config/iconfig.h"
#include "settings.h"
+#include "levels.h"
#include "mainwindows.h"
#include "gui-windows.h"
@@ -41,6 +42,12 @@ static void sig_layout_window_save(WINDOW_REC *window, CONFIG_NODE *node)
iconfig_node_set_int(node, "parent", active->refnum);
}
+ if (gui->view->hidden_level != MSGLEVEL_HIDDEN) {
+ char *level = bits2level(gui->view->hidden_level);
+ iconfig_node_set_str(node, "hidelevel", level);
+ g_free(level);
+ }
+
if (gui->use_scroll)
iconfig_node_set_bool(node, "scroll", gui->scroll);
}
@@ -48,9 +55,9 @@ static void sig_layout_window_save(WINDOW_REC *window, CONFIG_NODE *node)
static void sig_layout_window_restore(WINDOW_REC *window, CONFIG_NODE *node)
{
WINDOW_REC *parent;
- GUI_WINDOW_REC *gui;
+ GUI_WINDOW_REC *gui;
- gui = WINDOW_GUI(window);
+ gui = WINDOW_GUI(window);
parent = window_find_refnum(config_node_get_int(node, "parent", -1));
if (parent != NULL)
@@ -58,10 +65,13 @@ static void sig_layout_window_restore(WINDOW_REC *window, CONFIG_NODE *node)
if (config_node_get_bool(node, "sticky", FALSE))
gui_window_set_sticky(window);
+
+ textbuffer_view_set_hidden_level(gui->view, level2bits(config_node_get_str(node, "hidelevel", "HIDDEN"), NULL));
+
if (config_node_get_str(node, "scroll", NULL) != NULL) {
gui->use_scroll = TRUE;
gui->scroll = config_node_get_bool(node, "scroll", TRUE);
- textbuffer_view_set_scroll(gui->view, gui->scroll);
+ textbuffer_view_set_scroll(gui->view, gui->scroll);
}
}
@@ -74,6 +84,8 @@ static void main_window_save(MAIN_WINDOW_REC *window, CONFIG_NODE *node)
iconfig_node_set_int(node, "first_line", window->first_line);
iconfig_node_set_int(node, "lines", window->height);
+ iconfig_node_set_int(node, "first_column", window->first_column);
+ iconfig_node_set_int(node, "columns", window->width);
}
static void sig_layout_save(void)
@@ -88,8 +100,16 @@ static void sig_layout_save(void)
static int window_node_cmp(CONFIG_NODE *n1, CONFIG_NODE *n2)
{
- return config_node_get_int(n1, "first_line", 0) >
- config_node_get_int(n2, "first_line", 0) ? -1 : 1;
+ return (config_node_get_int(n1, "first_line", 0) ==
+ config_node_get_int(n2, "first_line", 0)
+ &&
+ config_node_get_int(n1, "first_column", 0) >
+ config_node_get_int(n2, "first_column", 0)
+ ) ||
+ config_node_get_int(n1, "first_line", 0) >
+ config_node_get_int(n2, "first_line", 0)
+ ? -1
+ : 1;
}
/* Returns list of mainwindow nodes sorted by first_line
@@ -108,14 +128,45 @@ static GSList *get_sorted_windows_config(CONFIG_NODE *node)
return output;
}
+static GSList *get_windows_config_filter_line(GSList *in)
+{
+ GSList *tmp, *output;
+
+ output = NULL;
+ for (tmp = in; tmp != NULL; tmp = tmp->next) {
+ CONFIG_NODE *node = tmp->data;
+ if (config_node_get_int(node, "first_column", 0) == 0)
+ output = g_slist_append(output, node);
+ }
+
+ return output;
+}
+
+static GSList *get_windows_config_filter_column(GSList *in, int first_line, int last_line)
+{
+ GSList *tmp, *output;
+
+ output = NULL;
+ for (tmp = in; tmp != NULL; tmp = tmp->next) {
+ int l1, l2;
+ CONFIG_NODE *node = tmp->data;
+ l1 = config_node_get_int(node, "first_line", -1);
+ l2 = l1 + config_node_get_int(node, "lines", 0) - 1;
+ if (l1 >= first_line && l2 <= last_line)
+ output = g_slist_prepend(output, node);
+ }
+
+ return output;
+}
+
static void sig_layout_restore(void)
{
- MAIN_WINDOW_REC *lower_window;
- WINDOW_REC *window;
+ MAIN_WINDOW_REC *lower_window;
+ WINDOW_REC *window, *first;
CONFIG_NODE *node;
- GSList *tmp, *sorted_config;
- int avail_height, height, *heights;
- int i, lower_size, windows_count, diff;
+ GSList *tmp, *sorted_config, *lines_config;
+ int avail_height, height, *heights, *widths, max_wins_line;
+ int i, lower_size, lines_count, columns_count, diff;
node = iconfig_node_traverse("mainwindows", FALSE);
if (node == NULL) return;
@@ -123,51 +174,56 @@ static void sig_layout_restore(void)
sorted_config = get_sorted_windows_config(node);
if (sorted_config == NULL) return;
- windows_count = g_slist_length(sorted_config);
+ lines_config = get_windows_config_filter_line(sorted_config);
+ lines_count = g_slist_length(lines_config);
- /* calculate the saved terminal height */
+ /* calculate the saved terminal height */
avail_height = term_height -
screen_reserved_top - screen_reserved_bottom;
height = 0;
- heights = g_new0(int, windows_count);
- for (i = 0, tmp = sorted_config; tmp != NULL; tmp = tmp->next, i++) {
+ heights = g_new0(int, lines_count);
+ for (i = 0, tmp = lines_config; tmp != NULL; tmp = tmp->next, i++) {
CONFIG_NODE *node = tmp->data;
- heights[i] = config_node_get_int(node, "lines", 0);
+ heights[i] = config_node_get_int(node, "lines", 0);
height += heights[i];
}
+ max_wins_line = (term_width + 1) / (NEW_WINDOW_WIDTH + 1);
+ if (max_wins_line < 1)
+ max_wins_line = 1;
+
if (avail_height <= (WINDOW_MIN_SIZE*2)+1) {
/* we can fit only one window to screen -
give it all the height we can */
- windows_count = 1;
- heights[0] = avail_height;
+ lines_count = 1;
+ heights[0] = avail_height;
} else if (height != avail_height) {
/* Terminal's height is different from the saved one.
Resize the windows so they fit to screen. */
while (height > avail_height &&
- windows_count*(WINDOW_MIN_SIZE+1) > avail_height) {
+ lines_count*(WINDOW_MIN_SIZE+1) > avail_height) {
/* all windows can't fit into screen,
remove the lowest ones */
- windows_count--;
+ lines_count--;
}
- /* try to keep the windows' size about the same in percents */
- for (i = 0; i < windows_count; i++) {
+ /* try to keep the windows' size about the same in percents */
+ for (i = 0; i < lines_count; i++) {
int size = avail_height*heights[i]/height;
if (size < WINDOW_MIN_SIZE+1)
- size = WINDOW_MIN_SIZE+1;
+ size = WINDOW_MIN_SIZE+1;
heights[i] = size;
}
/* give/remove the last bits */
- height = 0;
- for (i = 0; i < windows_count; i++)
- height += heights[i];
+ height = 0;
+ for (i = 0; i < lines_count; i++)
+ height += heights[i];
diff = height < avail_height ? 1 : -1;
for (i = 0; height != avail_height; i++) {
- if (i == windows_count)
+ if (i == lines_count)
i = 0;
if (heights[i] > WINDOW_MIN_SIZE+1) {
@@ -178,25 +234,59 @@ static void sig_layout_restore(void)
}
/* create all the visible windows with correct size */
- lower_window = NULL; lower_size = 0;
- for (i = 0, tmp = sorted_config; i < windows_count; tmp = tmp->next, i++) {
+ lower_window = NULL; lower_size = 0; first = NULL;
+ for (i = 0, tmp = lines_config; i < lines_count; tmp = tmp->next, i++) {
+ GSList *tmp2, *columns_config, *line;
+ int j, l1, l2;
CONFIG_NODE *node = tmp->data;
if (node->key == NULL) continue;
- /* create a new window + mainwindow */
- signal_emit("gui window create override", 1,
- GINT_TO_POINTER(0));
+ l1 = config_node_get_int(node, "first_line", -1);
+ l2 = l1 + config_node_get_int(node, "lines", 0) - 1;
+ columns_config = get_windows_config_filter_column(sorted_config, l1, l2);
+
+ window = NULL; columns_count = 0;
+ widths = g_new0(int, max_wins_line);
+ for (j = 0, tmp2 = columns_config; j < max_wins_line && tmp2 != NULL; tmp2 = tmp2->next, j++) {
+ int width;
+ WINDOW_REC *new_win;
+ CONFIG_NODE *node2 = tmp2->data;
+ if (node2->key == NULL) continue;
+
+ /* create a new window + mainwindow */
+ signal_emit("gui window create override", 1,
+ GINT_TO_POINTER(window == NULL ? MAIN_WINDOW_TYPE_SPLIT : MAIN_WINDOW_TYPE_RSPLIT));
- window = window_create(NULL, TRUE);
- window_set_refnum(window, atoi(node->key));
+ new_win = window_create(NULL, TRUE);
+
+ window_set_refnum(new_win, atoi(node2->key));
+ width = config_node_get_int(node2, "columns", NEW_WINDOW_WIDTH);
+ widths[j] = width;
+ columns_count += width + (window == NULL ? 0 : 1);
+
+ if (window == NULL)
+ window = new_win;
+ if (first == NULL)
+ first = new_win;
+
+ window_set_active(new_win);
+ active_mainwin = WINDOW_MAIN(new_win);
+ }
+ if (window == NULL)
+ continue;
+ line = g_slist_reverse(mainwindows_get_line(WINDOW_MAIN(window)));
+ for (j = g_slist_length(line), tmp2 = line; tmp2 != NULL; tmp2 = tmp2->next, j--) {
+ int width = MAX(NEW_WINDOW_WIDTH, widths[j-1] * term_width / columns_count);
+ MAIN_WINDOW_REC *rec = tmp2->data;
+ mainwindow_set_rsize(rec, width);
+ }
+ g_slist_free(line);
+ g_free(widths);
if (lower_size > 0)
mainwindow_set_size(lower_window, lower_size, FALSE);
- window_set_active(window);
- active_mainwin = WINDOW_MAIN(window);
-
- lower_window = WINDOW_MAIN(window);
+ lower_window = WINDOW_MAIN(window);
lower_size = heights[i];
if (lower_size < WINDOW_MIN_SIZE+1)
lower_size = WINDOW_MIN_SIZE+1;
@@ -206,6 +296,11 @@ static void sig_layout_restore(void)
if (lower_size > 0)
mainwindow_set_size(lower_window, lower_size, FALSE);
+
+ if (first != NULL) {
+ window_set_active(first);
+ active_mainwin = WINDOW_MAIN(first);
+ }
}
static void sig_layout_reset(void)
diff --git a/src/fe-text/mainwindows.c b/src/fe-text/mainwindows.c
index 5f58c25f..5f24674f 100644
--- a/src/fe-text/mainwindows.c
+++ b/src/fe-text/mainwindows.c
@@ -34,24 +34,27 @@
GSList *mainwindows;
MAIN_WINDOW_REC *active_mainwin;
+MAIN_WINDOW_BORDER_REC *clrtoeol_info;
int screen_reserved_top, screen_reserved_bottom;
-static int old_screen_width, old_screen_height;
+int screen_reserved_left, screen_reserved_right;
+static int screen_width, screen_height;
#define mainwindow_create_screen(window) \
- term_window_create(0, \
+ term_window_create((window)->first_column + (window)->statusbar_columns_left, \
(window)->first_line + (window)->statusbar_lines_top, \
- (window)->width, \
+ (window)->width - (window)->statusbar_columns, \
(window)->height - (window)->statusbar_lines)
#define mainwindow_set_screen_size(window) \
- term_window_move((window)->screen_win, 0, \
+ term_window_move((window)->screen_win, \
+ (window)->first_column + (window)->statusbar_columns_left, \
(window)->first_line + (window)->statusbar_lines_top, \
- (window)->width, \
+ (window)->width - (window)->statusbar_columns, \
(window)->height - (window)->statusbar_lines);
-static MAIN_WINDOW_REC *find_window_with_room(void)
+static MAIN_WINDOW_REC *find_window_with_room()
{
MAIN_WINDOW_REC *biggest_rec;
GSList *tmp;
@@ -71,14 +74,34 @@ static MAIN_WINDOW_REC *find_window_with_room(void)
return biggest_rec;
}
+static MAIN_WINDOW_REC *find_window_with_room_right(void)
+{
+ MAIN_WINDOW_REC *biggest_rec;
+ GSList *tmp;
+ int space, biggest;
+
+ biggest = 0; biggest_rec = NULL;
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ space = MAIN_WINDOW_TEXT_WIDTH(rec);
+ if (space >= 2 * NEW_WINDOW_WIDTH && space > biggest) {
+ biggest = space;
+ biggest_rec = rec;
+ }
+ }
+
+ return biggest_rec;
+}
+
#define window_size_equals(window, mainwin) \
- ((window)->width == (mainwin)->width && \
+ ((window)->width == MAIN_WINDOW_TEXT_WIDTH(mainwin) && \
(window)->height == MAIN_WINDOW_TEXT_HEIGHT(mainwin))
static void mainwindow_resize_windows(MAIN_WINDOW_REC *window)
{
GSList *tmp;
- int resized;
+ int resized;
mainwindow_set_screen_size(window);
@@ -89,24 +112,31 @@ static void mainwindow_resize_windows(MAIN_WINDOW_REC *window)
if (rec->gui_data != NULL &&
WINDOW_GUI(rec)->parent == window &&
!window_size_equals(rec, window)) {
- resized = TRUE;
- gui_window_resize(rec, window->width,
+ resized = TRUE;
+ gui_window_resize(rec, MAIN_WINDOW_TEXT_WIDTH(window),
MAIN_WINDOW_TEXT_HEIGHT(window));
}
}
- if (resized)
+ if (resized)
signal_emit("mainwindow resized", 1, window);
}
static void mainwindow_resize(MAIN_WINDOW_REC *window, int xdiff, int ydiff)
{
+ int height, width;
if (quitting || (xdiff == 0 && ydiff == 0))
- return;
+ return;
- window->width += xdiff;
+ height = window->height + ydiff;
+ width = window->width + xdiff;
+ window->width = window->last_column-window->first_column+1;
window->height = window->last_line-window->first_line+1;
- window->size_dirty = TRUE;
+ if (height != window->height || width != window->width) {
+ g_warning("Resizing window %p W:%d expected:%d H:%d expected:%d",
+ window, window->width, width, window->height, height);
+ }
+ window->size_dirty = TRUE;
}
static GSList *get_sticky_windows_sorted(MAIN_WINDOW_REC *mainwin)
@@ -178,14 +208,13 @@ void mainwindows_recreate(void)
}
}
-MAIN_WINDOW_REC *mainwindow_create(void)
+MAIN_WINDOW_REC *mainwindow_create(int right)
{
MAIN_WINDOW_REC *rec, *parent;
int space;
rec = g_new0(MAIN_WINDOW_REC, 1);
rec->dirty = TRUE;
- rec->width = term_width;
if (mainwindows == NULL) {
active_mainwin = rec;
@@ -193,21 +222,53 @@ MAIN_WINDOW_REC *mainwindow_create(void)
rec->first_line = screen_reserved_top;
rec->last_line = term_height-1 - screen_reserved_bottom;
rec->height = rec->last_line-rec->first_line+1;
+ rec->first_column = screen_reserved_left;
+ rec->last_column = screen_width-1 - screen_reserved_right;
+ rec->width = rec->last_column-rec->first_column+1;
} else {
parent = WINDOW_MAIN(active_win);
- if (MAIN_WINDOW_TEXT_HEIGHT(parent) <
- WINDOW_MIN_SIZE+NEW_WINDOW_SIZE)
- parent = find_window_with_room();
- if (parent == NULL)
- return NULL; /* not enough space */
-
- space = parent->height / 2;
- rec->first_line = parent->first_line;
- rec->last_line = rec->first_line + space;
- rec->height = rec->last_line-rec->first_line+1;
- parent->first_line += space+1;
- mainwindow_resize(parent, 0, -space-1);
+ if (!right) {
+ GSList *tmp, *line;
+ if (MAIN_WINDOW_TEXT_HEIGHT(parent) <
+ WINDOW_MIN_SIZE+NEW_WINDOW_SIZE)
+ parent = find_window_with_room();
+ if (parent == NULL)
+ return NULL; /* not enough space */
+
+ space = parent->height / 2;
+ rec->first_line = parent->first_line;
+ rec->last_line = rec->first_line + space;
+ rec->height = rec->last_line-rec->first_line+1;
+ rec->first_column = screen_reserved_left;
+ rec->last_column = screen_width-1 - screen_reserved_right;
+ rec->width = rec->last_column-rec->first_column+1;
+
+ line = mainwindows_get_line(parent);
+ for (tmp = line; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+ rec->first_line += space+1;
+ mainwindow_resize(rec, 0, -space-1);
+ }
+ g_slist_free(line);
+ } else {
+ if (MAIN_WINDOW_TEXT_WIDTH(parent) <
+ 2* NEW_WINDOW_WIDTH)
+ parent = find_window_with_room_right();
+ if (parent == NULL)
+ return NULL; /* not enough space */
+
+ space = parent->width / 2;
+ rec->first_line = parent->first_line;
+ rec->last_line = parent->last_line;
+ rec->height = parent->height;
+ rec->first_column = parent->last_column - space + 1;
+ rec->last_column = parent->last_column;
+ rec->width = rec->last_column-rec->first_column+1;
+
+ parent->last_column -= space+1;
+ mainwindow_resize(parent, -space-1, 0);
+ }
}
rec->screen_win = mainwindow_create_screen(rec);
@@ -218,16 +279,22 @@ MAIN_WINDOW_REC *mainwindow_create(void)
return rec;
}
-static MAIN_WINDOW_REC *mainwindows_find_lower(int line)
+static MAIN_WINDOW_REC *mainwindows_find_lower(MAIN_WINDOW_REC *window)
{
+ int last_line;
MAIN_WINDOW_REC *best;
GSList *tmp;
+ if (window != NULL)
+ last_line = window->last_line;
+ else
+ last_line = -1;
+
best = NULL;
for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
MAIN_WINDOW_REC *rec = tmp->data;
- if (rec->first_line > line &&
+ if (rec->first_line > last_line &&
(best == NULL || rec->first_line < best->first_line))
best = rec;
}
@@ -235,16 +302,64 @@ static MAIN_WINDOW_REC *mainwindows_find_lower(int line)
return best;
}
-static MAIN_WINDOW_REC *mainwindows_find_upper(int line)
+static MAIN_WINDOW_REC *mainwindows_find_right(MAIN_WINDOW_REC *window, int find_first)
{
+ int first_line, last_line, last_column;
MAIN_WINDOW_REC *best;
GSList *tmp;
+ if (window != NULL) {
+ first_line = window->first_line;
+ last_line = window->last_line;
+ last_column = window->last_column;
+ } else {
+ first_line = last_line = last_column = -1;
+ }
+
+ if (find_first)
+ last_column = -1;
+
best = NULL;
for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
MAIN_WINDOW_REC *rec = tmp->data;
- if (rec->last_line < line &&
+ if (rec->first_line >= first_line &&
+ rec->last_line <= last_line &&
+ rec->first_column > last_column &&
+ (best == NULL || rec->first_column < best->first_column))
+ best = rec;
+ }
+
+ return best;
+}
+
+static MAIN_WINDOW_REC *mainwindows_find_lower_right(MAIN_WINDOW_REC *window)
+{
+ MAIN_WINDOW_REC *best;
+
+ best = mainwindows_find_right(window, FALSE);
+ if (best == NULL)
+ best = mainwindows_find_lower(window);
+
+ return best;
+}
+
+static MAIN_WINDOW_REC *mainwindows_find_upper(MAIN_WINDOW_REC *window)
+{
+ int first_line;
+ MAIN_WINDOW_REC *best;
+ GSList *tmp;
+
+ if (window != NULL)
+ first_line = window->first_line;
+ else
+ first_line = screen_height;
+
+ best = NULL;
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ if (rec->last_line < first_line &&
(best == NULL || rec->last_line > best->last_line))
best = rec;
}
@@ -252,27 +367,142 @@ static MAIN_WINDOW_REC *mainwindows_find_upper(int line)
return best;
}
-static void mainwindows_add_space(int first_line, int last_line)
+static MAIN_WINDOW_REC *mainwindows_find_left(MAIN_WINDOW_REC *window, int find_last)
+{
+ int first_line, last_line, first_column;
+ MAIN_WINDOW_REC *best;
+ GSList *tmp;
+
+ if (window != NULL) {
+ first_line = window->first_line;
+ last_line = window->last_line;
+ first_column = window->first_column;
+ } else {
+ first_line = last_line = screen_height;
+ first_column = screen_width;
+ }
+
+ if (find_last)
+ first_column = screen_width;
+
+ best = NULL;
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+
+ if (rec->first_line >= first_line &&
+ rec->last_line <= last_line &&
+ rec->last_column < first_column &&
+ (best == NULL || rec->last_column > best->last_column))
+ best = rec;
+ }
+
+ return best;
+}
+
+static MAIN_WINDOW_REC *mainwindows_find_upper_left(MAIN_WINDOW_REC *window)
+{
+ MAIN_WINDOW_REC *best;
+
+ best = mainwindows_find_left(window, FALSE);
+ if (best == NULL)
+ best = mainwindows_find_upper(window);
+
+ return best;
+}
+
+static MAIN_WINDOW_REC *mainwindows_find_left_upper(MAIN_WINDOW_REC *window)
+{
+ MAIN_WINDOW_REC *best;
+
+ best = mainwindows_find_left(window, FALSE);
+ if (best == NULL)
+ best = mainwindows_find_left(mainwindows_find_upper(window), TRUE);
+
+ return best;
+}
+
+GSList *mainwindows_get_line(MAIN_WINDOW_REC *rec)
+{
+ MAIN_WINDOW_REC *win;
+ GSList *list;
+
+ list = NULL;
+
+ for (win = mainwindows_find_left(rec, FALSE);
+ win != NULL;
+ win = mainwindows_find_left(win, FALSE)) {
+ list = g_slist_append(list, win);
+ }
+
+ if (rec != NULL)
+ list = g_slist_append(list, rec);
+
+ for (win = mainwindows_find_right(rec, FALSE);
+ win != NULL;
+ win = mainwindows_find_right(win, FALSE)) {
+ list = g_slist_append(list, win);
+ }
+
+ return list;
+}
+
+/* add back the space which was occupied by destroyed mainwindow first_line .. last_line */
+static void mainwindows_add_space(MAIN_WINDOW_REC *destroy_win)
{
MAIN_WINDOW_REC *rec;
- int size;
+ int size, rsize;
- if (last_line < first_line)
+ if (destroy_win->last_line < destroy_win->first_line)
return;
- size = last_line-first_line+1;
+ if (destroy_win->last_column < destroy_win->first_column)
+ return;
- rec = mainwindows_find_lower(last_line);
+ rsize = destroy_win->last_column-destroy_win->first_column+1;
+ rec = mainwindows_find_left(destroy_win, FALSE);
if (rec != NULL) {
- rec->first_line = first_line;
- mainwindow_resize(rec, 0, size);
+ rec->last_column = destroy_win->last_column;
+ mainwindow_resize(rec, rsize+1, 0);
return;
}
- rec = mainwindows_find_upper(first_line);
+ rec = mainwindows_find_right(destroy_win, FALSE);
if (rec != NULL) {
- rec->last_line = last_line;
- mainwindow_resize(rec, 0, size);
+ rec->first_column = destroy_win->first_column;
+ mainwindow_resize(rec, rsize+1, 0);
+ return;
+ }
+
+ size = destroy_win->last_line-destroy_win->first_line+1;
+
+ rec = mainwindows_find_lower(destroy_win);
+ if (rec != NULL) {
+ GSList *tmp, *list;
+ list = mainwindows_get_line(rec);
+
+ for (tmp = list; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+ rec->first_line = destroy_win->first_line;
+ mainwindow_resize(rec, 0, size);
+ }
+
+ g_slist_free(list);
+ return;
+ }
+
+ rec = mainwindows_find_upper(destroy_win);
+ if (rec != NULL) {
+ GSList *tmp, *list;
+ list = mainwindows_get_line(rec);
+
+ for (tmp = list; tmp != NULL; tmp = tmp->next) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+ rec->last_line = destroy_win->last_line;
+ mainwindow_resize(rec, 0, size);
+ }
+
+ g_slist_free(list);
+ return;
}
}
@@ -302,8 +532,7 @@ void mainwindow_destroy(MAIN_WINDOW_REC *window)
if (mainwindows != NULL) {
gui_windows_remove_parent(window);
if (!quitting) {
- mainwindows_add_space(window->first_line,
- window->last_line);
+ mainwindows_add_space(window);
mainwindows_redraw();
}
}
@@ -313,6 +542,14 @@ void mainwindow_destroy(MAIN_WINDOW_REC *window)
if (active_mainwin == window) active_mainwin = NULL;
}
+void mainwindow_destroy_half(MAIN_WINDOW_REC *window)
+{
+ int really_quitting = quitting;
+ quitting = TRUE;
+ mainwindow_destroy(window);
+ quitting = really_quitting;
+}
+
void mainwindows_redraw(void)
{
GSList *tmp;
@@ -327,12 +564,20 @@ void mainwindows_redraw(void)
static int mainwindows_compare(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2)
{
- return w1->first_line < w2->first_line ? -1 : 1;
+ return w1->first_line < w2->first_line ? -1
+ : w1->first_line > w2->first_line ? 1
+ : w1->first_column < w2->first_column ? -1
+ : w1->first_column > w2->first_column ? 1
+ : 0;
}
static int mainwindows_compare_reverse(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2)
{
- return w1->first_line < w2->first_line ? 1 : -1;
+ return w1->first_line < w2->first_line ? 1
+ : w1->first_line > w2->first_line ? -1
+ : w1->first_column < w2->first_column ? 1
+ : w1->first_column > w2->first_column ? -1
+ : 0;
}
GSList *mainwindows_get_sorted(int reverse)
@@ -348,123 +593,235 @@ GSList *mainwindows_get_sorted(int reverse)
return list;
}
-static void mainwindows_resize_smaller(int xdiff, int ydiff)
+static void mainwindows_resize_smaller(int ydiff)
{
- MAIN_WINDOW_REC *rec;
+ MAIN_WINDOW_REC *rec;
GSList *sorted, *tmp;
- int space;
+ int space;
- sorted = mainwindows_get_sorted(TRUE);
+ sorted = NULL;
+ for (rec = mainwindows_find_lower(NULL);
+ rec != NULL;
+ rec = mainwindows_find_lower(rec)) {
+ sorted = g_slist_prepend(sorted, rec);
+ }
if (sorted == NULL)
return;
for (;;) {
+ int skip_active = FALSE;
space = 0;
- for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ /* for each line of windows, calculate the space that can be reduced still */
+ for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
+ int min;
+ GSList *line, *ltmp;
rec = tmp->data;
- space += MAIN_WINDOW_TEXT_HEIGHT(rec)-WINDOW_MIN_SIZE;
+ line = mainwindows_get_line(rec);
+ min = screen_height - ydiff;
+ for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) {
+ int lmin;
+ MAIN_WINDOW_REC *win = ltmp->data;
+ if (win == active_mainwin && tmp == sorted)
+ skip_active = TRUE;
+
+ lmin = MAIN_WINDOW_TEXT_HEIGHT(win)-WINDOW_MIN_SIZE;
+ if (lmin < min)
+ min = lmin;
+ }
+ g_slist_free(line);
+ space += min;
}
if (space >= -ydiff)
break;
rec = sorted->data;
- if (rec == active_mainwin && sorted->next != NULL)
+ if (skip_active && sorted->next != NULL)
rec = sorted->next->data;
sorted = g_slist_remove(sorted, rec);
if (sorted != NULL) {
/* terminal is too small - destroy the
uppest window and try again */
- mainwindow_destroy(rec);
+ GSList *line, *ltmp;
+ line = mainwindows_get_line(rec);
+ for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) {
+ MAIN_WINDOW_REC *win = ltmp->data;
+ mainwindow_destroy(win);
+ }
+ g_slist_free(line);
} else {
- /* only one window in screen.. just force the resize */
- rec->last_line += ydiff;
- mainwindow_resize(rec, xdiff, ydiff);
- return;
+ /* only one line of window in screen.. just force the resize */
+ GSList *line, *ltmp;
+ line = mainwindows_get_line(rec);
+ for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) {
+ MAIN_WINDOW_REC *win = ltmp->data;
+ win->last_line += ydiff;
+ mainwindow_resize(win, 0, ydiff);
+ }
+ g_slist_free(line);
+ return;
}
}
/* resize windows that have space */
for (tmp = sorted; tmp != NULL && ydiff < 0; tmp = tmp->next) {
- rec = tmp->data;
+ int min;
+ GSList *line, *ltmp;
- space = MAIN_WINDOW_TEXT_HEIGHT(rec)-WINDOW_MIN_SIZE;
- if (space == 0) {
- mainwindow_resize(rec, xdiff, 0);
-
- rec->first_line += ydiff;
- rec->last_line += ydiff;
- signal_emit("mainwindow moved", 1, rec);
- continue;
+ rec = tmp->data;
+ line = mainwindows_get_line(rec);
+ min = screen_height - ydiff;
+ for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) {
+ int lmin;
+ MAIN_WINDOW_REC *win = ltmp->data;
+ lmin = MAIN_WINDOW_TEXT_HEIGHT(win)-WINDOW_MIN_SIZE;
+ if (lmin < min)
+ min = lmin;
}
+ space = min;
- if (space > -ydiff) space = -ydiff;
- rec->last_line += ydiff;
- ydiff += space;
- rec->first_line += ydiff;
-
- mainwindow_resize(rec, xdiff, -space);
- }
+ if (space == 0) {
+ /* move the line */
+ for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) {
+ MAIN_WINDOW_REC *win = ltmp->data;
+ mainwindow_resize(win, 0, 0);
+ win->size_dirty = TRUE;
+ win->first_line += ydiff;
+ win->last_line += ydiff;
+ signal_emit("mainwindow moved", 1, win);
+ }
+ } else {
+ if (space > -ydiff) space = -ydiff;
+ for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) {
+ MAIN_WINDOW_REC *win = ltmp->data;
+ win->last_line += ydiff;
+ win->first_line += ydiff + space;
- if (xdiff != 0) {
- while (tmp != NULL) {
- mainwindow_resize(tmp->data, xdiff, 0);
- tmp = tmp->next;
+ mainwindow_resize(win, 0, -space);
+ }
+ ydiff += space;
}
+ g_slist_free(line);
}
g_slist_free(sorted);
}
-static void mainwindows_resize_bigger(int xdiff, int ydiff)
+static void mainwindows_rresize_line(int xdiff, MAIN_WINDOW_REC *win)
{
- GSList *sorted, *tmp;
+ int windows, i, extra_width, next_column, shrunk;
+ int *widths;
+ GSList *line, *tmp;
- sorted = mainwindows_get_sorted(FALSE);
- for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
- MAIN_WINDOW_REC *rec = tmp->data;
+ line = mainwindows_get_line(win);
+ windows = g_slist_length(line);
+ widths = g_new0(int, windows);
- if (ydiff == 0 || tmp->next != NULL) {
- mainwindow_resize(rec, xdiff, 0);
- continue;
+ extra_width = screen_width - windows + 1;
+ for (tmp = line, i = 0; tmp != NULL; tmp = tmp->next, i++) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+ widths[i] = (MAIN_WINDOW_TEXT_WIDTH(rec) * (screen_width - windows + 1)) / (screen_width - xdiff - windows + 1);
+ extra_width -= widths[i] + rec->statusbar_columns;
+ }
+ shrunk = FALSE;
+ for (i = windows; extra_width < 0; i = i > 1 ? i - 1 : windows) {
+ if (widths[i-1] > NEW_WINDOW_WIDTH || (i == 1 && !shrunk)) {
+ widths[i-1]--;
+ extra_width++;
+ shrunk = i == 1;
}
-
- /* lowest window - give all the extra space for it */
- rec->last_line += ydiff;
- mainwindow_resize(rec, xdiff, ydiff);
}
- g_slist_free(sorted);
-}
-static void mainwindows_resize_horiz(int xdiff)
-{
- GSList *tmp;
+ next_column = 0;
- for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
- MAIN_WINDOW_REC *rec = tmp->data;
+#define extra ( (i >= screen_width % windows && i < extra_width + (screen_width % windows)) \
+ || i + windows < extra_width + (screen_width % windows) ? 1 : 0 )
- mainwindow_resize(rec, xdiff, 0);
+ for (tmp = line, i = 0; tmp != NULL; tmp = tmp->next, i++) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+ rec->first_column = next_column;
+ rec->last_column = rec->first_column + widths[i] + rec->statusbar_columns + extra - 1;
+ next_column = rec->last_column + 2;
+ mainwindow_resize(rec, widths[i] + rec->statusbar_columns + extra - rec->width, 0);
+ rec->size_dirty = TRUE;
}
+#undef extra
+
+ g_free(widths);
+ g_slist_free(line);
}
void mainwindows_resize(int width, int height)
{
int xdiff, ydiff;
- xdiff = width-old_screen_width;
- ydiff = height-old_screen_height;
- old_screen_width = width;
- old_screen_height = height;
+ xdiff = width-screen_width;
+ ydiff = height-screen_height;
+ screen_width = width;
+ screen_height = height;
+
+ if (ydiff > 0) {
+ /* algorithm: enlarge bottom window */
+ MAIN_WINDOW_REC *rec;
+ GSList *line, *tmp;
+ line = mainwindows_get_line(mainwindows_find_upper(NULL));
+ for (tmp = line; tmp != NULL; tmp = tmp->next) {
+ rec = tmp->data;
+ rec->last_line += ydiff;
+ mainwindow_resize(rec, 0, ydiff);
+ }
+ g_slist_free(line);
+ }
+
+ if (xdiff > 0) {
+ /* algorithm: distribute new space on each line */
+ MAIN_WINDOW_REC *win;
+
+ for (win = mainwindows_find_lower(NULL);
+ win != NULL;
+ win = mainwindows_find_lower(win)) {
+ mainwindows_rresize_line(xdiff, win);
+ }
+ }
+
+ if (xdiff < 0) {
+ /* algorithm: shrink each window,
+ destroy windows on the right if no room */
+ MAIN_WINDOW_REC *win;
+
+ for (win = mainwindows_find_lower(NULL);
+ win != NULL;
+ win = mainwindows_find_lower(win)) {
+ int max_windows, i, last_column;
+ GSList *line, *tmp;
+
+ line = mainwindows_get_line(win);
+ max_windows = (screen_width + 1) / (NEW_WINDOW_WIDTH + 1);
+ if (max_windows < 1)
+ max_windows = 1;
+ last_column = screen_width - 1;
+ for (tmp = line, i = 0; tmp != NULL; tmp = tmp->next, i++) {
+ MAIN_WINDOW_REC *rec = tmp->data;
+ if (i >= max_windows)
+ mainwindow_destroy_half(rec);
+ else
+ last_column = rec->last_column;
+ }
+ win = line->data;
+ g_slist_free(line);
+
+ mainwindows_rresize_line(screen_width - last_column + 1, win);
+ }
+ }
- if (ydiff < 0)
- mainwindows_resize_smaller(xdiff, ydiff);
- else if (ydiff > 0)
- mainwindows_resize_bigger(xdiff, ydiff);
- else if (xdiff != 0)
- mainwindows_resize_horiz(xdiff);
+ if (ydiff < 0) {
+ /* algorithm: shrink windows starting from bottom,
+ destroy windows starting from top if no room */
+ mainwindows_resize_smaller(ydiff);
+ }
- signal_emit("terminal resized", 0);
+ signal_emit("terminal resized", 0);
irssi_redraw();
}
@@ -474,31 +831,37 @@ int mainwindows_reserve_lines(int top, int bottom)
MAIN_WINDOW_REC *window;
int ret;
- ret = -1;
+ ret = -1;
if (top != 0) {
+ GSList *list, *tmp;
g_return_val_if_fail(top > 0 || screen_reserved_top > top, -1);
ret = screen_reserved_top;
screen_reserved_top += top;
- window = mainwindows_find_lower(-1);
- if (window != NULL) {
+ list = mainwindows_get_line(mainwindows_find_lower(NULL));
+ for (tmp = list; tmp != NULL; tmp = tmp->next) {
+ window = tmp->data;
window->first_line += top;
mainwindow_resize(window, 0, -top);
}
+ g_slist_free(list);
}
if (bottom != 0) {
+ GSList *list, *tmp;
g_return_val_if_fail(bottom > 0 || screen_reserved_bottom > bottom, -1);
ret = screen_reserved_bottom;
screen_reserved_bottom += bottom;
- window = mainwindows_find_upper(term_height);
- if (window != NULL) {
+ list = mainwindows_get_line(mainwindows_find_upper(NULL));
+ for (tmp = list; tmp != NULL; tmp = tmp->next) {
+ window = tmp->data;
window->last_line -= bottom;
mainwindow_resize(window, 0, -bottom);
}
+ g_slist_free(list);
}
return ret;
@@ -528,47 +891,109 @@ int mainwindow_set_statusbar_lines(MAIN_WINDOW_REC *window,
return ret;
}
-static void mainwindows_resize_two(MAIN_WINDOW_REC *grow_win,
- MAIN_WINDOW_REC *shrink_win, int count)
+static void mainwindows_resize_two(GSList *grow_list,
+ GSList *shrink_list, int count)
{
- irssi_set_dirty();
+ GSList *tmp;
+ MAIN_WINDOW_REC *win;
- mainwindow_resize(grow_win, 0, count);
- mainwindow_resize(shrink_win, 0, -count);
- grow_win->dirty = TRUE;
- shrink_win->dirty = TRUE;
+ irssi_set_dirty();
+
+ for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ mainwindow_resize(win, 0, -count);
+ win->dirty = TRUE;
+ }
+ for (tmp = grow_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ mainwindow_resize(win, 0, count);
+ win->dirty = TRUE;
+ }
}
static int try_shrink_lower(MAIN_WINDOW_REC *window, int count)
{
MAIN_WINDOW_REC *shrink_win;
- shrink_win = mainwindows_find_lower(window->last_line);
- if (shrink_win != NULL &&
- MAIN_WINDOW_TEXT_HEIGHT(shrink_win)-count >= WINDOW_MIN_SIZE) {
- window->last_line += count;
- shrink_win->first_line += count;
- mainwindows_resize_two(window, shrink_win, count);
- return TRUE;
+ shrink_win = mainwindows_find_lower(window);
+ if (shrink_win != NULL) {
+ int ok;
+ GSList *shrink_list, *tmp;
+ MAIN_WINDOW_REC *win;
+
+ ok = TRUE;
+ shrink_list = mainwindows_get_line(shrink_win);
+
+ for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ if (MAIN_WINDOW_TEXT_HEIGHT(win)-count < WINDOW_MIN_SIZE) {
+ ok = FALSE;
+ break;
+ }
+ }
+ if (ok) {
+ GSList *grow_list;
+ grow_list = mainwindows_get_line(window);
+
+ for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ win->first_line += count;
+ }
+ for (tmp = grow_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ win->last_line += count;
+ }
+
+ mainwindows_resize_two(grow_list, shrink_list, count);
+ g_slist_free(grow_list);
+ }
+
+ g_slist_free(shrink_list);
+ return ok;
}
- return FALSE;
+ return FALSE;
}
static int try_shrink_upper(MAIN_WINDOW_REC *window, int count)
{
MAIN_WINDOW_REC *shrink_win;
- shrink_win = mainwindows_find_upper(window->first_line);
- if (shrink_win != NULL &&
- MAIN_WINDOW_TEXT_HEIGHT(shrink_win)-count >= WINDOW_MIN_SIZE) {
- window->first_line -= count;
- shrink_win->last_line -= count;
- mainwindows_resize_two(window, shrink_win, count);
- return TRUE;
+ shrink_win = mainwindows_find_upper(window);
+ if (shrink_win != NULL) {
+ int ok;
+ GSList *shrink_list, *tmp;
+ MAIN_WINDOW_REC *win;
+
+ ok = TRUE;
+ shrink_list = mainwindows_get_line(shrink_win);
+
+ for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ if (MAIN_WINDOW_TEXT_HEIGHT(win)-count < WINDOW_MIN_SIZE) {
+ ok = FALSE;
+ break;
+ }
+ }
+ if (ok) {
+ GSList *grow_list;
+ grow_list = mainwindows_get_line(window);
+ for (tmp = grow_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ win->first_line -= count;
+ }
+ for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ win->last_line -= count;
+ }
+ mainwindows_resize_two(grow_list, shrink_list, count);
+ g_slist_free(grow_list);
+ }
+ g_slist_free(shrink_list);
+ return ok;
}
- return FALSE;
+ return FALSE;
}
static int mainwindow_grow(MAIN_WINDOW_REC *window, int count,
@@ -588,28 +1013,52 @@ static int try_grow_lower(MAIN_WINDOW_REC *window, int count)
{
MAIN_WINDOW_REC *grow_win;
- grow_win = mainwindows_find_lower(window->last_line);
+ grow_win = mainwindows_find_lower(window);
if (grow_win != NULL) {
- window->last_line -= count;
- grow_win->first_line -= count;
- mainwindows_resize_two(grow_win, window, count);
+ MAIN_WINDOW_REC *win;
+ GSList *grow_list, *shrink_list, *tmp;
+ grow_list = mainwindows_get_line(grow_win);
+ shrink_list = mainwindows_get_line(window);
+ for (tmp = grow_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ win->first_line -= count;
+ }
+ for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ win->last_line -= count;
+ }
+ mainwindows_resize_two(grow_list, shrink_list, count);
+ g_slist_free(shrink_list);
+ g_slist_free(grow_list);
}
- return grow_win != NULL;
+ return grow_win != NULL;
}
static int try_grow_upper(MAIN_WINDOW_REC *window, int count)
{
MAIN_WINDOW_REC *grow_win;
- grow_win = mainwindows_find_upper(window->first_line);
+ grow_win = mainwindows_find_upper(window);
if (grow_win != NULL) {
- window->first_line += count;
- grow_win->last_line += count;
- mainwindows_resize_two(grow_win, window, count);
+ MAIN_WINDOW_REC *win;
+ GSList *grow_list, *shrink_list, *tmp;
+ grow_list = mainwindows_get_line(grow_win);
+ shrink_list = mainwindows_get_line(window);
+ for (tmp = grow_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ win->last_line += count;
+ }
+ for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) {
+ win = tmp->data;
+ win->first_line += count;
+ }
+ mainwindows_resize_two(grow_list, shrink_list, count);
+ g_slist_free(shrink_list);
+ g_slist_free(grow_list);
}
- return grow_win != NULL;
+ return grow_win != NULL;
}
static int mainwindow_shrink(MAIN_WINDOW_REC *window, int count, int resize_lower)
@@ -627,6 +1076,109 @@ static int mainwindow_shrink(MAIN_WINDOW_REC *window, int count, int resize_lowe
return TRUE;
}
+static void mainwindows_rresize_two(MAIN_WINDOW_REC *grow_win,
+ MAIN_WINDOW_REC *shrink_win, int count)
+{
+ irssi_set_dirty();
+
+ mainwindow_resize(grow_win, count, 0);
+ mainwindow_resize(shrink_win, -count, 0);
+ grow_win->dirty = TRUE;
+ shrink_win->dirty = TRUE;
+}
+
+static int try_rshrink_right(MAIN_WINDOW_REC *window, int count)
+{
+ MAIN_WINDOW_REC *shrink_win;
+
+ shrink_win = mainwindows_find_right(window, FALSE);
+ if (shrink_win != NULL) {
+ if (MAIN_WINDOW_TEXT_WIDTH(shrink_win)-count < NEW_WINDOW_WIDTH) {
+ return FALSE;
+ }
+
+ shrink_win->first_column += count;
+ window->last_column += count;
+
+ mainwindows_rresize_two(window, shrink_win, count);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int try_rshrink_left(MAIN_WINDOW_REC *window, int count)
+{
+ MAIN_WINDOW_REC *shrink_win;
+
+ shrink_win = mainwindows_find_left(window, FALSE);
+ if (shrink_win != NULL) {
+ if (MAIN_WINDOW_TEXT_WIDTH(shrink_win)-count < NEW_WINDOW_WIDTH) {
+ return FALSE;
+ }
+ window->first_column -= count;
+ shrink_win->last_column -= count;
+
+ mainwindows_rresize_two(window, shrink_win, count);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int mainwindow_rgrow(MAIN_WINDOW_REC *window, int count)
+{
+ if (!try_rshrink_right(window, count)) {
+ if (!try_rshrink_left(window, count))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int try_rgrow_right(MAIN_WINDOW_REC *window, int count)
+{
+ MAIN_WINDOW_REC *grow_win;
+
+ grow_win = mainwindows_find_right(window, FALSE);
+ if (grow_win != NULL) {
+ grow_win->first_column -= count;
+ window->last_column -= count;
+ mainwindows_rresize_two(grow_win, window, count);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int try_rgrow_left(MAIN_WINDOW_REC *window, int count)
+{
+ MAIN_WINDOW_REC *grow_win;
+
+ grow_win = mainwindows_find_left(window, FALSE);
+ if (grow_win != NULL) {
+ grow_win->last_column += count;
+ window->first_column += count;
+ mainwindows_rresize_two(grow_win, window, count);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int mainwindow_rshrink(MAIN_WINDOW_REC *window, int count)
+{
+ if (MAIN_WINDOW_TEXT_WIDTH(window)-count < NEW_WINDOW_WIDTH)
+ return FALSE;
+
+ if (!try_rgrow_right(window, count)) {
+ if (!try_rgrow_left(window, count))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/* Change the window height - the height includes the lines needed for
statusbars. If resize_lower is TRUE, the lower window is first tried
to be resized instead of upper window. */
@@ -639,6 +1191,15 @@ void mainwindow_set_size(MAIN_WINDOW_REC *window, int height, int resize_lower)
mainwindow_grow(window, height, resize_lower);
}
+void mainwindow_set_rsize(MAIN_WINDOW_REC *window, int width)
+{
+ width -= window->width;
+ if (width < 0)
+ mainwindow_rshrink(window, -width);
+ else
+ mainwindow_rgrow(window, width);
+}
+
void mainwindows_redraw_dirty(void)
{
GSList *tmp;
@@ -653,6 +1214,8 @@ void mainwindows_redraw_dirty(void)
if (rec->dirty) {
rec->dirty = FALSE;
gui_window_redraw(rec->active);
+ } else if (WINDOW_GUI(rec->active)->view->dirty) {
+ gui_window_redraw(rec->active);
}
}
}
@@ -707,35 +1270,52 @@ static void cmd_window_size(const char *data)
/* SYNTAX: WINDOW BALANCE */
static void cmd_window_balance(void)
{
- GSList *sorted, *tmp;
+ GSList *sorted, *stmp, *line, *ltmp;
int avail_size, unit_size, bigger_units;
int windows, last_line, old_size;
+ MAIN_WINDOW_REC *win;
windows = g_slist_length(mainwindows);
if (windows == 1) return;
+ sorted = NULL;
+ windows = 0;
+ for (win = mainwindows_find_lower(NULL);
+ win != NULL;
+ win = mainwindows_find_lower(win)) {
+ windows++;
+ sorted = g_slist_append(sorted, win);
+ }
+
avail_size = term_height - screen_reserved_top-screen_reserved_bottom;
unit_size = avail_size/windows;
bigger_units = avail_size%windows;
- sorted = mainwindows_get_sorted(FALSE);
- last_line = screen_reserved_top;
- for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
- MAIN_WINDOW_REC *rec = tmp->data;
+ last_line = screen_reserved_top;
+ for (stmp = sorted; stmp != NULL; stmp = stmp->next) {
+ win = stmp->data;
+ line = mainwindows_get_line(win);
- old_size = rec->height;
- rec->first_line = last_line;
- rec->last_line = rec->first_line + unit_size-1;
+ for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) {
+ MAIN_WINDOW_REC *rec = ltmp->data;
+ old_size = rec->height;
+ rec->first_line = last_line;
+ rec->last_line = rec->first_line + unit_size-1;
- if (bigger_units > 0) {
- rec->last_line++;
- bigger_units--;
- }
+ if (bigger_units > 0) {
+ rec->last_line++;
+ }
- rec->height = rec->last_line-rec->first_line+1;
- last_line = rec->last_line+1;
+ rec->height = rec->last_line-rec->first_line+1;
- mainwindow_resize(rec, 0, rec->height-old_size);
+ mainwindow_resize(rec, 0, rec->height-old_size);
+ }
+ if (line != NULL && bigger_units > 0) {
+ bigger_units--;
+ }
+ last_line = win->last_line+1;
+
+ g_slist_free(line);
}
g_slist_free(sorted);
@@ -769,29 +1349,30 @@ static void cmd_window_hide(const char *data)
return;
if (WINDOW_MAIN(window)->sticky_windows) {
- printformat_window(active_win, MSGLEVEL_CLIENTERROR,
- TXT_CANT_HIDE_STICKY_WINDOWS);
- return;
+ if (!settings_get_bool("autounstick_windows")) {
+ printformat_window(active_win, MSGLEVEL_CLIENTERROR,
+ TXT_CANT_HIDE_STICKY_WINDOWS);
+ return;
+ }
}
mainwindow_destroy(WINDOW_MAIN(window));
if (active_mainwin == NULL) {
active_mainwin = WINDOW_MAIN(active_win);
- window_set_active(active_mainwin->active);
+ window_set_active(active_mainwin->active);
}
}
-/* SYNTAX: WINDOW SHOW <number>|<name> */
-static void cmd_window_show(const char *data)
+static void _cmd_window_show_opt(const char *data, int right)
{
- MAIN_WINDOW_REC *parent;
+ MAIN_WINDOW_REC *parent;
WINDOW_REC *window;
if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
if (is_numeric(data, '\0')) {
- window = window_find_refnum(atoi(data));
+ window = window_find_refnum(atoi(data));
if (window == NULL) {
printformat_window(active_win, MSGLEVEL_CLIENTERROR,
TXT_REFNUM_NOT_FOUND, data);
@@ -804,30 +1385,150 @@ static void cmd_window_show(const char *data)
return;
if (WINDOW_GUI(window)->sticky) {
- printformat_window(active_win, MSGLEVEL_CLIENTERROR,
- TXT_CANT_SHOW_STICKY_WINDOWS);
- return;
+ if (!settings_get_bool("autounstick_windows")) {
+ printformat_window(active_win, MSGLEVEL_CLIENTERROR,
+ TXT_CANT_SHOW_STICKY_WINDOWS);
+ return;
+ }
}
- parent = mainwindow_create();
+ parent = mainwindow_create(right);
parent->active = window;
- gui_window_reparent(window, parent);
+ gui_window_reparent(window, parent);
if (settings_get_bool("autostick_split_windows"))
- gui_window_set_sticky(window);
+ gui_window_set_sticky(window);
active_mainwin = NULL;
window_set_active(window);
}
+/* SYNTAX: WINDOW SHOW <number>|<name> */
+static void cmd_window_show(const char *data)
+{
+ _cmd_window_show_opt(data, FALSE);
+}
+
+/* SYNTAX: WINDOW RSHOW <number>|<name> */
+static void cmd_window_rshow(const char *data)
+{
+ _cmd_window_show_opt(data, TRUE);
+}
+
+/* SYNTAX: WINDOW RGROW [<columns>] */
+static void cmd_window_rgrow(const char *data)
+{
+ int count;
+
+ count = *data == '\0' ? 1 : atoi(data);
+ if (!mainwindow_rgrow(WINDOW_MAIN(active_win), count)) {
+ printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
+ TXT_WINDOW_TOO_SMALL);
+ }
+}
+
+/* SYNTAX: WINDOW RSHRINK [<lines>] */
+static void cmd_window_rshrink(const char *data)
+{
+ int count;
+
+ count = *data == '\0' ? 1 : atoi(data);
+ if (!mainwindow_rshrink(WINDOW_MAIN(active_win), count)) {
+ printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
+ TXT_WINDOW_TOO_SMALL);
+ }
+}
+
+/* SYNTAX: WINDOW RSIZE <columns> */
+static void cmd_window_rsize(const char *data)
+{
+ char rsizestr[MAX_INT_STRLEN];
+ int rsize;
+
+ if (!is_numeric(data, 0)) return;
+ rsize = atoi(data);
+
+ rsize -= MAIN_WINDOW_TEXT_WIDTH(WINDOW_MAIN(active_win));
+ if (rsize == 0) return;
+
+ ltoa(rsizestr, rsize < 0 ? -rsize : rsize);
+ if (rsize < 0)
+ cmd_window_rshrink(rsizestr);
+ else
+ cmd_window_rgrow(rsizestr);
+}
+
+/* SYNTAX: WINDOW RBALANCE */
+static void cmd_window_rbalance(void)
+{
+ GSList *line, *ltmp;
+ int avail_width, unit_width, bigger_units;
+ int windows, last_column, old_width;
+ MAIN_WINDOW_REC *win;
+
+ line = mainwindows_get_line(WINDOW_MAIN(active_win));
+ windows = g_slist_length(line);
+ if (windows == 1) {
+ g_slist_free(line);
+ return;
+ }
+
+ avail_width = term_width - screen_reserved_left-screen_reserved_right - windows + 1;
+ unit_width = avail_width/windows;
+ bigger_units = avail_width%windows;
+
+ last_column = screen_reserved_left;
+ for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) {
+ win = ltmp->data;
+ old_width = win->width;
+ win->first_column = last_column;
+ win->last_column = win->first_column + unit_width-1;
+
+ if (bigger_units > 0) {
+ win->last_column++;
+ bigger_units--;
+ }
+
+ mainwindow_resize(win, win->last_column - win->first_column + 1 - old_width, 0);
+ last_column = win->last_column+2;
+ }
+ g_slist_free(line);
+
+ mainwindows_redraw();
+}
+
/* SYNTAX: WINDOW UP */
static void cmd_window_up(void)
{
MAIN_WINDOW_REC *rec;
- rec = mainwindows_find_upper(active_mainwin->first_line);
+ rec = mainwindows_find_left_upper(active_mainwin);
+ if (rec == NULL)
+ rec = mainwindows_find_left_upper(NULL);
+ if (rec != NULL)
+ window_set_active(rec->active);
+}
+
+/* SYNTAX: WINDOW DUP */
+static void cmd_window_dup(void)
+{
+ MAIN_WINDOW_REC *rec;
+
+ rec = mainwindows_find_upper(active_mainwin);
if (rec == NULL)
- rec = mainwindows_find_upper(term_height);
+ rec = mainwindows_find_upper(NULL);
+ if (rec != NULL)
+ window_set_active(rec->active);
+}
+
+/* SYNTAX: WINDOW DLEFT */
+static void cmd_window_dleft(void)
+{
+ MAIN_WINDOW_REC *rec;
+
+ rec = mainwindows_find_left(active_mainwin, FALSE);
+ if (rec == NULL)
+ rec = mainwindows_find_left(active_mainwin, TRUE);
if (rec != NULL)
window_set_active(rec->active);
}
@@ -837,9 +1538,33 @@ static void cmd_window_down(void)
{
MAIN_WINDOW_REC *rec;
- rec = mainwindows_find_lower(active_mainwin->last_line);
+ rec = mainwindows_find_lower_right(active_mainwin);
+ if (rec == NULL)
+ rec = mainwindows_find_lower_right(NULL);
+ if (rec != NULL)
+ window_set_active(rec->active);
+}
+
+/* SYNTAX: WINDOW DDOWN */
+static void cmd_window_ddown(void)
+{
+ MAIN_WINDOW_REC *rec;
+
+ rec = mainwindows_find_lower(active_mainwin);
+ if (rec == NULL)
+ rec = mainwindows_find_lower(NULL);
+ if (rec != NULL)
+ window_set_active(rec->active);
+}
+
+/* SYNTAX: WINDOW DRIGHT */
+static void cmd_window_dright(void)
+{
+ MAIN_WINDOW_REC *rec;
+
+ rec = mainwindows_find_right(active_mainwin, FALSE);
if (rec == NULL)
- rec = mainwindows_find_lower(-1);
+ rec = mainwindows_find_right(active_mainwin, TRUE);
if (rec != NULL)
window_set_active(rec->active);
}
@@ -997,13 +1722,37 @@ static void cmd_window_move_right(void)
window_set_refnum(active_win, refnum);
}
+/* SYNTAX: WINDOW MOVE DLEFT */
+static void cmd_window_move_dleft(void)
+{
+ MAIN_WINDOW_REC *rec;
+
+ rec = mainwindows_find_left(active_mainwin, FALSE);
+ if (rec == NULL)
+ rec = mainwindows_find_left(active_mainwin, TRUE);
+ if (rec != NULL)
+ window_reparent(active_win, rec);
+}
+
+/* SYNTAX: WINDOW MOVE DRIGHT */
+static void cmd_window_move_dright(void)
+{
+ MAIN_WINDOW_REC *rec;
+
+ rec = mainwindows_find_right(active_mainwin, FALSE);
+ if (rec == NULL)
+ rec = mainwindows_find_right(active_mainwin, TRUE);
+ if (rec != NULL)
+ window_reparent(active_win, rec);
+}
+
/* SYNTAX: WINDOW MOVE UP */
static void cmd_window_move_up(void)
{
MAIN_WINDOW_REC *rec;
- rec = mainwindows_find_upper(active_mainwin->first_line);
- if (rec != NULL)
+ rec = mainwindows_find_upper_left(active_mainwin);
+ if (rec != NULL)
window_reparent(active_win, rec);
}
@@ -1012,7 +1761,7 @@ static void cmd_window_move_down(void)
{
MAIN_WINDOW_REC *rec;
- rec = mainwindows_find_lower(active_mainwin->last_line);
+ rec = mainwindows_find_lower_right(active_mainwin);
if (rec != NULL)
window_reparent(active_win, rec);
}
@@ -1058,12 +1807,14 @@ static void sig_window_print_info(WINDOW_REC *win)
void mainwindows_init(void)
{
- old_screen_width = term_width;
- old_screen_height = term_height;
+ screen_width = term_width;
+ screen_height = term_height;
mainwindows = NULL;
active_mainwin = NULL;
+ clrtoeol_info = g_new0(MAIN_WINDOW_BORDER_REC, 1);
screen_reserved_top = screen_reserved_bottom = 0;
+ screen_reserved_left = screen_reserved_right = 0;
command_bind("window grow", NULL, (SIGNAL_FUNC) cmd_window_grow);
command_bind("window shrink", NULL, (SIGNAL_FUNC) cmd_window_shrink);
@@ -1075,18 +1826,30 @@ void mainwindows_init(void)
command_bind("window down", NULL, (SIGNAL_FUNC) cmd_window_down);
command_bind("window left", NULL, (SIGNAL_FUNC) cmd_window_left);
command_bind("window right", NULL, (SIGNAL_FUNC) cmd_window_right);
+ command_bind("window dup", NULL, (SIGNAL_FUNC) cmd_window_dup);
+ command_bind("window ddown", NULL, (SIGNAL_FUNC) cmd_window_ddown);
+ command_bind("window dleft", NULL, (SIGNAL_FUNC) cmd_window_dleft);
+ command_bind("window dright", NULL, (SIGNAL_FUNC) cmd_window_dright);
command_bind("window stick", NULL, (SIGNAL_FUNC) cmd_window_stick);
command_bind("window move left", NULL, (SIGNAL_FUNC) cmd_window_move_left);
command_bind("window move right", NULL, (SIGNAL_FUNC) cmd_window_move_right);
command_bind("window move up", NULL, (SIGNAL_FUNC) cmd_window_move_up);
command_bind("window move down", NULL, (SIGNAL_FUNC) cmd_window_move_down);
- signal_add("window print info", (SIGNAL_FUNC) sig_window_print_info);
+ command_bind("window move dleft", NULL, (SIGNAL_FUNC) cmd_window_move_dleft);
+ command_bind("window move dright", NULL, (SIGNAL_FUNC) cmd_window_move_dright);
+ command_bind("window rgrow", NULL, (SIGNAL_FUNC) cmd_window_rgrow);
+ command_bind("window rshrink", NULL, (SIGNAL_FUNC) cmd_window_rshrink);
+ command_bind("window rsize", NULL, (SIGNAL_FUNC) cmd_window_rsize);
+ command_bind("window rbalance", NULL, (SIGNAL_FUNC) cmd_window_rbalance);
+ command_bind("window rshow", NULL, (SIGNAL_FUNC) cmd_window_rshow);
+ signal_add("window print info", (SIGNAL_FUNC) sig_window_print_info);
}
void mainwindows_deinit(void)
{
while (mainwindows != NULL)
mainwindow_destroy(mainwindows->data);
+ g_free(clrtoeol_info);
command_unbind("window grow", (SIGNAL_FUNC) cmd_window_grow);
command_unbind("window shrink", (SIGNAL_FUNC) cmd_window_shrink);
@@ -1098,10 +1861,21 @@ void mainwindows_deinit(void)
command_unbind("window down", (SIGNAL_FUNC) cmd_window_down);
command_unbind("window left", (SIGNAL_FUNC) cmd_window_left);
command_unbind("window right", (SIGNAL_FUNC) cmd_window_right);
+ command_unbind("window dup", (SIGNAL_FUNC) cmd_window_dup);
+ command_unbind("window ddown", (SIGNAL_FUNC) cmd_window_ddown);
+ command_unbind("window dleft", (SIGNAL_FUNC) cmd_window_dleft);
+ command_unbind("window dright", (SIGNAL_FUNC) cmd_window_dright);
command_unbind("window stick", (SIGNAL_FUNC) cmd_window_stick);
command_unbind("window move left", (SIGNAL_FUNC) cmd_window_move_left);
command_unbind("window move right", (SIGNAL_FUNC) cmd_window_move_right);
command_unbind("window move up", (SIGNAL_FUNC) cmd_window_move_up);
command_unbind("window move down", (SIGNAL_FUNC) cmd_window_move_down);
- signal_remove("window print info", (SIGNAL_FUNC) sig_window_print_info);
+ command_unbind("window move dleft", (SIGNAL_FUNC) cmd_window_move_dleft);
+ command_unbind("window move dright", (SIGNAL_FUNC) cmd_window_move_dright);
+ command_unbind("window rgrow", (SIGNAL_FUNC) cmd_window_rgrow);
+ command_unbind("window rshrink", (SIGNAL_FUNC) cmd_window_rshrink);
+ command_unbind("window rsize", (SIGNAL_FUNC) cmd_window_rsize);
+ command_unbind("window rbalance", (SIGNAL_FUNC) cmd_window_rbalance);
+ command_unbind("window rshow", (SIGNAL_FUNC) cmd_window_rshow);
+ signal_remove("window print info", (SIGNAL_FUNC) sig_window_print_info);
}
diff --git a/src/fe-text/mainwindows.h b/src/fe-text/mainwindows.h
index 1bca333d..414275bf 100644
--- a/src/fe-text/mainwindows.h
+++ b/src/fe-text/mainwindows.h
@@ -5,36 +5,48 @@
#include "term.h"
#define WINDOW_MIN_SIZE 2
+#define NEW_WINDOW_WIDTH 10
#define MAIN_WINDOW_TEXT_HEIGHT(window) \
((window)->height-(window)->statusbar_lines)
+#define MAIN_WINDOW_TEXT_WIDTH(window) \
+ ((window)->width-(window)->statusbar_columns)
+
typedef struct {
WINDOW_REC *active;
TERM_WINDOW *screen_win;
- int sticky_windows; /* number of sticky windows */
+ int sticky_windows; /* number of sticky windows */
int first_line, last_line; /* first/last line used by this window (0..x) (includes statusbars) */
+ int first_column, last_column; /* first/last column used by this window (0..x) (includes statusbars) */
int width, height; /* width/height of the window (includes statusbars) */
GSList *statusbars;
- int statusbar_lines_top;
- int statusbar_lines_bottom;
+ int statusbar_lines_top, statusbar_lines_bottom;
int statusbar_lines; /* top+bottom */
+ int statusbar_columns_left, statusbar_columns_right;
+ int statusbar_columns; /* left+right */
unsigned int dirty:1; /* This window needs a redraw */
unsigned int size_dirty:1; /* We'll need to resize the window, but haven't got around doing it just yet. */
} MAIN_WINDOW_REC;
+typedef struct {
+ char *color;
+ TERM_WINDOW *window;
+} MAIN_WINDOW_BORDER_REC;
+
extern GSList *mainwindows;
extern MAIN_WINDOW_REC *active_mainwin;
+extern MAIN_WINDOW_BORDER_REC *clrtoeol_info;
extern int screen_reserved_top, screen_reserved_bottom;
void mainwindows_init(void);
void mainwindows_deinit(void);
-MAIN_WINDOW_REC *mainwindow_create(void);
+MAIN_WINDOW_REC *mainwindow_create(int);
void mainwindow_destroy(MAIN_WINDOW_REC *window);
void mainwindows_redraw(void);
@@ -45,6 +57,7 @@ void mainwindows_recreate(void);
to be resized instead of upper window. */
void mainwindow_set_size(MAIN_WINDOW_REC *window, int height,
int resize_lower);
+void mainwindow_set_rsize(MAIN_WINDOW_REC *window, int width);
void mainwindows_resize(int width, int height);
void mainwindow_change_active(MAIN_WINDOW_REC *mainwin,
@@ -56,5 +69,6 @@ int mainwindow_set_statusbar_lines(MAIN_WINDOW_REC *window,
void mainwindows_redraw_dirty(void);
GSList *mainwindows_get_sorted(int reverse);
+GSList *mainwindows_get_line(MAIN_WINDOW_REC *rec);
#endif
diff --git a/src/fe-text/module-formats.c b/src/fe-text/module-formats.c
index 899827c2..8fa31a0e 100644
--- a/src/fe-text/module-formats.c
+++ b/src/fe-text/module-formats.c
@@ -41,8 +41,8 @@ FORMAT_REC gui_text_formats[] =
{ "refnum_not_found", "Window number $0 not found", 1, { 0 } },
{ "window_too_small", "Not enough room to resize this window", 0 },
{ "cant_hide_last", "You can't hide the last window", 0 },
- { "cant_hide_sticky_windows", "You can't hide sticky windows (use /WINDOW STICK OFF)", 0 },
- { "cant_show_sticky_windows", "You can't show sticky windows (use /WINDOW STICK OFF)", 0 },
+ { "cant_hide_sticky_windows", "You can't hide sticky windows (use /SET autounstick_windows ON)", 0 },
+ { "cant_show_sticky_windows", "You can't show sticky windows (use /SET autounstick_windows ON)", 0 },
{ "window_not_sticky", "Window is not sticky", 0 },
{ "window_set_sticky", "Window set sticky", 0 },
{ "window_unset_sticky", "Window is not sticky anymore", 0 },
@@ -50,6 +50,7 @@ FORMAT_REC gui_text_formats[] =
{ "window_info_scroll", "%#Scroll : $0", 1, { 0 } },
{ "window_scroll", "Window scroll mode is now $0", 1, { 0 } },
{ "window_scroll_unknown", "Unknown scroll mode $0, must be ON, OFF or DEFAULT", 1, { 0 } },
+ { "window_hidelevel", "Window hidden level is now $0", 1, { 0 } },
/* ---- */
{ NULL, "Statusbars", 0 },
@@ -78,5 +79,26 @@ FORMAT_REC gui_text_formats[] =
{ "paste_warning", "Pasting $0 lines to $1. Press Ctrl-K if you wish to do this or Ctrl-C to cancel.", 2, { 1, 0 } },
{ "paste_prompt", "Hit Ctrl-K to paste, Ctrl-C to abort?", 0 },
+ /* ---- */
+ { NULL, "Welcome", 0 },
+
+ { "irssi_banner",
+ " ___ _%:"
+ "|_ _|_ _ _____(_)%:"
+ " | || '_(_-<_-< |%:"
+ "|___|_| /__/__/_|%:"
+ "Irssi v$J - http://www.irssi.org", 0 },
+ { "welcome_firsttime",
+ "- - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"
+ "Hi there! If this is your first time using Irssi, you%:"
+ "might want to go to our website and read the startup%:"
+ "documentation to get you going.%:%:"
+ "Our community and staff are available to assist you or%:"
+ "to answer any questions you may have.%:%:"
+ "Use the /HELP command to get detailed information about%:"
+ "the available commands.%:"
+ "- - - - - - - - - - - - - - - - - - - - - - - - - - - -", 0 },
+ { "welcome_init_settings", "The following settings were initialized", 0 },
+
{ NULL, NULL, 0 }
};
diff --git a/src/fe-text/module-formats.h b/src/fe-text/module-formats.h
index 3fa8c511..b753238b 100644
--- a/src/fe-text/module-formats.h
+++ b/src/fe-text/module-formats.h
@@ -26,6 +26,7 @@ enum {
TXT_WINDOW_INFO_SCROLL,
TXT_WINDOW_SCROLL,
TXT_WINDOW_SCROLL_UNKNOWN,
+ TXT_WINDOW_HIDELEVEL,
TXT_FILL_3,
@@ -52,6 +53,12 @@ enum {
TXT_PASTE_WARNING,
TXT_PASTE_PROMPT,
+ TXT_FILL_5, /* Welcome */
+
+ TXT_IRSSI_BANNER,
+ TXT_WELCOME_FIRSTTIME,
+ TXT_WELCOME_INIT_SETTINGS,
+
TXT_COUNT
};
diff --git a/src/fe-text/statusbar-items.c b/src/fe-text/statusbar-items.c
index de4499b4..5740a40b 100644
--- a/src/fe-text/statusbar-items.c
+++ b/src/fe-text/statusbar-items.c
@@ -369,8 +369,8 @@ static void item_lag(SBAR_ITEM_REC *item, int get_size_only)
last_lag_unknown = lag_unknown;
if (lag_unknown) {
- // "??)" in C becomes ']'
- // See: https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C
+ /* "??)" in C becomes ']'
+ See: https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C */
g_snprintf(str, sizeof(str), "%d (?""?)", lag / 100);
} else {
if (lag % 100 == 0)
@@ -418,7 +418,7 @@ static void item_input(SBAR_ITEM_REC *item, int get_size_only)
rec = g_hash_table_lookup(input_entries, item->bar->config->name);
if (rec == NULL) {
- rec = gui_entry_create(item->xpos, item->bar->real_ypos,
+ rec = gui_entry_create(ITEM_WINDOW_REAL_XPOS(item), item->bar->real_ypos,
item->size, term_type == TERM_TYPE_UTF8);
gui_entry_set_active(rec);
g_hash_table_insert(input_entries,
@@ -426,12 +426,21 @@ static void item_input(SBAR_ITEM_REC *item, int get_size_only)
}
if (get_size_only) {
- item->min_size = 2+term_width/10;
- item->max_size = term_width;
- return;
+ int max_width;
+ WINDOW_REC *window;
+
+ window = item->bar->parent_window != NULL
+ ? item->bar->parent_window->active
+ : NULL;
+
+ max_width = window != NULL ? window->width : term_width;
+
+ item->min_size = 2+max_width/10;
+ item->max_size = max_width;
+ return;
}
- gui_entry_move(rec, item->xpos, item->bar->real_ypos,
+ gui_entry_move(rec, ITEM_WINDOW_REAL_XPOS(item), item->bar->real_ypos,
item->size);
gui_entry_redraw(rec); /* FIXME: this is only necessary with ^L.. */
}
diff --git a/src/fe-text/statusbar.c b/src/fe-text/statusbar.c
index f0dff828..40837eea 100644
--- a/src/fe-text/statusbar.c
+++ b/src/fe-text/statusbar.c
@@ -242,17 +242,24 @@ static void statusbar_resize_items(STATUSBAR_REC *bar, int max_width)
static void statusbar_calc_item_positions(STATUSBAR_REC *bar)
{
- WINDOW_REC *old_active_win;
+ WINDOW_REC *window;
+ WINDOW_REC *old_active_win;
GSList *tmp, *right_items;
int xpos, rxpos;
+ int max_width;
old_active_win = active_win;
- if (bar->parent_window != NULL)
+ if (bar->parent_window != NULL)
active_win = bar->parent_window->active;
- statusbar_resize_items(bar, term_width);
+ window = bar->parent_window != NULL
+ ? bar->parent_window->active
+ : NULL;
+
+ max_width = window != NULL ? window->width : term_width;
+ statusbar_resize_items(bar, max_width);
- /* left-aligned items */
+ /* left-aligned items */
xpos = 0;
for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
SBAR_ITEM_REC *rec = tmp->data;
@@ -260,11 +267,11 @@ static void statusbar_calc_item_positions(STATUSBAR_REC *bar)
if (!rec->config->right_alignment &&
(rec->size > 0 || rec->current_size > 0)) {
if (SBAR_ITEM_REDRAW_NEEDED(bar, rec, xpos)) {
- /* redraw the item */
+ /* redraw the item */
rec->dirty = TRUE;
if (bar->dirty_xpos == -1 ||
xpos < bar->dirty_xpos) {
- irssi_set_dirty();
+ irssi_set_dirty();
bar->dirty = TRUE;
bar->dirty_xpos = xpos;
}
@@ -277,12 +284,12 @@ static void statusbar_calc_item_positions(STATUSBAR_REC *bar)
/* right-aligned items - first copy them to a new list backwards,
easier to draw them in right order */
- right_items = NULL;
+ right_items = NULL;
for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
SBAR_ITEM_REC *rec = tmp->data;
if (rec->config->right_alignment) {
- if (rec->size > 0)
+ if (rec->size > 0)
right_items = g_slist_prepend(right_items, rec);
else if (rec->current_size > 0 &&
(bar->dirty_xpos == -1 ||
@@ -291,12 +298,12 @@ static void statusbar_calc_item_positions(STATUSBAR_REC *bar)
to begin from the item's old xpos */
irssi_set_dirty();
bar->dirty = TRUE;
- bar->dirty_xpos = rec->xpos;
+ bar->dirty_xpos = rec->xpos;
}
}
}
- rxpos = term_width;
+ rxpos = max_width;
for (tmp = right_items; tmp != NULL; tmp = tmp->next) {
SBAR_ITEM_REC *rec = tmp->data;
@@ -312,7 +319,7 @@ static void statusbar_calc_item_positions(STATUSBAR_REC *bar)
rec->xpos = rxpos;
}
}
- g_slist_free(right_items);
+ g_slist_free(right_items);
active_win = old_active_win;
}
@@ -451,8 +458,13 @@ static void mainwindow_recalc_ypos(MAIN_WINDOW_REC *window, int placement)
static void sig_mainwindow_resized(MAIN_WINDOW_REC *window)
{
- mainwindow_recalc_ypos(window, STATUSBAR_TOP);
- mainwindow_recalc_ypos(window, STATUSBAR_BOTTOM);
+ GSList *tmp;
+ mainwindow_recalc_ypos(window, STATUSBAR_TOP);
+ mainwindow_recalc_ypos(window, STATUSBAR_BOTTOM);
+ for (tmp = window->statusbars; tmp != NULL; tmp = tmp->next) {
+ STATUSBAR_REC *bar = tmp->data;
+ statusbar_redraw(bar, TRUE);
+ }
}
STATUSBAR_REC *statusbar_create(STATUSBAR_GROUP_REC *group,
@@ -728,7 +740,7 @@ void statusbar_item_default_handler(SBAR_ITEM_REC *item, int get_size_only,
g_string_append_c(out, ' ');
}
- gui_printtext(item->xpos, item->bar->real_ypos, out->str);
+ gui_printtext(ITEM_WINDOW_REAL_XPOS(item), item->bar->real_ypos, out->str);
g_string_free(out, TRUE);
}
g_free(tmpstr);
@@ -960,20 +972,42 @@ void statusbar_item_destroy(SBAR_ITEM_REC *item)
g_free(item);
}
+static MAIN_WINDOW_BORDER_REC *set_border_info(STATUSBAR_REC *bar)
+{
+ MAIN_WINDOW_BORDER_REC *orig_border, *new_border;
+ orig_border = clrtoeol_info;
+ new_border = g_new0(MAIN_WINDOW_BORDER_REC, 1);
+ new_border->window = bar->parent_window != NULL ? bar->parent_window->screen_win : NULL;
+ new_border->color = bar->color;
+ clrtoeol_info = new_border;
+ return orig_border;
+}
+
+static void restore_border_info(MAIN_WINDOW_BORDER_REC *border_info)
+{
+ MAIN_WINDOW_BORDER_REC *old_border;
+ old_border = clrtoeol_info;
+ clrtoeol_info = border_info;
+ g_free(old_border);
+}
+
static void statusbar_redraw_needed_items(STATUSBAR_REC *bar)
{
- WINDOW_REC *old_active_win;
+ WINDOW_REC *old_active_win;
GSList *tmp;
char *str;
old_active_win = active_win;
- if (bar->parent_window != NULL)
+ if (bar->parent_window != NULL)
active_win = bar->parent_window->active;
if (bar->dirty_xpos >= 0) {
+ MAIN_WINDOW_BORDER_REC *orig_border;
+ orig_border = set_border_info(bar);
str = g_strconcat(bar->color, "%>", NULL);
- gui_printtext(bar->dirty_xpos, bar->real_ypos, str);
+ gui_printtext(BAR_WINDOW_REAL_DIRTY_XPOS(bar), bar->real_ypos, str);
g_free(str);
+ restore_border_info(orig_border);
}
for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
@@ -982,13 +1016,13 @@ static void statusbar_redraw_needed_items(STATUSBAR_REC *bar)
if (rec->dirty ||
(bar->dirty_xpos != -1 &&
rec->xpos >= bar->dirty_xpos)) {
- rec->current_size = rec->size;
+ rec->current_size = rec->size;
rec->func(rec, FALSE);
rec->dirty = FALSE;
}
}
- active_win = old_active_win;
+ active_win = old_active_win;
}
void statusbar_redraw_dirty(void)
diff --git a/src/fe-text/statusbar.h b/src/fe-text/statusbar.h
index 309294b0..b0048cc4 100644
--- a/src/fe-text/statusbar.h
+++ b/src/fe-text/statusbar.h
@@ -23,6 +23,12 @@ typedef struct SBAR_ITEM_REC SBAR_ITEM_REC;
#define STATUSBAR_VISIBLE_ACTIVE 2
#define STATUSBAR_VISIBLE_INACTIVE 3
+#define ITEM_WINDOW_REAL_XPOS(item) ( ( (item)->bar->parent_window != NULL ? \
+ (item)->bar->parent_window->first_column + (item)->bar->parent_window->statusbar_columns_left : 0 ) + (item)->xpos )
+
+#define BAR_WINDOW_REAL_DIRTY_XPOS(bar) ( ( (bar)->parent_window != NULL ? \
+ (bar)->parent_window->first_column + (bar)->parent_window->statusbar_columns_left : 0 ) + (bar)->dirty_xpos )
+
typedef struct {
char *name;
GSList *config_bars;
diff --git a/src/fe-text/term-terminfo.c b/src/fe-text/term-terminfo.c
index 6645cfb0..68947f0c 100644
--- a/src/fe-text/term-terminfo.c
+++ b/src/fe-text/term-terminfo.c
@@ -23,6 +23,7 @@
#include "term.h"
#include "terminfo-core.h"
#include "fe-windows.h"
+#include "gui-printtext.h"
#include "utf8.h"
#include <signal.h>
@@ -284,10 +285,10 @@ void term_window_clear(TERM_WINDOW *window)
{
int y;
- terminfo_set_normal();
- if (window->y == 0 && window->height == term_height) {
- term_clear();
- } else {
+ terminfo_set_normal();
+ if (window->y == 0 && window->height == term_height && window->width == term_width) {
+ term_clear();
+ } else {
for (y = 0; y < window->height; y++) {
term_move(window, 0, y);
term_clrtoeol(window);
@@ -452,14 +453,14 @@ void term_set_color(TERM_WINDOW *window, int col)
void term_move(TERM_WINDOW *window, int x, int y)
{
if (x >= 0 && y >= 0) {
- vcmove = TRUE;
- vcx = x+window->x;
- vcy = y+window->y;
-
- if (vcx >= term_width)
- vcx = term_width-1;
- if (vcy >= term_height)
- vcy = term_height-1;
+ vcmove = TRUE;
+ vcx = x+window->x;
+ vcy = y+window->y;
+
+ if (vcx >= term_width)
+ vcx = term_width-1;
+ if (vcy >= term_height)
+ vcy = term_height-1;
}
}
@@ -552,7 +553,7 @@ int term_addstr(TERM_WINDOW *window, const char *str)
while (*ptr != '\0') {
tmp = g_utf8_get_char_validated(ptr, -1);
/* On utf8 error, treat as single byte and try to
- continue interpretting rest of string as utf8 */
+ continue interpreting rest of string as utf8 */
if (tmp == (gunichar)-1 || tmp == (gunichar)-2) {
len++;
ptr++;
@@ -574,21 +575,52 @@ int term_addstr(TERM_WINDOW *window, const char *str)
void term_clrtoeol(TERM_WINDOW *window)
{
- /* clrtoeol() doesn't necessarily understand colors */
- if (last_fg == -1 && last_bg == -1 &&
- (last_attrs & (ATTR_UNDERLINE|ATTR_REVERSE|ATTR_ITALIC)) == 0) {
- if (!term_lines_empty[vcy]) {
- if (vcmove) term_move_real();
- terminfo_clrtoeol();
- if (vcx == 0) term_lines_empty[vcy] = TRUE;
- }
- } else if (vcx < term_width) {
- /* we'll need to fill the line ourself. */
+ if (vcx < window->x) {
+ /* we just wrapped outside of the split, warp the cursor back into the window */
+ vcx += window->x;
+ vcmove = TRUE;
+ }
+ if (window->x + window->width < term_width) {
+ /* we need to fill a vertical split */
if (vcmove) term_move_real();
- terminfo_repeat(' ', term_width-vcx);
+ terminfo_repeat(' ', window->x + window->width - vcx + 1);
terminfo_move(vcx, vcy);
- term_lines_empty[vcy] = FALSE;
+ term_lines_empty[vcy] = FALSE;
+ } else {
+ /* clrtoeol() doesn't necessarily understand colors */
+ if (last_fg == -1 && last_bg == -1 &&
+ (last_attrs & (ATTR_UNDERLINE|ATTR_REVERSE|ATTR_ITALIC)) == 0) {
+ if (!term_lines_empty[vcy]) {
+ if (vcmove) term_move_real();
+ terminfo_clrtoeol();
+ if (vcx == 0) term_lines_empty[vcy] = TRUE;
+ }
+ } else if (vcx < term_width) {
+ /* we'll need to fill the line ourself. */
+ if (vcmove) term_move_real();
+ terminfo_repeat(' ', term_width-vcx);
+ terminfo_move(vcx, vcy);
+ term_lines_empty[vcy] = FALSE;
+ }
+ }
+}
+
+void term_window_clrtoeol(TERM_WINDOW* window, int ypos)
+{
+ if (ypos >= 0 && window->y + ypos != vcy) {
+ /* the line is already full */
+ return;
}
+ term_clrtoeol(window);
+ if (window->x + window->width < term_width) {
+ gui_printtext_window_border(window->x + window->width, window->y + ypos);
+ term_set_color(window, ATTR_RESET);
+ }
+}
+
+void term_window_clrtoeol_abs(TERM_WINDOW* window, int ypos)
+{
+ term_window_clrtoeol(window, ypos - window->y);
}
void term_move_cursor(int x, int y)
@@ -733,3 +765,31 @@ void term_gets(GArray *buffer, int *line_count)
}
}
}
+
+static const char* term_env_warning =
+ "You seem to be running Irssi inside %2$s, but the TERM environment variable "
+ "is set to '%1$s', which can cause display glitches.\n"
+ "Consider changing TERM to '%2$s' or '%2$s-256color' instead.";
+
+void term_environment_check(void)
+{
+ const char *term, *sty, *tmux, *multiplexer;
+
+ term = g_getenv("TERM");
+ sty = g_getenv("STY");
+ tmux = g_getenv("TMUX");
+
+ multiplexer = (sty && *sty) ? "screen" :
+ (tmux && *tmux) ? "tmux" : NULL;
+
+ if (!multiplexer) {
+ return;
+ }
+
+ if (term && (g_str_has_prefix(term, "screen") ||
+ g_str_has_prefix(term, "tmux"))) {
+ return;
+ }
+
+ g_warning(term_env_warning, term, multiplexer);
+}
diff --git a/src/fe-text/term.h b/src/fe-text/term.h
index 0c7847f6..f25154c2 100644
--- a/src/fe-text/term.h
+++ b/src/fe-text/term.h
@@ -85,6 +85,8 @@ void term_addch(TERM_WINDOW *window, char chr);
void term_add_unichar(TERM_WINDOW *window, unichar chr);
int term_addstr(TERM_WINDOW *window, const char *str);
void term_clrtoeol(TERM_WINDOW *window);
+void term_window_clrtoeol(TERM_WINDOW* window, int ypos);
+void term_window_clrtoeol_abs(TERM_WINDOW* window, int ypos_abs);
void term_move_cursor(int x, int y);
@@ -105,4 +107,6 @@ void term_gets(GArray *buffer, int *line_count);
void term_common_init(void);
void term_common_deinit(void);
+void term_environment_check(void);
+
#endif
diff --git a/src/fe-text/textbuffer-commands.c b/src/fe-text/textbuffer-commands.c
index 648862e7..97d897f3 100644
--- a/src/fe-text/textbuffer-commands.c
+++ b/src/fe-text/textbuffer-commands.c
@@ -89,6 +89,25 @@ static void cmd_window_scroll(const char *data)
gui->scroll : settings_get_bool("scroll"));
}
+/* SYNTAX: WINDOW HIDELEVEL [<level>] */
+static void cmd_window_hidelevel(const char *data)
+{
+ GUI_WINDOW_REC *gui;
+ char *level;
+
+ g_return_if_fail(data != NULL);
+
+ gui = WINDOW_GUI(active_win);
+ textbuffer_view_set_hidden_level(gui->view,
+ combine_level(gui->view->hidden_level, data));
+ textbuffer_view_redraw(gui->view);
+ level = gui->view->hidden_level == 0 ? g_strdup("NONE") :
+ bits2level(gui->view->hidden_level);
+ printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
+ TXT_WINDOW_HIDELEVEL, level);
+ g_free(level);
+}
+
static void cmd_scrollback(const char *data, SERVER_REC *server,
WI_ITEM_REC *item)
{
@@ -358,6 +377,7 @@ void textbuffer_commands_init(void)
{
command_bind("clear", NULL, (SIGNAL_FUNC) cmd_clear);
command_bind("window scroll", NULL, (SIGNAL_FUNC) cmd_window_scroll);
+ command_bind("window hidelevel", NULL, (SIGNAL_FUNC) cmd_window_hidelevel);
command_bind("scrollback", NULL, (SIGNAL_FUNC) cmd_scrollback);
command_bind("scrollback clear", NULL, (SIGNAL_FUNC) cmd_scrollback_clear);
command_bind("scrollback levelclear", NULL, (SIGNAL_FUNC) cmd_scrollback_levelclear);
@@ -377,6 +397,7 @@ void textbuffer_commands_deinit(void)
{
command_unbind("clear", (SIGNAL_FUNC) cmd_clear);
command_unbind("window scroll", (SIGNAL_FUNC) cmd_window_scroll);
+ command_unbind("window hidelevel", (SIGNAL_FUNC) cmd_window_hidelevel);
command_unbind("scrollback", (SIGNAL_FUNC) cmd_scrollback);
command_unbind("scrollback clear", (SIGNAL_FUNC) cmd_scrollback_clear);
command_unbind("scrollback levelclear", (SIGNAL_FUNC) cmd_scrollback_levelclear);
diff --git a/src/fe-text/textbuffer-view.c b/src/fe-text/textbuffer-view.c
index cb066f5e..99625ecc 100644
--- a/src/fe-text/textbuffer-view.c
+++ b/src/fe-text/textbuffer-view.c
@@ -41,9 +41,15 @@ static GSList *views;
#define view_is_bottom(view) \
((view)->ypos >= -1 && (view)->ypos < (view)->height)
-#define view_get_linecount(view, line) \
+#define view_get_linecount_hidden(view, line) \
textbuffer_view_get_line_cache(view, line)->count
+#define view_line_is_hidden(view, line) \
+ (((line)->info.level & (view)->hidden_level) != 0)
+
+#define view_get_linecount(view, line) \
+ (view_line_is_hidden(view, line) ? 0 : view_get_linecount_hidden(view, line))
+
static GSList *textbuffer_get_views(TEXT_BUFFER_REC *buffer)
{
GSList *tmp, *list;
@@ -388,9 +394,9 @@ static void view_reset_cache(TEXT_BUFFER_VIEW_REC *view)
static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
int subline, int ypos, int max)
{
- INDENT_FUNC indent_func;
+ INDENT_FUNC indent_func;
LINE_CACHE_REC *cache;
- const unsigned char *text, *end, *text_newline;
+ const unsigned char *text, *end, *text_newline;
unsigned char *tmp;
unichar chr;
int xpos, color, drawcount, first, need_move, need_clrtoeol, char_width;
@@ -399,54 +405,54 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
#endif
if (view->dirty) /* don't bother drawing anything - redraw is coming */
- return 0;
+ return 0;
cache = textbuffer_view_get_line_cache(view, line);
if (subline >= cache->count)
- return 0;
+ return 0;
- color = ATTR_RESET;
- need_move = TRUE; need_clrtoeol = FALSE;
+ color = ATTR_RESET;
+ need_move = TRUE; need_clrtoeol = FALSE;
xpos = drawcount = 0; first = TRUE;
text_newline = text =
subline == 0 ? line->text : cache->lines[subline-1].start;
for (;;) {
if (text == text_newline) {
- if (need_clrtoeol && xpos < term_width) {
+ if (need_clrtoeol && xpos < view->width + (view->width == term_width ? 0 : 1)) {
term_set_color(view->window, ATTR_RESET);
- term_clrtoeol(view->window);
+ term_window_clrtoeol(view->window, ypos);
}
if (first)
first = FALSE;
else {
ypos++;
- if (--max == 0)
+ if (--max == 0)
break;
}
if (subline > 0) {
- /* continuing previous line - indent it */
+ /* continuing previous line - indent it */
indent_func = cache->lines[subline-1].indent_func;
if (indent_func == NULL)
xpos = cache->lines[subline-1].indent;
- color = cache->lines[subline-1].color;
+ color = cache->lines[subline-1].color;
#ifdef TERM_TRUECOLOR
- fg24 = cache->lines[subline-1].fg24;
- bg24 = cache->lines[subline-1].bg24;
+ fg24 = cache->lines[subline-1].fg24;
+ bg24 = cache->lines[subline-1].bg24;
#endif
} else {
indent_func = NULL;
}
if (xpos == 0 && indent_func == NULL)
- need_clrtoeol = TRUE;
+ need_clrtoeol = TRUE;
else {
/* line was indented - need to clear the
- indented area first */
+ indented area first */
term_set_color(view->window, ATTR_RESET);
term_move(view->window, 0, ypos);
- term_clrtoeol(view->window);
+ term_window_clrtoeol(view->window, ypos);
if (indent_func != NULL)
xpos = indent_func(view, line, ypos);
@@ -463,9 +469,17 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
} else {
/* get the beginning of the next subline */
text_newline = cache->lines[subline].start;
- need_move = !cache->lines[subline].continues;
+ if (view->width == term_width) {
+ /* ensure that links / long words are not broken */
+ need_move = !cache->lines[subline].continues;
+ } else {
+ /* we cannot use the need_move
+ optimisation unless the split spans
+ the whole width */
+ need_move = TRUE;
+ }
}
- drawcount++;
+ drawcount++;
subline++;
}
@@ -473,10 +487,10 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
/* command */
text++;
if (*text == LINE_CMD_EOL)
- break;
+ break;
if (*text == LINE_CMD_CONTINUE) {
- /* jump to next block */
+ /* jump to next block */
memcpy(&tmp, text+1, sizeof(unsigned char *));
text = tmp;
continue;
@@ -511,13 +525,13 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
}
xpos += char_width;
- if (xpos <= term_width) {
+ if (xpos <= view->width) {
if (unichar_isprint(chr)) {
if (view->utf8)
- term_add_unichar(view->window, chr);
+ term_add_unichar(view->window, chr);
else
- for (; text < end; text++)
- term_addch(view->window, *text);
+ for (; text < end; text++)
+ term_addch(view->window, *text);
} else {
/* low-ascii */
term_set_color(view->window, ATTR_RESET|ATTR_REVERSE);
@@ -528,12 +542,12 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
text = end;
}
- if (need_clrtoeol && xpos < term_width) {
+ if (need_clrtoeol && xpos < view->width + (view->width == term_width ? 0 : 1)) {
term_set_color(view->window, ATTR_RESET);
- term_clrtoeol(view->window);
+ term_window_clrtoeol(view->window, ypos);
}
- return drawcount;
+ return drawcount;
}
/* Recalculate view's bottom line information - try to keep the
@@ -552,6 +566,9 @@ static void textbuffer_view_init_bottom(TEXT_BUFFER_VIEW_REC *view)
total = 0;
line = textbuffer_line_last(view->buffer);
for (; line != NULL; line = line->prev) {
+ if (view_line_is_hidden(view, line))
+ continue;
+
linecount = view_get_linecount(view, line);
if (line == view->bottom_startline) {
/* keep the old one, make sure that subline is ok */
@@ -614,6 +631,8 @@ TEXT_BUFFER_VIEW_REC *textbuffer_view_create(TEXT_BUFFER_REC *buffer,
view->subline = view->bottom_subline;
view->bottom = TRUE;
+ view->hidden_level = 0;
+
textbuffer_view_init_ypos(view);
view->bookmarks = g_hash_table_new((GHashFunc) g_str_hash,
@@ -726,8 +745,10 @@ static void view_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
return;
while (line != NULL && lines > 0) {
- linecount = view_line_draw(view, line, subline, ypos, lines);
- ypos += linecount; lines -= linecount;
+ if (!view_line_is_hidden(view, line)) {
+ linecount = view_line_draw(view, line, subline, ypos, lines);
+ ypos += linecount; lines -= linecount;
+ }
subline = 0;
line = line->next;
@@ -738,7 +759,7 @@ static void view_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
term_set_color(view->window, ATTR_RESET);
while (lines > 0) {
term_move(view->window, 0, ypos);
- term_clrtoeol(view->window);
+ term_window_clrtoeol(view->window, ypos);
ypos++; lines--;
}
}
@@ -768,58 +789,63 @@ static void view_draw_bottom(TEXT_BUFFER_VIEW_REC *view, int lines)
view_draw(view, line, subline, maxline, lines, TRUE);
}
-/* Returns number of lines actually scrolled */
+/* lines: this pointer is scrolled by scrollcount screen lines
+ subline: this pointer contains the subline position
+ scrollcount: the number of lines to scroll down (negative: up)
+ draw_nonclean: whether to redraw the screen now
+
+ Returns number of lines actually scrolled */
static int view_scroll(TEXT_BUFFER_VIEW_REC *view, LINE_REC **lines,
int *subline, int scrollcount, int draw_nonclean)
{
int linecount, realcount, scroll_visible;
if (*lines == NULL)
- return 0;
+ return 0;
/* scroll down */
scroll_visible = lines == &view->startline;
realcount = -*subline;
scrollcount += *subline;
- *subline = 0;
+ *subline = 0;
while (scrollcount > 0) {
linecount = view_get_linecount(view, *lines);
if ((scroll_visible && *lines == view->bottom_startline) &&
(scrollcount >= view->bottom_subline)) {
*subline = view->bottom_subline;
- realcount += view->bottom_subline;
- scrollcount = 0;
- break;
+ realcount += view->bottom_subline;
+ scrollcount = 0;
+ break;
}
- realcount += linecount;
+ realcount += linecount;
scrollcount -= linecount;
if (scrollcount < 0) {
- realcount += scrollcount;
+ realcount += scrollcount;
*subline = linecount+scrollcount;
- scrollcount = 0;
- break;
+ scrollcount = 0;
+ break;
}
if ((*lines)->next == NULL)
break;
- *lines = (*lines)->next;
+ *lines = (*lines)->next;
}
- /* scroll up */
+ /* scroll up */
while (scrollcount < 0 && (*lines)->prev != NULL) {
*lines = (*lines)->prev;
linecount = view_get_linecount(view, *lines);
- realcount -= linecount;
+ realcount -= linecount;
scrollcount += linecount;
if (scrollcount > 0) {
- realcount += scrollcount;
+ realcount += scrollcount;
*subline = scrollcount;
- break;
+ break;
}
}
@@ -827,19 +853,28 @@ static int view_scroll(TEXT_BUFFER_VIEW_REC *view, LINE_REC **lines,
if (realcount <= -view->height || realcount >= view->height) {
/* scrolled more than screenful, redraw the
whole view */
- textbuffer_view_redraw(view);
+ textbuffer_view_redraw(view);
} else {
- term_set_color(view->window, ATTR_RESET);
- term_window_scroll(view->window, realcount);
+ if (view->width == term_width) {
+ /* we can try to use vt100 scroll regions */
+ term_set_color(view->window, ATTR_RESET);
+ term_window_scroll(view->window, realcount);
- if (draw_nonclean) {
- if (realcount < 0)
- view_draw_top(view, -realcount, TRUE);
- else
- view_draw_bottom(view, realcount);
- }
+ if (draw_nonclean) {
+ if (realcount < 0)
+ view_draw_top(view, -realcount, TRUE);
+ else
+ view_draw_bottom(view, realcount);
+ }
- term_refresh(view->window);
+ term_refresh(view->window);
+ } else {
+ /* do not bother with vt400 scroll
+ rectangles for now, redraw the
+ whole view */
+ view->dirty = TRUE;
+ irssi_set_dirty();
+ }
}
}
@@ -1027,7 +1062,7 @@ static void view_insert_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
view->bottom = view_is_bottom(view);
}
- if (view->window != NULL) {
+ if (view->window != NULL && !view_line_is_hidden(view, line)) {
ypos = view->ypos+1 - view_get_linecount(view, line);
if (ypos >= 0)
subline = 0;
@@ -1042,7 +1077,7 @@ static void view_insert_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
}
}
- if (view->window != NULL)
+ if (view->window != NULL && !view_line_is_hidden(view, line))
term_refresh(view->window);
}
@@ -1122,6 +1157,12 @@ static int view_get_lines_height(TEXT_BUFFER_VIEW_REC *view,
return height < view->height ? height : view->height;
}
+/* line: line to remove
+ linecount: linecount of that line, to be offset when the line was in/below view
+
+ scroll the window maintaining the startline while removing line
+ if startline is removed, make the previous line the new startline
+*/
static void view_remove_line_update_startline(TEXT_BUFFER_VIEW_REC *view,
LINE_REC *line, int linecount)
{
@@ -1318,6 +1359,37 @@ LINE_REC *textbuffer_view_get_bookmark(TEXT_BUFFER_VIEW_REC *view,
return g_hash_table_lookup(view->bookmarks, name);
}
+void textbuffer_view_set_hidden_level(TEXT_BUFFER_VIEW_REC *view, int level)
+{
+ g_return_if_fail(view != NULL);
+
+ if (view->hidden_level != level) {
+ if (view->empty_linecount > 0 && view->startline != NULL) {
+ int old_height, new_height;
+ LINE_REC *hidden_start;
+
+ hidden_start = view->startline;
+ while (hidden_start->prev != NULL && view_line_is_hidden(view, hidden_start->prev)) {
+ hidden_start = hidden_start->prev;
+ }
+
+ old_height = view_get_lines_height(view, hidden_start, view->subline, NULL);
+ view->hidden_level = level;
+ new_height = view_get_lines_height(view, hidden_start, view->subline, NULL);
+
+ view->empty_linecount -= new_height - old_height;
+
+ if (view->empty_linecount < 0)
+ view->empty_linecount = 0;
+ else if (view->empty_linecount > view->height)
+ view->empty_linecount = view->height;
+ } else {
+ view->hidden_level = level;
+ }
+ textbuffer_view_resize(view, view->width, view->height);
+ }
+}
+
/* Specify window where the changes in view should be drawn,
NULL disables it. */
void textbuffer_view_set_window(TEXT_BUFFER_VIEW_REC *view,
diff --git a/src/fe-text/textbuffer-view.h b/src/fe-text/textbuffer-view.h
index 5e7a9d0a..a670df2b 100644
--- a/src/fe-text/textbuffer-view.h
+++ b/src/fe-text/textbuffer-view.h
@@ -49,41 +49,51 @@ typedef struct {
struct _TEXT_BUFFER_VIEW_REC {
TEXT_BUFFER_REC *buffer;
- GSList *siblings; /* other views that use the same buffer */
+ /* other views that use the same buffer */
+ GSList *siblings;
TERM_WINDOW *window;
int width, height;
int default_indent;
INDENT_FUNC default_indent_func;
- unsigned int longword_noindent:1;
- unsigned int scroll:1; /* scroll down automatically when at bottom */
- unsigned int utf8:1; /* use UTF8 in this view */
- unsigned int break_wide:1; /* Break wide chars in this view */
TEXT_BUFFER_CACHE_REC *cache;
- int ypos; /* cursor position - visible area is 0..height-1 */
+ /* cursor position - visible area is 0..height-1 */
+ int ypos;
- LINE_REC *startline; /* line at the top of the screen */
- int subline; /* number of "real lines" to skip from `startline' */
+ /* line at the top of the screen */
+ LINE_REC *startline;
+ /* number of "real lines" to skip from `startline' */
+ int subline;
/* marks the bottom of the text buffer */
LINE_REC *bottom_startline;
int bottom_subline;
+ /* Bookmarks to the lines in the buffer - removed automatically
+ when the line gets removed from buffer */
+ GHashTable *bookmarks;
+
+ /* these levels should be hidden */
+ int hidden_level;
/* how many empty lines are in screen. a screenful when started
or used /CLEAR */
int empty_linecount;
+
+ unsigned int longword_noindent:1;
+ /* scroll down automatically when at bottom */
+ unsigned int scroll:1;
+ /* use UTF8 in this view */
+ unsigned int utf8:1;
+ /* Break wide chars in this view */
+ unsigned int break_wide:1;
/* window is at the bottom of the text buffer */
unsigned int bottom:1;
/* if !bottom - new text has been printed since we were at bottom */
unsigned int more_text:1;
/* Window needs a redraw */
unsigned int dirty:1;
-
- /* Bookmarks to the lines in the buffer - removed automatically
- when the line gets removed from buffer */
- GHashTable *bookmarks;
};
/* Create new view. */
@@ -143,6 +153,8 @@ void textbuffer_view_set_bookmark_bottom(TEXT_BUFFER_VIEW_REC *view,
/* Return the line for bookmark */
LINE_REC *textbuffer_view_get_bookmark(TEXT_BUFFER_VIEW_REC *view,
const char *name);
+/* Set hidden level for view */
+void textbuffer_view_set_hidden_level(TEXT_BUFFER_VIEW_REC *view, int level);
/* Specify window where the changes in view should be drawn,
NULL disables it. */
diff --git a/src/fe-text/textbuffer.c b/src/fe-text/textbuffer.c
index a920fab2..01cdd118 100644
--- a/src/fe-text/textbuffer.c
+++ b/src/fe-text/textbuffer.c
@@ -230,6 +230,7 @@ LINE_REC *textbuffer_line_last(TEXT_BUFFER_REC *buffer)
return buffer->cur_line;
}
+/* returns TRUE if `search' comes on or after `line' in the buffer */
int textbuffer_line_exists_after(LINE_REC *line, LINE_REC *search)
{
while (line != NULL) {
diff --git a/src/fe-text/textbuffer.h b/src/fe-text/textbuffer.h
index 303789a3..2aa22f1a 100644
--- a/src/fe-text/textbuffer.h
+++ b/src/fe-text/textbuffer.h
@@ -65,10 +65,10 @@ typedef struct {
LINE_REC *cur_line;
TEXT_CHUNK_REC *cur_text;
- unsigned int last_eol:1;
int last_fg;
int last_bg;
int last_flags;
+ unsigned int last_eol:1;
} TEXT_BUFFER_REC;
/* Create new buffer */
diff --git a/src/irc/core/channel-events.c b/src/irc/core/channel-events.c
index b0bddab2..46bbd5fa 100644
--- a/src/irc/core/channel-events.c
+++ b/src/irc/core/channel-events.c
@@ -138,7 +138,13 @@ static void channel_change_topic(IRC_SERVER_REC *server, const char *channel,
g_free_not_null(chanrec->topic_by);
chanrec->topic_by = g_strdup(setby);
- chanrec->topic_time = settime;
+ if (chanrec->topic_by == NULL) {
+ /* ensure invariant topic_time > 0 <=> topic_by != NULL.
+ this could be triggered by a topic command without sender */
+ chanrec->topic_time = 0;
+ } else {
+ chanrec->topic_time = settime;
+ }
signal_emit("channel topic changed", 1, chanrec);
}
diff --git a/src/irc/core/irc-nicklist.c b/src/irc/core/irc-nicklist.c
index 1cb1f3e9..3e16db80 100644
--- a/src/irc/core/irc-nicklist.c
+++ b/src/irc/core/irc-nicklist.c
@@ -323,8 +323,9 @@ static void event_nick_invalid(IRC_SERVER_REC *server, const char *data)
static void event_nick_in_use(IRC_SERVER_REC *server, const char *data)
{
- char *str, *cmd;
+ char *str, *cmd, *params, *nick;
int n;
+ gboolean try_alternate_nick;
g_return_if_fail(data != NULL);
@@ -332,11 +333,21 @@ static void event_nick_in_use(IRC_SERVER_REC *server, const char *data)
/* Already connected, no need to handle this anymore. */
return;
}
+
+ try_alternate_nick = g_ascii_strcasecmp(server->nick, server->connrec->nick) == 0 &&
+ server->connrec->alternate_nick != NULL &&
+ g_ascii_strcasecmp(server->connrec->alternate_nick, server->nick) != 0;
+
+ params = event_get_params(data, 2, NULL, &nick);
+ if (g_ascii_strcasecmp(server->nick, nick) != 0) {
+ /* the server uses a nick different from the one we send */
+ g_free(server->nick);
+ server->nick = g_strdup(nick);
+ }
+ g_free(params);
/* nick already in use - need to change it .. */
- if (g_ascii_strcasecmp(server->nick, server->connrec->nick) == 0 &&
- server->connrec->alternate_nick != NULL &&
- g_ascii_strcasecmp(server->connrec->alternate_nick, server->nick) != 0) {
+ if (try_alternate_nick) {
/* first try, so try the alternative nick.. */
g_free(server->nick);
server->nick = g_strdup(server->connrec->alternate_nick);
diff --git a/src/irc/core/irc-servers-setup.c b/src/irc/core/irc-servers-setup.c
index bae7d3b4..e79557ab 100644
--- a/src/irc/core/irc-servers-setup.c
+++ b/src/irc/core/irc-servers-setup.c
@@ -116,14 +116,17 @@ static void sig_server_setup_fill_chatnet(IRC_SERVER_CONNECT_REC *conn,
static void init_userinfo(void)
{
+ unsigned int changed;
const char *set, *nick, *user_name, *str;
+ changed = 0;
/* check if nick/username/realname wasn't read from setup.. */
set = settings_get_str("real_name");
if (set == NULL || *set == '\0') {
str = g_getenv("IRCNAME");
settings_set_str("real_name",
str != NULL ? str : g_get_real_name());
+ changed |= USER_SETTINGS_REAL_NAME;
}
/* username */
@@ -134,6 +137,7 @@ static void init_userinfo(void)
str != NULL ? str : g_get_user_name());
user_name = settings_get_str("user_name");
+ changed |= USER_SETTINGS_USER_NAME;
}
/* nick */
@@ -143,15 +147,20 @@ static void init_userinfo(void)
settings_set_str("nick", str != NULL ? str : user_name);
nick = settings_get_str("nick");
+ changed |= USER_SETTINGS_NICK;
}
/* host name */
set = settings_get_str("hostname");
if (set == NULL || *set == '\0') {
str = g_getenv("IRCHOST");
- if (str != NULL)
+ if (str != NULL) {
settings_set_str("hostname", str);
+ changed |= USER_SETTINGS_HOSTNAME;
+ }
}
+
+ signal_emit("irssi init userinfo changed", 1, GUINT_TO_POINTER(changed));
}
static void sig_server_setup_read(IRC_SERVER_SETUP_REC *rec, CONFIG_NODE *node)
diff --git a/src/irc/core/irc.c b/src/irc/core/irc.c
index 4dce3fcf..a740b0da 100644
--- a/src/irc/core/irc.c
+++ b/src/irc/core/irc.c
@@ -40,6 +40,8 @@ static int signal_server_incoming;
# define MAX_SOCKET_READS 5
#endif
+static void strip_params_colon(char *const);
+
/* The core of the irc_send_cmd* functions. If `raw' is TRUE, the `cmd'
won't be checked at all if it's 512 bytes or not, or if it contains
line feeds or not. Use with extreme caution! */
@@ -269,8 +271,9 @@ char *event_get_params(const char *data, int count, ...)
while (count-- > 0) {
str = (char **) va_arg(args, char **);
if (count == 0 && rest) {
- /* put the rest to last parameter */
- tmp = *datad == ':' ? datad+1 : datad;
+ /* Put the rest into the last parameter. */
+ strip_params_colon(datad);
+ tmp = datad;
} else {
tmp = event_get_param(&datad);
}
@@ -281,6 +284,33 @@ char *event_get_params(const char *data, int count, ...)
return duprec;
}
+/* Given a string containing <params>, strip any colon prefixing <trailing>. */
+static void strip_params_colon(char *const params)
+{
+ char *s;
+
+ if (params == NULL) {
+ return;
+ }
+
+ s = params;
+ while (*s != '\0') {
+ if (*s == ':') {
+ memmove(s, s+1, strlen(s+1)+1);
+ return;
+ }
+
+ s = strchr(s, ' ');
+ if (s == NULL) {
+ return;
+ }
+
+ while (*s == ' ') {
+ s++;
+ }
+ }
+}
+
static void irc_server_event(IRC_SERVER_REC *server, const char *line,
const char *nick, const char *address)
{
diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c
index 635b7dfb..2b589579 100644
--- a/src/irc/core/sasl.c
+++ b/src/irc/core/sasl.c
@@ -30,16 +30,16 @@
* Based on IRCv3 SASL Extension Specification:
* http://ircv3.net/specs/extensions/sasl-3.1.html
*/
-#define AUTHENTICATE_CHUNK_SIZE 400 // bytes
+#define AUTHENTICATE_CHUNK_SIZE 400 /* bytes */
/*
* Maximum size to allow the buffer to grow to before the next fragment comes in. Note that
* due to the way fragmentation works, the maximum message size will actually be:
* floor(AUTHENTICATE_MAX_SIZE / AUTHENTICATE_CHUNK_SIZE) + AUTHENTICATE_CHUNK_SIZE - 1
*/
-#define AUTHENTICATE_MAX_SIZE 8192 // bytes
+#define AUTHENTICATE_MAX_SIZE 8192 /* bytes */
-#define SASL_TIMEOUT (20 * 1000) // ms
+#define SASL_TIMEOUT (20 * 1000) /* ms */
static gboolean sasl_timeout(IRC_SERVER_REC *server)
{
diff --git a/src/perl/Makefile.am b/src/perl/Makefile.am
index 427c5492..db52744e 100644
--- a/src/perl/Makefile.am
+++ b/src/perl/Makefile.am
@@ -59,7 +59,7 @@ perl-signals-list.h: $(top_srcdir)/docs/signals.txt $(srcdir)/get-signals.pl
cat $(top_srcdir)/docs/signals.txt | $(perlpath) $(srcdir)/get-signals.pl > perl-signals-list.h
irssi-core.pl.h: irssi-core.pl
- $(top_srcdir)/file2header.sh $(srcdir)/irssi-core.pl irssi_core_code > irssi-core.pl.h
+ $(top_srcdir)/utils/file2header.sh $(srcdir)/irssi-core.pl irssi_core_code > irssi-core.pl.h
common_sources = \
common/Irssi.xs \
diff --git a/src/perl/common/Expando.xs b/src/perl/common/Expando.xs
index 26800b05..84853a02 100644
--- a/src/perl/common/Expando.xs
+++ b/src/perl/common/Expando.xs
@@ -74,6 +74,7 @@ static char *perl_expando_event(PerlExpando *rec, SERVER_REC *server,
ret = NULL;
if (SvTRUE(ERRSV)) {
+ char *error;
PERL_SCRIPT_REC *script = rec->script;
(void) POPs;
@@ -85,7 +86,7 @@ static char *perl_expando_event(PerlExpando *rec, SERVER_REC *server,
script_unregister_expandos(script);
/* rec has been freed now */
- char *error = g_strdup(SvPV_nolen(ERRSV));
+ error = g_strdup(SvPV_nolen(ERRSV));
signal_emit("script error", 2, script, error);
g_free(error);
} else if (retcount > 0) {
diff --git a/src/perl/textui/Statusbar.xs b/src/perl/textui/Statusbar.xs
index 8b0e5f65..111deaa7 100644
--- a/src/perl/textui/Statusbar.xs
+++ b/src/perl/textui/Statusbar.xs
@@ -67,7 +67,7 @@ static void perl_statusbar_event(char *function, SBAR_ITEM_REC *item,
if (SvTRUE(ERRSV)) {
PERL_SCRIPT_REC *script;
- char *package;
+ char *package, *error;
package = perl_function_get_package(function);
script = perl_script_find_package(package);
@@ -78,7 +78,7 @@ static void perl_statusbar_event(char *function, SBAR_ITEM_REC *item,
script_unregister_statusbars(script);
}
- char *error = g_strdup(SvPV_nolen(ERRSV));
+ error = g_strdup(SvPV_nolen(ERRSV));
signal_emit("script error", 2, script, error);
g_free(error);
} else {
diff --git a/src/perl/textui/TextUI.xs b/src/perl/textui/TextUI.xs
index 5d2c8a7f..12732e3f 100644
--- a/src/perl/textui/TextUI.xs
+++ b/src/perl/textui/TextUI.xs
@@ -40,6 +40,7 @@ static void perl_text_buffer_view_fill_hash(HV *hv, TEXT_BUFFER_VIEW_REC *view)
(void) hv_store(hv, "startline", 9, plain_bless(view->startline, "Irssi::TextUI::Line"), 0);
(void) hv_store(hv, "subline", 7, newSViv(view->subline), 0);
+ (void) hv_store(hv, "hidden_level", 12, newSViv(view->hidden_level), 0);
(void) hv_store(hv, "bottom_startline", 16, plain_bless(view->bottom_startline, "Irssi::TextUI::Line"), 0);
(void) hv_store(hv, "bottom_subline", 14, newSViv(view->bottom_subline), 0);
diff --git a/src/perl/ui/Window.xs b/src/perl/ui/Window.xs
index 8c994cc2..85e284bb 100644
--- a/src/perl/ui/Window.xs
+++ b/src/perl/ui/Window.xs
@@ -252,8 +252,148 @@ PREINIT:
GList *tmp;
PPCODE:
rec = command_history_current(window);
- for (tmp = rec->list; tmp != NULL; tmp = tmp->next)
- XPUSHs(sv_2mortal(new_pv(tmp->data)));
+ for (tmp = command_history_list_first(rec); tmp != NULL; tmp = command_history_list_next(rec, tmp))
+ XPUSHs(sv_2mortal(new_pv(((HISTORY_ENTRY_REC *)tmp->data)->text)));
+
+void
+window_get_history_entries(window)
+ Irssi::UI::Window window
+PREINIT:
+ HISTORY_REC *rec;
+ HISTORY_ENTRY_REC *ent;
+ WINDOW_REC *win;
+ GList *tmp;
+ GSList *stmp;
+ HV *hv;
+PPCODE:
+ rec = window == NULL ? NULL : command_history_current(window);
+ for (tmp = command_history_list_first(rec); tmp != NULL; tmp = command_history_list_next(rec, tmp)) {
+ hv = (HV*)sv_2mortal((SV*)newHV());
+ ent = tmp->data;
+ hv_store(hv, "text", 4, newSVpv(ent->text, 0), 0);
+ hv_store(hv, "time", 4, newSViv(ent->time), 0);
+ if (ent->history == command_history_current(NULL)) {
+ hv_store(hv, "history", 7, newSV(0), 0);
+ hv_store(hv, "window", 6, newSV(0), 0);
+ } else {
+ if (ent->history->name == NULL) {
+ hv_store(hv, "history", 7, newSV(0), 0);
+ for (stmp = windows; stmp != NULL; stmp = stmp->next) {
+ win = stmp->data;
+ if (win->history == ent->history) {
+ hv_store(hv, "window", 6, newSViv(win->refnum), 0);
+ break;
+ }
+ }
+ } else {
+ hv_store(hv, "history", 7, new_pv(ent->history->name), 0);
+ hv_store(hv, "window", 6, newSV(0), 0);
+ }
+ }
+ XPUSHs(sv_2mortal(newRV_inc((SV*)hv)));
+ }
+
+void
+window_load_history_entries(window, ...)
+ Irssi::UI::Window window
+PREINIT:
+ HV *hv;
+ SV **sv;
+ HISTORY_REC *history;
+ WINDOW_REC *tmp;
+ const char *text;
+ long hist_time;
+ int i;
+PPCODE:
+ for (i = 1; i < items; i++) {
+ if (!is_hvref(ST(i))) {
+ croak("Usage: Irssi::UI::Window::load_history_entries(window, hash...)");
+ }
+ hv = hvref(ST(i));
+ if (hv != NULL) {
+ tmp = NULL;
+ text = NULL;
+ hist_time = time(NULL);
+ history = command_history_current(NULL);
+
+ sv = hv_fetch(hv, "text", 4, 0);
+ if (sv != NULL) text = SvPV_nolen(*sv);
+ sv = hv_fetch(hv, "time", 4, 0);
+ if (sv != NULL && SvOK(*sv)) hist_time = SvIV(*sv);
+
+ if (window != NULL) {
+ history = command_history_current(window);
+ } else {
+ sv = hv_fetch(hv, "history", 7, 0);
+ if (sv != NULL && SvOK(*sv)) {
+ history = command_history_find_name(SvPV_nolen(*sv));
+ }
+
+ sv = hv_fetch(hv, "window", 6, 0);
+ if (sv != NULL && SvOK(*sv)) {
+ tmp = window_find_refnum(SvIV(*sv));
+ if (tmp != NULL) {
+ history = tmp->history;
+ }
+ }
+ }
+
+ if (text != NULL && history != NULL) {
+ command_history_load_entry(hist_time, history, text);
+ }
+ }
+ }
+
+void
+window_delete_history_entries(window, ...)
+ Irssi::UI::Window window
+PREINIT:
+ HV *hv;
+ SV **sv;
+ HISTORY_REC *history;
+ WINDOW_REC *tmp;
+ const char *text;
+ long hist_time;
+ int i;
+PPCODE:
+ for (i = 1; i < items; i++) {
+ if (!is_hvref(ST(i))) {
+ croak("Usage: Irssi::UI::Window::delete_history_entries(window, hash...)");
+ }
+ hv = hvref(ST(i));
+ if (hv != NULL) {
+ tmp = NULL;
+ text = NULL;
+ hist_time = -1;
+ history = command_history_current(NULL);
+
+ sv = hv_fetch(hv, "text", 4, 0);
+ if (sv != NULL) text = SvPV_nolen(*sv);
+ sv = hv_fetch(hv, "time", 4, 0);
+ if (sv != NULL && SvOK(*sv)) hist_time = SvIV(*sv);
+
+ if (window != NULL) {
+ history = command_history_current(window);
+ } else {
+ sv = hv_fetch(hv, "history", 7, 0);
+ if (sv != NULL && SvOK(*sv)) {
+ history = command_history_find_name(SvPV_nolen(*sv));
+ }
+
+ sv = hv_fetch(hv, "window", 6, 0);
+ if (sv != NULL && SvOK(*sv)) {
+ tmp = window_find_refnum(SvIV(*sv));
+ if (tmp != NULL) {
+ history = tmp->history;
+ }
+ }
+ }
+
+ if (text != NULL && history != NULL) {
+ XPUSHs(boolSV(command_history_delete_entry(hist_time, history, text)));
+ }
+ }
+ }
#*******************************
MODULE = Irssi::UI::Window PACKAGE = Irssi::Windowitem PREFIX = window_item_