summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--NEWS81
-rw-r--r--README.md2
-rw-r--r--configure.ac4
-rw-r--r--docs/help/in/hash.in2
-rw-r--r--docs/help/in/help.in2
-rw-r--r--docs/help/in/ison.in2
-rw-r--r--docs/help/in/window.in15
-rw-r--r--docs/irssi.12
-rw-r--r--docs/manual.txt2
-rw-r--r--irssi.conf4
-rw-r--r--src/common.h2
-rw-r--r--src/core/network-openssl.c20
-rw-r--r--src/fe-common/core/chat-completion.c55
-rw-r--r--src/fe-common/core/fe-common-core.c51
-rw-r--r--src/fe-common/core/fe-windows.h8
-rw-r--r--src/fe-common/core/formats.c27
-rw-r--r--src/fe-common/core/themes.c2
-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-netjoin.c19
-rw-r--r--src/fe-common/irc/fe-netsplit.c22
-rw-r--r--src/fe-fuzz/Makefile.am2
-rw-r--r--src/fe-fuzz/fe-common/Makefile.am1
-rw-r--r--src/fe-fuzz/fe-common/core/Makefile.am46
-rw-r--r--src/fe-fuzz/fe-common/core/theme-load.c66
-rw-r--r--src/fe-fuzz/irc/Makefile.am1
-rw-r--r--src/fe-fuzz/irc/core/Makefile.am46
-rw-r--r--src/fe-fuzz/irc/core/event-get-params.c82
-rw-r--r--src/fe-text/gui-entry.c596
-rw-r--r--src/fe-text/gui-entry.h11
-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.c3
-rw-r--r--src/fe-text/gui-windows.c14
-rw-r--r--src/fe-text/irssi.c4
-rw-r--r--src/fe-text/mainwindows-layout.c159
-rw-r--r--src/fe-text/mainwindows.c1209
-rw-r--r--src/fe-text/mainwindows.h22
-rw-r--r--src/fe-text/module-formats.c6
-rw-r--r--src/fe-text/statusbar-items.c19
-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-view.c121
-rw-r--r--src/perl/textui/TextUI.xs69
-rw-r--r--tests/fe-common/core/Makefile.am3
-rw-r--r--tests/fe-common/core/test-formats.c4
-rw-r--r--tests/irc/core/Makefile.am3
-rw-r--r--tests/irc/core/test-irc.c2
-rw-r--r--themes/default.theme1
-rwxr-xr-xutils/tap-test20
53 files changed, 2573 insertions, 506 deletions
diff --git a/.gitignore b/.gitignore
index cf1cf72e..916457f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,8 @@ docs/help/in/Makefile.am
src/fe-text/irssi
src/fe-fuzz/irssi-fuzz
+src/fe-fuzz/irc/core/event-get-params-fuzz
+src/fe-fuzz/fe-common/core/theme-load-fuzz
src/fe-common/irc/irc-modules.c
src/irc/irc.c
diff --git a/NEWS b/NEWS
index 1054bb62..4b171852 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,83 @@
-v1.1-head 2018-xx-xx The Irssi team <staff@irssi.org>
+v1.2-head 2018-xx-xx The Irssi team <staff@irssi.org>
+
+v1.1.0 2018-01-15 The Irssi team <staff@irssi.org>
+ * Colour is now re-set when reaching a comma, matching mIRC
+ behaviour (#742, #740, #790)
+ * Irssi now shows the initial nick and name on first start
+ (#785, #786)
+ * lynx is no longer required to run autogen.sh (#81, #781)
+ * The command history no longer permits wrapping around (#686)
+ * /foreach now correctly sends arguments as commands, stopping
+ you from embarassing AMSGs (#659)
+ * /server does not connect to servers anymore, use /server
+ connect to change servers (#559, #649).
+ * The net_ip_compare API function is now deprecated, and the
+ previously deprecated net_connect has been removed
+ (#770). By Will Storey (#770)
+ + Add an option to ignore all channels or ignore all queries
+ using /set activity_hide_targets. By Jari Matilainen (#612,
+ #779)
+ + Add a startup warning if the TERM var is wrong inside
+ tmux/screen (#726)
+ + Add option to hide certain levels from the textbuffer using
+ /window hidelevel (#746, #808)
+ + Irssi now has its first unit test (for mode parsing). By
+ Will Storey (#793)
+ + Added access to global command history when using window
+ history, and a binding to erase entries from the command
+ history (erase_history_entry) (#762)
+ + -alternate_nick is now available as a network specific
+ property. By Paul Townsend (#120, #771)
+ + On FreeBSD, Irssi now supports Capsicum sandbox (/capsicum
+ enter). By Edward Tomasz Napierala (#735, #755, #772)
+ + Filenames (directories) ending with a / now tab-complete
+ (#741)
+ + UTF-8 should now work in regular expressions when using
+ GRegex (the default) (#636, #653)
+ + Nicks are now properly escaped on completion. By Oscar
+ Linderholm (#693, #709)
+ + /server add -port <num> now works. By Jari Matilainen (#703)
+ + Add a setting key_timeout to make key sequences
+ automatically re-set when not finished (#644, #645)
+ + Warn users about expired client certificates, as servers may
+ refuse them (#211, #627)
+ + Add a new net_start_ssl function for StartTLS. This is
+ available from ABI 8 and can be used by protocol modules
+ (#615, #622).
+ + The %# code is now stored in the textbuffer, so for example
+ web scripts can make use of it (#626)
+ + Add new setting break_wide which can be used to enable
+ breaking of wide characters (for east-asian
+ users). Originally from FreeBSD ports. (#625)
+ + Add fuzzing code (#610, #620, #701, #713)
+ - Netsplits show properly again (#812)
+ - Do not error on blank lines when using /exec -o. By Fabian
+ Kurz (FS#902, #805)
+ - Detect used nickname as reported by server. By Alexandre
+ Morignot (#219, #804)
+ - Prevent use after free error during the execution of some
+ commands. Found by Joseph Bisch. (GL#17, GL!24)
+ - Fix MODE parameter parsing when colon was used at a place
+ Irssi didn't expect (#601, #766)
+ - Fixed code to compile with
+ -Werror=declaration-after-statement (#795)
+ - Clang-format is now supported for git-clang-format (#784)
+ - Fix use after free when changing the network of
+ hilights. Reported by Rui Mathias. (#787, #788)
+ - Fix positioning error when tab-completing non-ascii
+ strings. (#752, #754)
+ - In-development issues (#750, #751)
+ - Clarify Alis in /help list (#699, #712)
+ - Improve /lastlog performance from O(N^2) to O(N) (#715)
+ - Fix a segfault on "script destroyed" signal. By Stephen
+ Oberholtzer (#660, #661).
+ - Fix early ISON error (#596, #647)
+ - Documentation improvements. By Paolo Martini (#639).
+ By Tristan Pepin (#731). By Paul Townsend (#684, #736).
+ By Will Storey (#777)
+ - Minor cleanups (#590). By Edward Tomasz Napierala (#734,
+ #738)
+ - Fix space issue in glib-2.0.m4 (#621)
v1.0.6 2018-01-07 The Irssi team <staff@irssi.org>
- Fix invalid memory access when reading hilight configuration
diff --git a/README.md b/README.md
index 0f54ccf5..3550b640 100644
--- a/README.md
+++ b/README.md
@@ -53,7 +53,7 @@ make && sudo make install
## [Themes](https://irssi-import.github.io/themes/)
-## [Scripts](http://scripts.irssi.org/)
+## [Scripts](https://scripts.irssi.org/)
## [Modules](https://irssi.org/modules/)
diff --git a/configure.ac b/configure.ac
index 76ada09f..e8df7d9e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -650,6 +650,10 @@ src/fe-common/irc/Makefile
src/fe-common/irc/dcc/Makefile
src/fe-common/irc/notifylist/Makefile
src/fe-fuzz/Makefile
+src/fe-fuzz/irc/Makefile
+src/fe-fuzz/irc/core/Makefile
+src/fe-fuzz/fe-common/Makefile
+src/fe-fuzz/fe-common/core/Makefile
src/fe-none/Makefile
src/fe-text/Makefile
src/lib-config/Makefile
diff --git a/docs/help/in/hash.in b/docs/help/in/hash.in
index 32dfc9c7..2d5a355d 100644
--- a/docs/help/in/hash.in
+++ b/docs/help/in/hash.in
@@ -15,7 +15,7 @@
%9References:%9
- http://www.irssi.org
+ https://irssi.org
https://github.com/irssi
%9See also:%9 DIE, KILL, OPER
diff --git a/docs/help/in/help.in b/docs/help/in/help.in
index 555e20e1..35ab9b75 100644
--- a/docs/help/in/help.in
+++ b/docs/help/in/help.in
@@ -20,7 +20,7 @@
%9References:%9
- http://www.irssi.org
+ https://irssi.org
https://github.com/irssi
%9See also:%9 CONNECT, MSG, NETWORK, SERVER
diff --git a/docs/help/in/ison.in b/docs/help/in/ison.in
index c77e4c59..e9e54ee9 100644
--- a/docs/help/in/ison.in
+++ b/docs/help/in/ison.in
@@ -16,5 +16,5 @@
/ISON mike
/ISON sarah bob
-%9See also:%9 NOTIFY, WHOAS, WHOIS
+%9See also:%9 NOTIFY, WHOWAS, WHOIS
diff --git a/docs/help/in/window.in b/docs/help/in/window.in
index 6dde6c50..0e7ed637 100644
--- a/docs/help/in/window.in
+++ b/docs/help/in/window.in
@@ -35,10 +35,19 @@
SHRINK: %|Decrease the size of the active split window by the specified number of lines.
SIZE: %|Set the current split window size to the specified numer of lines.
BALANCE: %|Balance the heights of all split windows.
+ RGROW: %|Increase the width of the active split window by the specified number of columns.
+ RSHRINK: %|Decrease the wodth of the active split window by the specified number of columns.
+ RSIZE: %|Set the current split window width to the specified numer of columns.
+ RBALANCE: %|Balance the widths of all split windows in this line.
HIDE: %|Hides the current split window, or the split window specified by number or item name.
SHOW: %|Show the window specified by number or item name as a new split windows. It is made sticky when autostick_split_windows is turned on.
- UP: %|Set the split window above the current one active. At the top, wraps to the bottom.
- DOWN: %|Set the split window below the current one active. At the bottom, wraps to the top.
+ RSHOW: %|Show the window specified by number or item name as a new windows split to the right of the current window. It is made sticky when autostick_split_windows is turned on.
+ UP: %|Set the split window left or above the current one active. At the top, wraps to the bottom.
+ DOWN: %|Set the split window right or below the current one active. At the bottom, wraps to the top.
+ DUP: %|Set the split window above the current one active. At the top, wraps to the bottom.
+ DDOWN: %|Set the split window below the current one active. At the bottom, wraps to the top.
+ DLEFT: %|Set the split window left to the current one active. At the left, wraps to the right.
+ DRIGHT: %|Set the split window right to the current one active. At the right, wraps to the left.
LEFT: %|Go to the previous window numerically that is part of the current sticky group (or not part of any sticky group).
RIGHT: %|Go to the next window numerically that is part of the current sticky group (or not part of any sticky group).
STICK: %|Make the currently active window sticky, or stick the window specified by number to the currently visible split window. Or turn off stickyness of the currently active window or the window specified by number.
@@ -46,6 +55,8 @@
MOVE RIGHT: %|Move the window to the numerically next location inside the current sticky group.
MOVE UP: %|Move the current window to the sticky group of the split window above. If no sticky group remains, the split window collapses.
MOVE DOWN: %|Move the current window to the sticky group of the split window below. If no sticky group remains, the split window collapses.
+ MOVE DLEFT: %|Move the current window to the sticky group of the split window to the left. If no sticky group remains, the split window collapses.
+ MOVE DRIGHT: %|Move the current window to the sticky group of the split window to the right. If no sticky group remains, the split window collapses.
%|Add the required arguments for the given command. Without arguments, the details (size, immortality, levels, server, name and sticky group) of the currently active window are displayed. If used with a number as argument, same as WINDOW REFNUM.
diff --git a/docs/irssi.1 b/docs/irssi.1
index e1fab0d8..08be69f5 100644
--- a/docs/irssi.1
+++ b/docs/irssi.1
@@ -59,7 +59,7 @@ show a help message
.SH SEE ALSO
.B Irssi
has a solid amount of documentation available; check /HELP or look online
-at http://www.irssi.org
+at https://irssi.org
.SH FILES
.TP
.I ~/.irssi/config
diff --git a/docs/manual.txt b/docs/manual.txt
index b2d0de14..db40e5d3 100644
--- a/docs/manual.txt
+++ b/docs/manual.txt
@@ -1,5 +1,5 @@
- Irssi 0.8 documentation - http://www.irssi.org/
+ Irssi 0.8 documentation - https://irssi.org/
Copyright(c) 2000 Timo Sirainen <cras@irssi.org>
diff --git a/irssi.conf b/irssi.conf
index 0e486807..61d2e81f 100644
--- a/irssi.conf
+++ b/irssi.conf
@@ -145,7 +145,7 @@ aliases = {
SB = "SCROLLBACK";
SBAR = "STATUSBAR";
SIGNOFF = "QUIT";
- SV = "MSG * Irssi $J ($V) - http://www.irssi.org";
+ SV = "MSG * Irssi $J ($V) - https://irssi.org";
T = "TOPIC";
UB = "UNBAN";
UMODE = "MODE $N";
@@ -281,7 +281,7 @@ statusbar = {
prompt_empty = "{prompt $winname}";
topic = " $topic";
- topic_empty = " Irssi v$J - http://www.irssi.org";
+ topic_empty = " Irssi v$J - https://irssi.org";
lag = "{sb Lag: $0-}";
act = "{sb Act: $0-}";
diff --git a/src/common.h b/src/common.h
index ba5557e6..46d0c45a 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 13
+#define IRSSI_ABI_VERSION 14
#define DEFAULT_SERVER_ADD_PORT 6667
#define DEFAULT_SERVER_ADD_TLS_PORT 6697
diff --git a/src/core/network-openssl.c b/src/core/network-openssl.c
index c7ce4b43..9fddf073 100644
--- a/src/core/network-openssl.c
+++ b/src/core/network-openssl.c
@@ -46,6 +46,7 @@
#endif
/* OpenSSL 1.1.0 also introduced some useful additions to the api */
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L)
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined (LIBRESSL_VERSION_NUMBER)
static int X509_STORE_up_ref(X509_STORE *vfy)
{
@@ -57,6 +58,7 @@ static int X509_STORE_up_ref(X509_STORE *vfy)
return (n > 1) ? 1 : 0;
}
#endif
+#endif
/* ssl i/o channel object */
typedef struct
@@ -72,7 +74,10 @@ typedef struct
} GIOSSLChannel;
static int ssl_inited = FALSE;
+/* https://github.com/irssi/irssi/issues/820 */
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L)
static X509_STORE *store = NULL;
+#endif
static void irssi_ssl_free(GIOChannel *handle)
{
@@ -379,7 +384,9 @@ static GIOFuncs irssi_ssl_channel_funcs = {
gboolean irssi_ssl_init(void)
{
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L)
int success;
+#endif
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
if (!OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, NULL)) {
@@ -391,6 +398,8 @@ gboolean irssi_ssl_init(void)
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L)
store = X509_STORE_new();
if (store == NULL) {
g_error("Could not initialize OpenSSL: X509_STORE_new() failed");
@@ -404,6 +413,7 @@ gboolean irssi_ssl_init(void)
store = NULL;
/* Don't return an error; the user might have their own cafile/capath. */
}
+#endif
ssl_inited = TRUE;
@@ -522,13 +532,21 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_
g_free(scafile);
g_free(scapath);
verify = TRUE;
- } else if (store != NULL) {
+ }
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L)
+ else if (store != NULL) {
/* Make sure to increment the refcount every time the store is
* used, that's essential not to get it free'd by OpenSSL when
* the SSL_CTX is destroyed. */
X509_STORE_up_ref(store);
SSL_CTX_set_cert_store(ctx, store);
}
+#else
+ else {
+ if (!SSL_CTX_set_default_verify_paths(ctx))
+ g_warning("Could not load default certificates");
+ }
+#endif
if(!(ssl = SSL_new(ctx)))
{
diff --git a/src/fe-common/core/chat-completion.c b/src/fe-common/core/chat-completion.c
index 97cd0565..7ecdd4a2 100644
--- a/src/fe-common/core/chat-completion.c
+++ b/src/fe-common/core/chat-completion.c
@@ -639,6 +639,59 @@ static void complete_window_nicks(GList **list, WINDOW_REC *window,
}
}
+/* Checks if a line is only nicks from autocompletion.
+ This lets us insert colons only at the beginning of a list
+ of nicks */
+static int only_nicks(const char *linestart)
+{
+ int i = 1;
+ char prev;
+
+ // at the beginning of the line
+ if (*linestart == '\0') {
+ return TRUE;
+ }
+
+ /* completion_char being a whole string introduces loads of edge cases
+ and can't be handled generally. Skip this case; we handled the
+ "beginning of line" case already */
+ if (completion_char[1] != '\0')
+ return FALSE;
+
+ /* This would make the completion char get inserted everywhere otherwise */
+ if (*completion_char == ' ')
+ return FALSE;
+
+ /* First ensure that the line is of the format "foo: bar: baz"
+ we check this by ensuring each space is preceded by a colon or
+ another space */
+ while (linestart[i] != '\0') {
+ if (linestart[i] == ' ') {
+ prev = linestart[i - 1];
+ if (prev != *completion_char && prev != ' ')
+ return FALSE;
+ }
+ i += 1;
+ }
+
+ /* There's an edge case here, if we're completing something
+ like `foo: bar ba<tab>`, then the `linestart` line will end
+ at "bar", and we'll miss the space. Ensure that the end
+ of the line is a colon followed by an optional series of spaces */
+ i -= 1;
+ while (i >= 0) {
+ if (linestart[i] == ' ') {
+ i--;
+ continue;
+ } else if (linestart[i] == *completion_char) {
+ return TRUE;
+ } else {
+ break;
+ }
+ }
+ return FALSE;
+}
+
static void sig_complete_word(GList **list, WINDOW_REC *window,
const char *word, const char *linestart,
int *want_space)
@@ -691,7 +744,7 @@ static void sig_complete_word(GList **list, WINDOW_REC *window,
} else if (channel != NULL) {
/* nick completion .. we could also be completing a nick
after /MSG from nicks in channel */
- const char *suffix = *linestart != '\0' ? NULL : completion_char;
+ const char *suffix = only_nicks(linestart) ? completion_char : NULL;
complete_window_nicks(list, window, word, suffix);
} else if (window->level & MSGLEVEL_MSGS) {
/* msgs window, complete /MSG nicks */
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-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 37db6f7c..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);
diff --git a/src/fe-common/core/themes.c b/src/fe-common/core/themes.c
index cb1cce8f..6692985b 100644
--- a/src/fe-common/core/themes.c
+++ b/src/fe-common/core/themes.c
@@ -130,7 +130,7 @@ static char *theme_replace_expand(THEME_REC *theme, int index,
abstract = rec->data;
abstract = theme_format_expand_data(theme, (const char **) &abstract,
default_fg, default_bg,
- last_fg, last_bg, flags);
+ last_fg, last_bg, (flags | EXPAND_FLAG_IGNORE_REPLACES));
ret = parse_special_string(abstract, NULL, NULL, data, NULL,
PARSE_FLAG_ONLY_ARGS);
g_free(abstract);
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-netjoin.c b/src/fe-common/irc/fe-netjoin.c
index 8272093f..a7a2e4fe 100644
--- a/src/fe-common/irc/fe-netjoin.c
+++ b/src/fe-common/irc/fe-netjoin.c
@@ -245,23 +245,18 @@ static void print_netjoins(NETJOIN_SERVER_REC *server, const char *filter_channe
message before it. */
static void sig_print_starting(TEXT_DEST_REC *dest)
{
- NETJOIN_SERVER_REC *rec;
+ GSList *tmp, *next;
if (printing_joins)
return;
- if (!IS_IRC_SERVER(dest->server))
- return;
-
- if (!(dest->level & MSGLEVEL_PUBLIC))
- return;
-
- if (!server_ischannel(dest->server, dest->target))
- return;
+ for (tmp = joinservers; tmp != NULL; tmp = next) {
+ NETJOIN_SERVER_REC *server = tmp->data;
- rec = netjoin_find_server(IRC_SERVER(dest->server));
- if (rec != NULL && rec->netjoins != NULL)
- print_netjoins(rec, dest->target);
+ next = tmp->next;
+ if (server->netjoins != NULL)
+ print_netjoins(server, 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..edd3fc34 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);
@@ -247,23 +247,17 @@ static int check_server_splits(IRC_SERVER_REC *server)
message before it. */
static void sig_print_starting(TEXT_DEST_REC *dest)
{
- IRC_SERVER_REC *rec;
+ GSList *tmp;
if (printing_splits)
return;
- if (!IS_IRC_SERVER(dest->server))
- return;
-
- if (!(dest->level & MSGLEVEL_PUBLIC))
- return;
-
- if (!server_ischannel(dest->server, dest->target))
- return;
+ for (tmp = servers; tmp != NULL; tmp = tmp->next) {
+ IRC_SERVER_REC *rec = tmp->data;
- rec = IRC_SERVER(dest->server);
- if (rec->split_servers != NULL)
- print_splits(rec, dest->target);
+ if (IS_IRC_SERVER(rec) && rec->split_servers != NULL)
+ print_splits(rec, NULL);
+ }
}
static int sig_check_splits(void)
diff --git a/src/fe-fuzz/Makefile.am b/src/fe-fuzz/Makefile.am
index c11b3dbb..40abd5ba 100644
--- a/src/fe-fuzz/Makefile.am
+++ b/src/fe-fuzz/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS = irc fe-common
+
bin_PROGRAMS = irssi-fuzz
# Force link with CXX for libfuzzer support
diff --git a/src/fe-fuzz/fe-common/Makefile.am b/src/fe-fuzz/fe-common/Makefile.am
new file mode 100644
index 00000000..52770885
--- /dev/null
+++ b/src/fe-fuzz/fe-common/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = core
diff --git a/src/fe-fuzz/fe-common/core/Makefile.am b/src/fe-fuzz/fe-common/core/Makefile.am
new file mode 100644
index 00000000..4fe5937c
--- /dev/null
+++ b/src/fe-fuzz/fe-common/core/Makefile.am
@@ -0,0 +1,46 @@
+bin_PROGRAMS = theme-load-fuzz
+
+# Force link with CXX for libfuzzer support
+CCLD=$(CXX) $(CXXFLAGS)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/core/ \
+ -I$(top_srcdir)/src/irc/core/ \
+ -I$(top_srcdir)/src/fe-common/core/ \
+ $(GLIB_CFLAGS)
+
+AM_DEPENDENCIES = \
+ ../../../core/libcore.a \
+ ../../../lib-config/libirssi_config.a \
+ ../../../irc/libirc.a \
+ ../../../irc/core/libirc_core.a \
+ ../../../irc/dcc/libirc_dcc.a \
+ ../../../irc/flood/libirc_flood.a \
+ ../../../irc/notifylist/libirc_notifylist.a \
+ ../../../fe-common/core/libfe_common_core.a \
+ ../../../fe-common/irc/libfe_common_irc.a \
+ ../../../fe-common/irc/dcc/libfe_irc_dcc.a \
+ ../../../fe-common/irc/notifylist/libfe_irc_notifylist.a
+
+LDADD = \
+ ../../../irc/libirc.a \
+ ../../../irc/core/libirc_core.a \
+ ../../../irc/dcc/libirc_dcc.a \
+ ../../../irc/flood/libirc_flood.a \
+ ../../../irc/notifylist/libirc_notifylist.a \
+ ../../../fe-common/core/libfe_common_core.a \
+ ../../../fe-common/irc/libfe_common_irc.a \
+ ../../../fe-common/irc/dcc/libfe_irc_dcc.a \
+ ../../../fe-common/irc/notifylist/libfe_irc_notifylist.a \
+ ../../../core/libcore.a \
+ ../../../lib-config/libirssi_config.a \
+ @PROG_LIBS@ \
+ $(FUZZER_LIBS)
+
+theme_load_fuzz_SOURCES = \
+ theme-load.c \
+ $(top_srcdir)/src/fe-text/module-formats.c
+
+noinst_HEADERS = \
+ $(top_srcdir)/src/fe-text/module-formats.h
diff --git a/src/fe-fuzz/fe-common/core/theme-load.c b/src/fe-fuzz/fe-common/core/theme-load.c
new file mode 100644
index 00000000..14df74c6
--- /dev/null
+++ b/src/fe-fuzz/fe-common/core/theme-load.c
@@ -0,0 +1,66 @@
+/*
+ theme-load.c : irssi
+
+ Copyright (C) 2018 Joseph Bisch
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include "modules-load.h"
+#include "levels.h"
+#include "../fe-text/module-formats.h" // need to explicitly grab from fe-text
+#include "themes.h"
+#include "core.h"
+#include "fe-common-core.h"
+#include "args.h"
+#include "printtext.h"
+#include "irc.h"
+#include "themes.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+int LLVMFuzzerInitialize(int *argc, char ***argv) {
+ core_register_options();
+ fe_common_core_register_options();
+ char *irssi_argv[] = {*argv[0], "--home", "/tmp/irssi", NULL};
+ int irssi_argc = sizeof(irssi_argv) / sizeof(char *) - 1;
+ args_execute(irssi_argc, irssi_argv);
+ core_preinit((*argv)[0]);
+ core_init();
+ fe_common_core_init();
+ theme_register(gui_text_formats);
+ module_register("core", "fe-fuzz");
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ gchar *copy = g_strndup((const gchar *)data, size);
+
+ FILE *fp = fopen("/tmp/irssi/fuzz.theme", "wb");
+ if (fp) {
+ fwrite(copy, strlen(copy), 1, fp);
+ fclose(fp);
+ }
+
+ THEME_REC *theme = theme_load("fuzz");
+ theme_destroy(theme);
+
+ g_free(copy);
+ return 0;
+}
diff --git a/src/fe-fuzz/irc/Makefile.am b/src/fe-fuzz/irc/Makefile.am
new file mode 100644
index 00000000..52770885
--- /dev/null
+++ b/src/fe-fuzz/irc/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = core
diff --git a/src/fe-fuzz/irc/core/Makefile.am b/src/fe-fuzz/irc/core/Makefile.am
new file mode 100644
index 00000000..fa614abb
--- /dev/null
+++ b/src/fe-fuzz/irc/core/Makefile.am
@@ -0,0 +1,46 @@
+bin_PROGRAMS = event-get-params-fuzz
+
+# Force link with CXX for libfuzzer support
+CCLD=$(CXX) $(CXXFLAGS)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/core/ \
+ -I$(top_srcdir)/src/irc/core/ \
+ -I$(top_srcdir)/src/fe-common/core/ \
+ $(GLIB_CFLAGS)
+
+AM_DEPENDENCIES = \
+ ../../../core/libcore.a \
+ ../../../lib-config/libirssi_config.a \
+ ../../../irc/libirc.a \
+ ../../../irc/core/libirc_core.a \
+ ../../../irc/dcc/libirc_dcc.a \
+ ../../../irc/flood/libirc_flood.a \
+ ../../../irc/notifylist/libirc_notifylist.a \
+ ../../../fe-common/core/libfe_common_core.a \
+ ../../../fe-common/irc/libfe_common_irc.a \
+ ../../../fe-common/irc/dcc/libfe_irc_dcc.a \
+ ../../../fe-common/irc/notifylist/libfe_irc_notifylist a
+
+LDADD = \
+ ../../../irc/libirc.a \
+ ../../../irc/core/libirc_core.a \
+ ../../../irc/dcc/libirc_dcc.a \
+ ../../../irc/flood/libirc_flood.a \
+ ../../../irc/notifylist/libirc_notifylist.a \
+ ../../../fe-common/core/libfe_common_core.a \
+ ../../../fe-common/irc/libfe_common_irc.a \
+ ../../../fe-common/irc/dcc/libfe_irc_dcc.a \
+ ../../../fe-common/irc/notifylist/libfe_irc_notifylist.a \
+ ../../../core/libcore.a \
+ ../../../lib-config/libirssi_config.a \
+ @PROG_LIBS@ \
+ $(FUZZER_LIBS)
+
+event_get_params_fuzz_SOURCES = \
+ event-get-params.c \
+ $(top_srcdir)/src/fe-text/module-formats.c
+
+noinst_HEADERS = \
+ $(top_srcdir)/src/fe-text/module-formats.h
diff --git a/src/fe-fuzz/irc/core/event-get-params.c b/src/fe-fuzz/irc/core/event-get-params.c
new file mode 100644
index 00000000..c50b6205
--- /dev/null
+++ b/src/fe-fuzz/irc/core/event-get-params.c
@@ -0,0 +1,82 @@
+/*
+ event-get-params.c : irssi
+
+ Copyright (C) 2017 Joseph Bisch
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include "modules-load.h"
+#include "levels.h"
+#include "../fe-text/module-formats.h" // need to explicitly grab from fe-text
+#include "themes.h"
+#include "core.h"
+#include "fe-common-core.h"
+#include "args.h"
+#include "printtext.h"
+#include "irc.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+int LLVMFuzzerInitialize(int *argc, char ***argv) {
+ core_register_options();
+ fe_common_core_register_options();
+ /* no args */
+ args_execute(0, NULL);
+ core_preinit((*argv)[0]);
+ core_init();
+ fe_common_core_init();
+ theme_register(gui_text_formats);
+ module_register("core", "fe-fuzz");
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size < 1) {
+ return 0;
+ }
+ uint8_t count = *data;
+ gchar *copy = g_strndup((const gchar *)data+1, size-1);
+
+ char *output0;
+ char *output1;
+ char *output2;
+ char *output3;
+ char *params;
+ if (count % 8 == 0) {
+ params = event_get_params(copy, 1 | PARAM_FLAG_GETREST, &output0);
+ } else if (count % 8 == 1) {
+ params = event_get_params(copy, 2 | PARAM_FLAG_GETREST, &output0, &output1);
+ } else if (count % 8 == 2) {
+ params = event_get_params(copy, 3 | PARAM_FLAG_GETREST, &output0, &output1, &output2);
+ } else if (count % 8 == 3) {
+ params = event_get_params(copy, 4 | PARAM_FLAG_GETREST, &output0, &output1, &output2, &output3);
+ } else if (count % 8 == 4) {
+ params = event_get_params(copy, 1, &output0);
+ } else if (count % 8 == 5) {
+ params = event_get_params(copy, 2, &output0, &output1);
+ } else if (count % 8 == 6) {
+ params = event_get_params(copy, 3, &output0, &output1, &output2);
+ } else {
+ params = event_get_params(copy, 4, &output0, &output1, &output2, &output3);
+ }
+ g_free(params);
+ g_free(copy);
+ return 0;
+}
diff --git a/src/fe-text/gui-entry.c b/src/fe-text/gui-entry.c
index e91fcfb3..52a39969 100644
--- a/src/fe-text/gui-entry.c
+++ b/src/fe-text/gui-entry.c
@@ -65,6 +65,10 @@ static void entry_text_grow(GUI_ENTRY_REC *entry, int grow_size)
entry->text_alloc = nearest_power(entry->text_alloc+grow_size);
entry->text = g_realloc(entry->text,
sizeof(unichar) * entry->text_alloc);
+
+ if (entry->uses_extents)
+ entry->extents = g_realloc(entry->extents,
+ sizeof(char *) * entry->text_alloc);
}
GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8)
@@ -74,14 +78,30 @@ GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8)
rec = g_new0(GUI_ENTRY_REC, 1);
rec->xpos = xpos;
rec->ypos = ypos;
- rec->width = width;
- rec->text_alloc = 1024;
+ rec->width = width;
+ rec->text_alloc = 1024;
rec->text = g_new(unichar, rec->text_alloc);
- rec->text[0] = '\0';
- rec->utf8 = utf8;
+ rec->extents = NULL;
+ rec->text[0] = '\0';
+ rec->utf8 = utf8;
return rec;
}
+static void destroy_extents(GUI_ENTRY_REC *entry)
+{
+ if (entry->uses_extents) {
+ int i;
+ for (i = 0; i < entry->text_alloc; i++) {
+ if (entry->extents[i] != NULL) {
+ g_free(entry->extents[i]);
+ }
+ }
+ }
+ g_free(entry->extents);
+ entry->extents = NULL;
+ entry->uses_extents = FALSE;
+}
+
void gui_entry_destroy(GUI_ENTRY_REC *entry)
{
GSList *tmp;
@@ -100,9 +120,10 @@ void gui_entry_destroy(GUI_ENTRY_REC *entry)
}
g_slist_free(entry->kill_ring);
- g_free(entry->text);
+ destroy_extents(entry);
+ g_free(entry->text);
g_free(entry->prompt);
- g_free(entry);
+ g_free(entry);
}
/* big5 functions */
@@ -164,15 +185,36 @@ void big5_to_unichars(const char *str, unichar *out)
*out = '\0';
}
+/* Return screen length of plain string */
+static int scrlen_str(const char *str, int utf8)
+{
+ int len = 0;
+ char *stripped;
+ g_return_val_if_fail(str != NULL, 0);
+
+ stripped = strip_codes(str);
+ len = string_width(stripped, utf8 ? TREAT_STRING_AS_UTF8 : TREAT_STRING_AS_BYTES);
+ g_free(stripped);
+ return len;
+}
+
/* ----------------------------- */
-static int pos2scrpos(GUI_ENTRY_REC *entry, int pos)
+static int pos2scrpos(GUI_ENTRY_REC *entry, int pos, int cursor)
{
int i;
int xpos = 0;
+ if (!cursor && pos <= 0)
+ return 0;
+
+ if (entry->uses_extents && entry->extents[0] != NULL) {
+ xpos += scrlen_str(entry->extents[0], entry->utf8);
+ }
+
for (i = 0; i < pos; i++) {
unichar c = entry->text[i];
+ const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
if (term_type == TERM_TYPE_BIG5)
xpos += big5_width(c);
@@ -180,16 +222,26 @@ static int pos2scrpos(GUI_ENTRY_REC *entry, int pos)
xpos += unichar_isprint(c) ? mk_wcwidth(c) : 1;
else
xpos++;
+
+ if (extent != NULL) {
+ xpos += scrlen_str(extent, entry->utf8);
+ }
+
}
return xpos;
}
static int scrpos2pos(GUI_ENTRY_REC *entry, int pos)
{
- int i, width, xpos;
+ int i, width, xpos = 0;
- for (i = 0, xpos = 0; i < entry->text_len; i++) {
+ if (entry->uses_extents && entry->extents[0] != NULL) {
+ xpos += scrlen_str(entry->extents[0], entry->utf8);
+ }
+
+ for (i = 0; i < entry->text_len && xpos < pos; i++) {
unichar c = entry->text[i];
+ const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
if (term_type == TERM_TYPE_BIG5)
width = big5_width(c);
@@ -198,15 +250,13 @@ static int scrpos2pos(GUI_ENTRY_REC *entry, int pos)
else
width = 1;
- if (xpos + width > pos)
- break;
xpos += width;
- }
- if (xpos == pos)
- return i;
- else
- return i-1;
+ if (extent != NULL) {
+ xpos += scrlen_str(extent, entry->utf8);
+ }
+ }
+ return i;
}
/* Fixes the cursor position in screen */
@@ -215,19 +265,19 @@ static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry)
int old_scrstart;
/* assume prompt len == prompt scrlen */
- int start = pos2scrpos(entry, entry->scrstart);
- int now = pos2scrpos(entry, entry->pos);
+ int start = pos2scrpos(entry, entry->scrstart, FALSE);
+ int now = pos2scrpos(entry, entry->pos, TRUE);
old_scrstart = entry->scrstart;
- if (now-start < entry->width - 2 - entry->promptlen && now-start > 0)
+ if (now-start < entry->width - 2 - entry->promptlen && now-start > 0) {
entry->scrpos = now-start;
- else if (now < entry->width - 1 - entry->promptlen) {
+ } else if (now < entry->width - 1 - entry->promptlen) {
entry->scrstart = 0;
entry->scrpos = now;
} else {
entry->scrstart = scrpos2pos(entry, now-(entry->width -
entry->promptlen)*2/3);
- start = pos2scrpos(entry, entry->scrstart);
+ start = pos2scrpos(entry, entry->scrstart, FALSE);
entry->scrpos = now - start;
}
@@ -235,59 +285,140 @@ static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry)
entry->redraw_needed_from = 0;
}
+static char *text_effects_only(const char *p)
+{
+ GString *str;
+
+ str = g_string_sized_new(strlen(p));
+ for (; *p != '\0'; p++) {
+ if (*p == 4 && p[1] != '\0') {
+ if (p[1] >= FORMAT_STYLE_SPECIAL) {
+ g_string_append_len(str, p, 2);
+ p++;
+ continue;
+ }
+
+ /* irssi color */
+ if (p[2] != '\0') {
+#ifdef TERM_TRUECOLOR
+ if (p[1] == FORMAT_COLOR_24) {
+ if (p[3] == '\0') p += 2;
+ else if (p[4] == '\0') p += 3;
+ else if (p[5] == '\0') p += 4;
+ else {
+ g_string_append_len(str, p, 6);
+ p += 5;
+ }
+ } else {
+#endif /* TERM_TRUECOLOR */
+ g_string_append_len(str, p, 3);
+ p += 2;
+#ifdef TERM_TRUECOLOR
+ }
+#endif /* TERM_TRUECOLOR */
+ continue;
+ }
+ }
+ }
+
+ return g_string_free(str, FALSE);
+}
+
static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos)
{
- int i;
- int xpos, end_xpos;
+ int i, start;
+ int start_xpos, xpos, new_xpos, end_xpos;
+ char *tmp;
+ GString *str;
+
+ start = entry->scrstart + pos;
- xpos = entry->xpos + entry->promptlen +
- pos2scrpos(entry, pos + entry->scrstart) -
- pos2scrpos(entry, entry->scrstart);
+ start_xpos = xpos = entry->xpos + entry->promptlen +
+ pos2scrpos(entry, start, FALSE) -
+ pos2scrpos(entry, entry->scrstart, FALSE);
end_xpos = entry->xpos + entry->width;
if (xpos > end_xpos)
return;
+ str = g_string_sized_new(entry->text_alloc);
+
term_set_color(root_window, ATTR_RESET);
- term_move(root_window, xpos, entry->ypos);
+ /* term_move(root_window, xpos, entry->ypos); */
+
+ if (entry->uses_extents && entry->extents[0] != NULL) {
+ g_string_append(str, entry->extents[0]);
+ }
+ for (i = 0; i < start && i < entry->text_len; i++) {
+ const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
+ if (extent != NULL) {
+ g_string_append(str, extent);
+ }
+ }
+ if (i == 0) {
+ xpos += scrlen_str(str->str, entry->utf8);
+ } else {
+ tmp = text_effects_only(str->str);
+ g_string_assign(str, tmp);
+ g_free(tmp);
+ }
- for (i = entry->scrstart + pos; i < entry->text_len; i++) {
+ for (; i < entry->text_len; i++) {
unichar c = entry->text[i];
+ const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
+ new_xpos = xpos;
if (entry->hidden)
- xpos++;
+ new_xpos++;
else if (term_type == TERM_TYPE_BIG5)
- xpos += big5_width(c);
+ new_xpos += big5_width(c);
else if (entry->utf8)
- xpos += unichar_isprint(c) ? mk_wcwidth(c) : 1;
+ new_xpos += unichar_isprint(c) ? mk_wcwidth(c) : 1;
else
- xpos++;
+ new_xpos++;
- if (xpos > end_xpos)
+ if (new_xpos > end_xpos)
break;
if (entry->hidden)
- term_addch(root_window, ' ');
+ g_string_append_c(str, ' ');
else if (unichar_isprint(c))
- term_add_unichar(root_window, c);
+ g_string_append_unichar(str, c);
else {
- term_set_color(root_window, ATTR_RESET|ATTR_REVERSE);
- term_addch(root_window, (c & 127)+'A'-1);
- term_set_color(root_window, ATTR_RESET);
+ g_string_append_c(str, 4);
+ g_string_append_c(str, FORMAT_STYLE_REVERSE);
+ g_string_append_c(str, (c & 127)+'A'-1);
+ g_string_append_c(str, 4);
+ g_string_append_c(str, FORMAT_STYLE_REVERSE);
+ }
+ xpos = new_xpos;
+
+ if (extent != NULL) {
+ new_xpos += scrlen_str(extent, entry->utf8);
+
+ if (new_xpos > end_xpos)
+ break;
+
+ g_string_append(str, extent);
+ xpos = new_xpos;
}
}
/* clear the rest of the input line */
if (xpos < end_xpos) {
- if (end_xpos == term_width)
- term_clrtoeol(root_window);
- else {
+ if (end_xpos == term_width) {
+ g_string_append_c(str, 4);
+ g_string_append_c(str, FORMAT_STYLE_CLRTOEOL);
+ } else {
while (xpos < end_xpos) {
- term_addch(root_window, ' ');
+ g_string_append_c(str, ' ');
xpos++;
}
}
}
+
+ gui_printtext_internal(start_xpos, entry->ypos, str->str);
+ g_string_free(str, TRUE);
}
static void gui_entry_draw(GUI_ENTRY_REC *entry)
@@ -359,19 +490,6 @@ void gui_entry_set_active(GUI_ENTRY_REC *entry)
}
}
-/* Return screen length of plain string */
-static int scrlen_str(const char *str)
-{
- int len = 0;
- char *stripped;
- g_return_val_if_fail(str != NULL, 0);
-
- stripped = strip_codes(str);
- len = string_width(stripped, -1);
- g_free(stripped);
- return len;
-}
-
void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str)
{
int oldlen;
@@ -382,7 +500,7 @@ void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str)
if (str != NULL) {
g_free_not_null(entry->prompt);
entry->prompt = g_strdup(str);
- entry->promptlen = scrlen_str(str);
+ entry->promptlen = scrlen_str(str, entry->utf8);
}
if (entry->prompt != NULL)
@@ -416,6 +534,7 @@ void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str)
entry->text_len = 0;
entry->pos = 0;
entry->text[0] = '\0';
+ destroy_extents(entry);
gui_entry_insert_text(entry, str);
}
@@ -488,6 +607,15 @@ void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str)
g_memmove(entry->text + entry->pos + len, entry->text + entry->pos,
(entry->text_len-entry->pos + 1) * sizeof(unichar));
+ /* make space for the color */
+ if (entry->uses_extents) {
+ g_memmove(entry->extents + entry->pos + len + 1, entry->extents + entry->pos + 1,
+ (entry->text_len-entry->pos) * sizeof(char *));
+ for (i = 0; i < len; i++) {
+ entry->extents[entry->pos + i + 1] = NULL;
+ }
+ }
+
if (!entry->utf8) {
if (term_type == TERM_TYPE_BIG5) {
chr = entry->text[entry->pos + len];
@@ -514,7 +642,7 @@ void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str)
void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
{
- g_return_if_fail(entry != NULL);
+ g_return_if_fail(entry != NULL);
if (chr == 0 || chr == 13 || chr == 10)
return; /* never insert NUL, CR or LF characters */
@@ -522,7 +650,7 @@ void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
if (entry->utf8 && entry->pos == 0 && mk_wcwidth(chr) == 0)
return;
- gui_entry_redraw_from(entry, entry->pos);
+ gui_entry_redraw_from(entry, entry->pos);
entry_text_grow(entry, 1);
@@ -530,9 +658,15 @@ void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
g_memmove(entry->text + entry->pos + 1, entry->text + entry->pos,
(entry->text_len-entry->pos + 1) * sizeof(unichar));
+ if (entry->uses_extents) {
+ g_memmove(entry->extents + entry->pos + 1 + 1, entry->extents + entry->pos + 1,
+ (entry->text_len-entry->pos) * sizeof(char *));
+ entry->extents[entry->pos + 1] = NULL;
+ }
+
entry->text[entry->pos] = chr;
entry->text_len++;
- entry->pos++;
+ entry->pos++;
gui_entry_fix_cursor(entry);
gui_entry_draw(entry);
@@ -631,7 +765,7 @@ static GUI_ENTRY_CUTBUFFER_REC *get_cutbuffer_rec(GUI_ENTRY_REC *entry, CUTBUFFE
void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_cutbuffer)
{
- size_t w = 0;
+ size_t i, w = 0;
g_return_if_fail(entry != NULL);
@@ -700,6 +834,23 @@ void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_
g_memmove(entry->text + entry->pos - size, entry->text + entry->pos,
(entry->text_len-entry->pos+1) * sizeof(unichar));
+ if (entry->uses_extents) {
+ for (i = entry->pos - size; i < entry->pos; i++) {
+ if (entry->extents[i+1] != NULL) {
+ g_free(entry->extents[i+1]);
+ }
+ }
+ g_memmove(entry->extents + entry->pos - size + 1, entry->extents + entry->pos + 1,
+ (entry->text_len - entry->pos) * sizeof(void *)); /* no null terminator here */
+ for (i = 0; i < size; i++) {
+ entry->extents[entry->text_len - i] = NULL;
+ }
+ if (entry->text_len == size && entry->extents[0] != NULL) {
+ g_free(entry->extents[0]);
+ entry->extents[0] = NULL;
+ }
+ }
+
entry->pos -= size;
entry->text_len -= size;
@@ -719,11 +870,28 @@ void gui_entry_erase_cell(GUI_ENTRY_REC *entry)
mk_wcwidth(entry->text[entry->pos+size]) == 0) size++;
g_memmove(entry->text + entry->pos, entry->text + entry->pos + size,
- (entry->text_len-entry->pos-size+1) * sizeof(unichar));
+ (entry->text_len-entry->pos-size+1) * sizeof(unichar));
+
+ if (entry->uses_extents) {
+ int i;
+ for (i = 0; i < size; i++) {
+ g_free(entry->extents[entry->pos + i + 1]);
+ }
+ g_memmove(entry->extents + entry->pos + 1, entry->extents + entry->pos + size + 1,
+ (entry->text_len-entry->pos-size) * sizeof(char *));
+ for (i = 0; i < size; i++) {
+ entry->extents[entry->text_len - i] = NULL;
+ }
+ if (entry->text_len == size && entry->extents[0] != NULL) {
+ g_free(entry->extents[0]);
+ entry->extents[0] = NULL;
+ }
+ }
entry->text_len -= size;
gui_entry_redraw_from(entry, entry->pos);
+ gui_entry_fix_cursor(entry);
gui_entry_draw(entry);
}
@@ -782,6 +950,7 @@ void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPD
void gui_entry_transpose_chars(GUI_ENTRY_REC *entry)
{
unichar chr;
+ char *extent;
if (entry->pos == 0 || entry->text_len < 2)
return;
@@ -794,6 +963,12 @@ void gui_entry_transpose_chars(GUI_ENTRY_REC *entry)
entry->text[entry->pos] = entry->text[entry->pos-1];
entry->text[entry->pos-1] = chr;
+ if (entry->uses_extents) {
+ extent = entry->extents[entry->pos+1];
+ entry->extents[entry->pos+1] = entry->extents[entry->pos];
+ entry->extents[entry->pos] = extent;
+ }
+
entry->pos++;
gui_entry_redraw_from(entry, entry->pos-2);
@@ -830,31 +1005,60 @@ void gui_entry_transpose_words(GUI_ENTRY_REC *entry)
/* do wordswap if any found */
if (spos1 < epos1 && epos1 < spos2 && spos2 < epos2) {
unichar *first, *sep, *second;
+ char **first_extent, **sep_extent, **second_extent;
int i;
first = (unichar *) g_malloc( (epos1 - spos1) * sizeof(unichar) );
sep = (unichar *) g_malloc( (spos2 - epos1) * sizeof(unichar) );
second = (unichar *) g_malloc( (epos2 - spos2) * sizeof(unichar) );
- for (i = spos1; i < epos1; i++)
+ first_extent = (char **) g_malloc( (epos1 - spos1) * sizeof(char *) );
+ sep_extent = (char **) g_malloc( (spos2 - epos1) * sizeof(char *) );
+ second_extent = (char **) g_malloc( (epos2 - spos2) * sizeof(char *) );
+
+ for (i = spos1; i < epos1; i++) {
first[i-spos1] = entry->text[i];
- for (i = epos1; i < spos2; i++)
+ if (entry->uses_extents)
+ first_extent[i-spos1] = entry->extents[i+1];
+ }
+ for (i = epos1; i < spos2; i++) {
sep[i-epos1] = entry->text[i];
- for (i = spos2; i < epos2; i++)
+ if (entry->uses_extents)
+ sep_extent[i-epos1] = entry->extents[i+1];
+ }
+ for (i = spos2; i < epos2; i++) {
second[i-spos2] = entry->text[i];
+ if (entry->uses_extents)
+ second_extent[i-spos2] = entry->extents[i+1];
+ }
entry->pos = spos1;
- for (i = 0; i < epos2-spos2; i++)
- entry->text[entry->pos++] = second[i];
- for (i = 0; i < spos2-epos1; i++)
- entry->text[entry->pos++] = sep[i];
- for (i = 0; i < epos1-spos1; i++)
- entry->text[entry->pos++] = first[i];
+ for (i = 0; i < epos2-spos2; i++) {
+ entry->text[entry->pos] = second[i];
+ if (entry->uses_extents)
+ entry->extents[entry->pos+1] = second_extent[i];
+ entry->pos++;
+ }
+ for (i = 0; i < spos2-epos1; i++) {
+ entry->text[entry->pos] = sep[i];
+ if (entry->uses_extents)
+ entry->extents[entry->pos+1] = sep_extent[i];
+ entry->pos++;
+ }
+ for (i = 0; i < epos1-spos1; i++) {
+ entry->text[entry->pos] = first[i];
+ if (entry->uses_extents)
+ entry->extents[entry->pos+1] = first_extent[i];
+ entry->pos++;
+ }
g_free(first);
g_free(sep);
g_free(second);
+ g_free(first_extent);
+ g_free(sep_extent);
+ g_free(second_extent);
}
gui_entry_redraw_from(entry, spos1);
@@ -938,11 +1142,17 @@ void gui_entry_set_pos(GUI_ENTRY_REC *entry, int pos)
void gui_entry_set_text_and_pos_bytes(GUI_ENTRY_REC *entry, const char *str, int pos_bytes)
{
- int pos;
+ int pos, extents_alloc;
+ char **extents;
const char *ptr;
g_return_if_fail(entry != NULL);
+ extents = entry->extents;
+ extents_alloc = entry->text_alloc;
+ entry->extents = NULL;
+ entry->uses_extents = FALSE;
+
gui_entry_set_text(entry, str);
if (entry->utf8) {
@@ -953,6 +1163,19 @@ void gui_entry_set_text_and_pos_bytes(GUI_ENTRY_REC *entry, const char *str, int
else
pos = pos_bytes;
+ if (extents != NULL) {
+ entry->uses_extents = TRUE;
+ entry->extents = extents;
+ if (extents_alloc < entry->text_alloc) {
+ int i;
+ entry->extents = g_realloc(entry->extents,
+ sizeof(char *) * entry->text_alloc);
+ for (i = extents_alloc; i < entry->text_alloc; i++) {
+ entry->extents[i] = NULL;
+ }
+ }
+ }
+ gui_entry_redraw_from(entry, 0);
gui_entry_set_pos(entry, pos);
}
@@ -1042,3 +1265,234 @@ void gui_entry_redraw(GUI_ENTRY_REC *entry)
gui_entry_fix_cursor(entry);
gui_entry_draw(entry);
}
+
+static void gui_entry_alloc_extents(GUI_ENTRY_REC *entry)
+{
+ entry->uses_extents = TRUE;
+ entry->extents = g_new0(char *, entry->text_alloc);
+}
+
+void gui_entry_set_extent(GUI_ENTRY_REC *entry, int pos, const char *text)
+{
+ int update = FALSE;
+
+ g_return_if_fail(entry != NULL);
+
+ if (pos < 0 || pos > entry->text_len)
+ return;
+
+ if (text == NULL)
+ return;
+
+ if (!entry->uses_extents) {
+ gui_entry_alloc_extents(entry);
+ }
+
+ if (g_strcmp0(entry->extents[pos], text) != 0) {
+ g_free(entry->extents[pos]);
+ if (*text == '\0') {
+ entry->extents[pos] = NULL;
+ } else {
+ entry->extents[pos] = g_strdup(text);
+ }
+ update = TRUE;
+ }
+
+ if (update) {
+ gui_entry_redraw_from(entry, pos - 1);
+ gui_entry_fix_cursor(entry);
+ gui_entry_draw(entry);
+ }
+}
+
+void gui_entry_set_extents(GUI_ENTRY_REC *entry, int pos, int len, const char *left, const char *right)
+{
+ int end, update = FALSE;
+
+ g_return_if_fail(entry != NULL);
+
+ if (pos < 0 || len < 0 || pos > entry->text_len)
+ return;
+
+ end = pos + len;
+
+ if (end > entry->text_len)
+ end = entry->text_len;
+
+ if (!entry->uses_extents) {
+ gui_entry_alloc_extents(entry);
+ }
+
+ if (g_strcmp0(entry->extents[pos], left) != 0) {
+ g_free(entry->extents[pos]);
+ if (*left == '\0') {
+ entry->extents[pos] = NULL;
+ } else {
+ entry->extents[pos] = g_strdup(left);
+ }
+ update = TRUE;
+ }
+
+ if (pos != end && g_strcmp0(entry->extents[end], right) != 0) {
+ g_free(entry->extents[end]);
+ if (*right == '\0') {
+ entry->extents[end] = NULL;
+ } else {
+ entry->extents[end] = g_strdup(right);
+ }
+ update = TRUE;
+ }
+
+ if (update) {
+ gui_entry_redraw_from(entry, pos - 1);
+ gui_entry_fix_cursor(entry);
+ gui_entry_draw(entry);
+ }
+}
+
+void gui_entry_clear_extents(GUI_ENTRY_REC *entry, int pos, int len)
+{
+ int i, end, update = FALSE;
+
+ g_return_if_fail(entry != NULL);
+
+ if (pos < 0 || len < 0 || pos > entry->text_len)
+ return;
+
+ end = pos + len;
+
+ if (end > entry->text_len)
+ end = entry->text_len;
+
+ if (!entry->uses_extents) {
+ return;
+ }
+
+ for (i = pos; i <= end; i++) {
+ if (entry->extents[i] != NULL) {
+ g_free(entry->extents[i]);
+ entry->extents[i] = NULL;
+ update = TRUE;
+ }
+ }
+
+ if (update) {
+ gui_entry_redraw_from(entry, pos);
+ gui_entry_fix_cursor(entry);
+ gui_entry_draw(entry);
+ }
+}
+
+char *gui_entry_get_extent(GUI_ENTRY_REC *entry, int pos)
+{
+ g_return_val_if_fail(entry != NULL, NULL);
+
+ if (!entry->uses_extents)
+ return NULL;
+
+ if (pos < 0 || pos >= entry->text_len)
+ return NULL;
+
+ return entry->extents[pos];
+}
+
+#define POS_FLAG "%|"
+GSList *gui_entry_get_text_and_extents(GUI_ENTRY_REC *entry)
+{
+ GSList *list = NULL;
+ GString *str;
+ int i;
+
+ g_return_val_if_fail(entry != NULL, NULL);
+
+ if (entry->uses_extents && entry->extents[0] != NULL) {
+ if (entry->pos == 0) {
+ list = g_slist_prepend(list, g_strconcat(entry->extents[0], POS_FLAG, NULL));
+ } else {
+ list = g_slist_prepend(list, g_strdup(entry->extents[0]));
+ }
+ } else {
+ if (entry->pos == 0) {
+ list = g_slist_prepend(list, g_strdup(POS_FLAG));
+ } else {
+ list = g_slist_prepend(list, NULL);
+ }
+ }
+
+ str = g_string_sized_new(entry->text_alloc);
+ for (i = 0; i < entry->text_len; i++) {
+ if (entry->utf8) {
+ g_string_append_unichar(str, entry->text[i]);
+ } else if (term_type == TERM_TYPE_BIG5) {
+ if(entry->text[i] > 0xff)
+ g_string_append_c(str, (entry->text[i] >> 8) & 0xff);
+ g_string_append_c(str, entry->text[i] & 0xff);
+ } else {
+ g_string_append_c(str, entry->text[i]);
+ }
+ if (entry->pos == i+1 || (entry->uses_extents && entry->extents[i+1] != NULL)) {
+ list = g_slist_prepend(list, g_strdup(str->str));
+ g_string_truncate(str, 0);
+ if (entry->uses_extents && entry->extents[i+1] != NULL) {
+ if (entry->pos == i+1) {
+ list = g_slist_prepend(list, g_strconcat(entry->extents[i+1], POS_FLAG, NULL));
+ } else {
+ list = g_slist_prepend(list, g_strdup(entry->extents[i+1]));
+ }
+ } else if (entry->pos == i+1) {
+ list = g_slist_prepend(list, g_strdup(POS_FLAG));
+ }
+ }
+ }
+ if (str->len > 0) {
+ list = g_slist_prepend(list, g_strdup(str->str));
+ }
+ list = g_slist_reverse(list);
+ g_string_free(str, TRUE);
+
+ return list;
+}
+
+void gui_entry_set_text_and_extents(GUI_ENTRY_REC *entry, GSList *list)
+{
+ GSList *tmp;
+ int pos = -1;
+ int is_extent = 1;
+
+ gui_entry_set_text(entry, "");
+ for (tmp = list, is_extent = TRUE; tmp != NULL; tmp = tmp->next, is_extent ^= 1) {
+ if (is_extent) {
+ char *extent;
+ int len;
+
+ if (tmp->data == NULL)
+ continue;
+
+ extent = g_strdup(tmp->data);
+ len = strlen(extent);
+ if (len >= strlen(POS_FLAG) && g_strcmp0(&extent[len-strlen(POS_FLAG)], POS_FLAG) == 0) {
+ char *tmp;
+ tmp = extent;
+ extent = g_strndup(tmp, len - strlen(POS_FLAG));
+ g_free(tmp);
+ pos = entry->pos;
+ }
+
+ if (strlen(extent) > 0) {
+ gui_entry_set_extent(entry, entry->pos, extent);
+ }
+ g_free(extent);
+ } else {
+ gui_entry_insert_text(entry, tmp->data);
+ }
+ }
+ gui_entry_set_pos(entry, pos);
+}
+
+void gui_entry_init(void)
+{
+}
+
+void gui_entry_deinit(void)
+{
+}
diff --git a/src/fe-text/gui-entry.h b/src/fe-text/gui-entry.h
index 000c5f03..dff860d3 100644
--- a/src/fe-text/gui-entry.h
+++ b/src/fe-text/gui-entry.h
@@ -9,6 +9,7 @@ typedef struct {
typedef struct {
int text_len, text_alloc; /* as shorts, not chars */
unichar *text;
+ char **extents;
GSList *kill_ring;
@@ -26,6 +27,7 @@ typedef struct {
unsigned int previous_append_next_kill:1;
unsigned int append_next_kill:1;
unsigned int yank_preceded:1;
+ unsigned int uses_extents:1;
} GUI_ENTRY_REC;
typedef enum {
@@ -77,5 +79,14 @@ void gui_entry_move_words(GUI_ENTRY_REC *entry, int count, int to_space);
void gui_entry_redraw(GUI_ENTRY_REC *entry);
+void gui_entry_set_extent(GUI_ENTRY_REC *entry, int pos, const char *text);
+void gui_entry_set_extents(GUI_ENTRY_REC *entry, int pos, int len, const char *left, const char *right);
+void gui_entry_clear_extents(GUI_ENTRY_REC *entry, int pos, int len);
+char *gui_entry_get_extent(GUI_ENTRY_REC *entry, int pos);
+GSList *gui_entry_get_text_and_extents(GUI_ENTRY_REC *entry);
+void gui_entry_set_text_and_extents(GUI_ENTRY_REC *entry, GSList *list);
+
+void gui_entry_init(void);
+void gui_entry_deinit(void);
#endif
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 b3a78396..88e827a7 100644
--- a/src/fe-text/gui-readline.c
+++ b/src/fe-text/gui-readline.c
@@ -1174,6 +1174,7 @@ void gui_readline_init(void)
key_bind("key", NULL, "^H", "backspace", (SIGNAL_FUNC) key_combo);
key_bind("key", NULL, "^?", "backspace", (SIGNAL_FUNC) key_combo);
key_bind("key", NULL, "^I", "tab", (SIGNAL_FUNC) key_combo);
+ key_bind("key", NULL, "meta2-Z", "stab", (SIGNAL_FUNC) key_combo);
/* meta */
key_bind("key", NULL, "^[", "meta", (SIGNAL_FUNC) key_combo);
@@ -1278,7 +1279,7 @@ void gui_readline_init(void)
/* line transmitting */
key_bind("send_line", "Execute the input line", "return", NULL, (SIGNAL_FUNC) key_send_line);
- key_bind("word_completion_backward", "", NULL, NULL, (SIGNAL_FUNC) key_word_completion_backward);
+ key_bind("word_completion_backward", "Choose previous completion suggestion", "stab", NULL, (SIGNAL_FUNC) key_word_completion_backward);
key_bind("word_completion", "Complete the current word", "tab", NULL, (SIGNAL_FUNC) key_word_completion);
key_bind("erase_completion", "Remove the completion added by word_completion", "meta-k", NULL, (SIGNAL_FUNC) key_erase_completion);
key_bind("check_replaces", "Check word replaces", NULL, NULL, (SIGNAL_FUNC) key_check_replaces);
diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c
index 34c55772..3efb9803 100644
--- a/src/fe-text/gui-windows.c
+++ b/src/fe-text/gui-windows.c
@@ -75,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);
@@ -285,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 ef443670..f30ce4b8 100644
--- a/src/fe-text/irssi.c
+++ b/src/fe-text/irssi.c
@@ -165,6 +165,7 @@ static void textui_finish_init(void)
gui_expandos_init();
gui_printtext_init();
gui_readline_init();
+ gui_entry_init();
lastlog_init();
mainwindows_init();
mainwindow_activity_init();
@@ -207,6 +208,8 @@ static void textui_finish_init(void)
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)
@@ -228,6 +231,7 @@ static void textui_deinit(void)
lastlog_deinit();
statusbar_deinit();
+ gui_entry_deinit();
gui_printtext_deinit();
gui_readline_deinit();
gui_windows_deinit();
diff --git a/src/fe-text/mainwindows-layout.c b/src/fe-text/mainwindows-layout.c
index acbcb6b9..17c6647b 100644
--- a/src/fe-text/mainwindows-layout.c
+++ b/src/fe-text/mainwindows-layout.c
@@ -55,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)
@@ -71,7 +71,7 @@ static void sig_layout_window_restore(WINDOW_REC *window, CONFIG_NODE *node)
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);
}
}
@@ -84,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)
@@ -98,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
@@ -118,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;
@@ -133,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) {
@@ -188,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));
+
+ new_win = window_create(NULL, TRUE);
- window = window_create(NULL, TRUE);
- window_set_refnum(window, atoi(node->key));
+ 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;
@@ -216,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..83a3e0cc 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 (destroy_win->last_line < destroy_win->first_line)
+ return;
- if (last_line < first_line)
+ if (destroy_win->last_column < destroy_win->first_column)
return;
- size = last_line-first_line+1;
+ rsize = destroy_win->last_column-destroy_win->first_column+1;
+ rec = mainwindows_find_left(destroy_win, FALSE);
+ if (rec != NULL) {
+ rec->last_column = destroy_win->last_column;
+ mainwindow_resize(rec, rsize+1, 0);
+ return;
+ }
- rec = mainwindows_find_lower(last_line);
+ rec = mainwindows_find_right(destroy_win, FALSE);
if (rec != NULL) {
- rec->first_line = first_line;
- mainwindow_resize(rec, 0, size);
+ rec->first_column = destroy_win->first_column;
+ mainwindow_resize(rec, rsize+1, 0);
return;
}
- rec = mainwindows_find_upper(first_line);
+ size = destroy_win->last_line-destroy_win->first_line+1;
+
+ rec = mainwindows_find_lower(destroy_win);
if (rec != NULL) {
- rec->last_line = last_line;
- mainwindow_resize(rec, 0, size);
+ 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 (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 (xdiff > 0) {
+ /* algorithm: distribute new space on each line */
+ MAIN_WINDOW_REC *win;
- signal_emit("terminal resized", 0);
+ 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) {
+ /* algorithm: shrink windows starting from bottom,
+ destroy windows starting from top if no room */
+ mainwindows_resize_smaller(ydiff);
+ }
+
+ 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,113 @@ 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;
+ g_return_val_if_fail(count >= 0, FALSE);
+
+ 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;
+ g_return_val_if_fail(count >= 0, FALSE);
+
+ 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,32 +1017,58 @@ 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)
{
+ g_return_val_if_fail(count >= 0, FALSE);
+
if (MAIN_WINDOW_TEXT_HEIGHT(window)-count < WINDOW_MIN_SIZE)
return FALSE;
@@ -627,6 +1082,115 @@ 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;
+
+ g_return_val_if_fail(count >= 0, FALSE);
+
+ 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;
+
+ g_return_val_if_fail(count >= 0, FALSE);
+
+ 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)
+{
+ g_return_val_if_fail(count >= 0, FALSE);
+
+ 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 +1203,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 +1226,23 @@ 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);
+ }
+ }
+}
+
+static void mainwindow_grow_int(int count)
+{
+ if (count == 0) {
+ return;
+ } else if (count < 0) {
+ if (!mainwindow_shrink(WINDOW_MAIN(active_win), -count, FALSE)) {
+ printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, TXT_WINDOW_TOO_SMALL);
+ }
+ } else {
+ if (!mainwindow_grow(WINDOW_MAIN(active_win), count, FALSE)) {
+ printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, TXT_WINDOW_TOO_SMALL);
}
}
}
@@ -660,16 +1250,11 @@ void mainwindows_redraw_dirty(void)
/* SYNTAX: WINDOW GROW [<lines>] */
static void cmd_window_grow(const char *data)
{
- MAIN_WINDOW_REC *window;
int count;
count = *data == '\0' ? 1 : atoi(data);
- window = WINDOW_MAIN(active_win);
- if (!mainwindow_grow(window, count, FALSE)) {
- printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
- TXT_WINDOW_TOO_SMALL);
- }
+ mainwindow_grow_int(count);
}
/* SYNTAX: WINDOW SHRINK [<lines>] */
@@ -678,16 +1263,14 @@ static void cmd_window_shrink(const char *data)
int count;
count = *data == '\0' ? 1 : atoi(data);
- if (!mainwindow_shrink(WINDOW_MAIN(active_win), count, FALSE)) {
- printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
- TXT_WINDOW_TOO_SMALL);
- }
+ if (count < -INT_MAX) count = -INT_MAX;
+
+ mainwindow_grow_int(-count);
}
/* SYNTAX: WINDOW SIZE <lines> */
static void cmd_window_size(const char *data)
{
- char sizestr[MAX_INT_STRLEN];
int size;
if (!is_numeric(data, 0)) return;
@@ -695,47 +1278,60 @@ static void cmd_window_size(const char *data)
size -= WINDOW_MAIN(active_win)->height -
WINDOW_MAIN(active_win)->statusbar_lines;
- if (size == 0) return;
+ if (size < -INT_MAX) size = -INT_MAX;
- ltoa(sizestr, size < 0 ? -size : size);
- if (size < 0)
- cmd_window_shrink(sizestr);
- else
- cmd_window_grow(sizestr);
+ mainwindow_grow_int(size);
}
/* 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);
+ }
+ if (line != NULL && bigger_units > 0) {
+ bigger_units--;
+ }
+ last_line = win->last_line+1;
- mainwindow_resize(rec, 0, rec->height-old_size);
+ g_slist_free(line);
}
g_slist_free(sorted);
@@ -769,29 +1365,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 +1401,161 @@ 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(right);
+ if (parent == NULL) {
+ printformat_window(active_win, MSGLEVEL_CLIENTERROR, TXT_WINDOW_TOO_SMALL);
+ return;
}
- parent = mainwindow_create();
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);
+}
+
+static void window_rgrow_int(int count)
+{
+ if (count == 0) {
+ return;
+ } else if (count < 0) {
+ if (!mainwindow_rshrink(WINDOW_MAIN(active_win), -count)) {
+ printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, TXT_WINDOW_TOO_SMALL);
+ }
+ } else {
+ if (!mainwindow_rgrow(WINDOW_MAIN(active_win), count)) {
+ printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, TXT_WINDOW_TOO_SMALL);
+ }
+ }
+}
+
+/* SYNTAX: WINDOW RGROW [<columns>] */
+static void cmd_window_rgrow(const char *data)
+{
+ int count;
+
+ count = *data == '\0' ? 1 : atoi(data);
+
+ window_rgrow_int(count);
+}
+
+/* SYNTAX: WINDOW RSHRINK [<lines>] */
+static void cmd_window_rshrink(const char *data)
+{
+ int count;
+
+ count = *data == '\0' ? 1 : atoi(data);
+ if (count < -INT_MAX) count = -INT_MAX;
+
+ window_rgrow_int(-count);
+}
+
+/* SYNTAX: WINDOW RSIZE <columns> */
+static void cmd_window_rsize(const char *data)
+{
+ int rsize;
+
+ if (!is_numeric(data, 0)) return;
+ rsize = atoi(data);
+
+ rsize -= MAIN_WINDOW_TEXT_WIDTH(WINDOW_MAIN(active_win));
+
+ window_rgrow_int(rsize);
+}
+
+/* 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_upper(term_height);
+ 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(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 +1565,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(-1);
+ 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_right(active_mainwin, TRUE);
if (rec != NULL)
window_set_active(rec->active);
}
@@ -997,13 +1749,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 +1788,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 +1834,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 +1853,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 +1888,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 b8a26192..b234f46c 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 },
@@ -87,7 +87,7 @@ FORMAT_REC gui_text_formats[] =
"|_ _|_ _ _____(_)%:"
" | || '_(_-<_-< |%:"
"|___|_| /__/__/_|%:"
- "Irssi v$J - http://www.irssi.org", 0 },
+ "Irssi v$J - https://irssi.org", 0 },
{ "welcome_firsttime",
"- - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"
"Hi there! If this is your first time using Irssi, you%:"
diff --git a/src/fe-text/statusbar-items.c b/src/fe-text/statusbar-items.c
index c7d6bcfb..5740a40b 100644
--- a/src/fe-text/statusbar-items.c
+++ b/src/fe-text/statusbar-items.c
@@ -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-view.c b/src/fe-text/textbuffer-view.c
index b54f1c8e..99625ecc 100644
--- a/src/fe-text/textbuffer-view.c
+++ b/src/fe-text/textbuffer-view.c
@@ -394,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;
@@ -405,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);
@@ -469,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++;
}
@@ -479,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;
@@ -517,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);
@@ -534,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
@@ -751,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--;
}
}
@@ -793,51 +801,51 @@ static int view_scroll(TEXT_BUFFER_VIEW_REC *view, LINE_REC **lines,
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;
}
}
@@ -845,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();
+ }
}
}
diff --git a/src/perl/textui/TextUI.xs b/src/perl/textui/TextUI.xs
index 5d2c8a7f..e2f162a0 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);
@@ -123,6 +124,74 @@ gui_input_set(str)
CODE:
gui_entry_set_text(active_entry, str);
+void
+gui_input_set_extent(pos, text)
+ int pos
+ char *text
+PREINIT:
+ char *tt;
+CODE:
+ tt = text != NULL ? format_string_expand(text, NULL) : NULL;
+ gui_entry_set_extent(active_entry, pos, tt);
+ g_free(tt);
+
+void
+gui_input_set_extents(pos, len, left, right)
+ int pos
+ int len
+ char *left
+ char *right
+PREINIT:
+ char *tl;
+ char *tr;
+CODE:
+ tl = left != NULL ? format_string_expand(left, NULL) : NULL;
+ tr = right != NULL ? format_string_expand(right, NULL) : NULL;
+ gui_entry_set_extents(active_entry, pos, len, tl, tr);
+ g_free(tl);
+ g_free(tr);
+
+void
+gui_input_clear_extents(pos, len = 0)
+ int pos
+ int len
+CODE:
+ gui_entry_clear_extents(active_entry, pos, len);
+
+void
+gui_input_get_extent(pos)
+ int pos
+PREINIT:
+ char *ret;
+PPCODE:
+ ret = gui_entry_get_extent(active_entry, pos);
+ XPUSHs(sv_2mortal(new_pv(ret)));
+ g_free(ret);
+
+void
+gui_input_get_text_and_extents()
+PREINIT:
+ GSList *ret, *tmp;
+PPCODE:
+ ret = gui_entry_get_text_and_extents(active_entry);
+ for (tmp = ret; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(new_pv(tmp->data)));
+ }
+ g_slist_free_full(ret, g_free);
+
+void
+gui_input_set_text_and_extents(...)
+PREINIT:
+ GSList *list;
+ int i;
+PPCODE:
+ list = NULL;
+ for (i = items; i > 0; i--) {
+ list = g_slist_prepend(list, SvPV_nolen(ST(i-1)));
+ }
+ gui_entry_set_text_and_extents(active_entry, list);
+ g_slist_free(list);
+
int
gui_input_get_pos()
CODE:
diff --git a/tests/fe-common/core/Makefile.am b/tests/fe-common/core/Makefile.am
index 070b6052..f048e95c 100644
--- a/tests/fe-common/core/Makefile.am
+++ b/tests/fe-common/core/Makefile.am
@@ -21,8 +21,7 @@ test_formats_LDADD = \
../../../src/fe-common/core/libfe_common_core.a \
../../../src/core/libcore.a \
../../../src/lib-config/libirssi_config.a \
- @GLIB_LIBS@ \
- @OPENSSL_LIBS@
+ @PROG_LIBS@
test_formats_SOURCES = \
test-formats.c
diff --git a/tests/fe-common/core/test-formats.c b/tests/fe-common/core/test-formats.c
index 9ef23fd6..aee5a219 100644
--- a/tests/fe-common/core/test-formats.c
+++ b/tests/fe-common/core/test-formats.c
@@ -15,7 +15,7 @@ format_real_length_test_case const format_real_length_fixtures[] = {
{
.description = "",
.input = "%4%w ",
- .result = { 0, 5, 5, -1 },
+ .result = { 4, 5, 5, -1 },
},
};
@@ -31,7 +31,9 @@ int main(int argc, char **argv)
g_free(name);
}
+#if GLIB_CHECK_VERSION(2,38,0)
g_test_set_nonfatal_assertions();
+#endif
return g_test_run();
}
diff --git a/tests/irc/core/Makefile.am b/tests/irc/core/Makefile.am
index ccc6aa97..86f1d547 100644
--- a/tests/irc/core/Makefile.am
+++ b/tests/irc/core/Makefile.am
@@ -22,8 +22,7 @@ test_irc_LDADD = \
../../../src/irc/core/libirc_core.a \
../../../src/core/libcore.a \
../../../src/lib-config/libirssi_config.a \
- @GLIB_LIBS@ \
- @OPENSSL_LIBS@
+ @PROG_LIBS@
test_irc_SOURCES = \
test-irc.c
diff --git a/tests/irc/core/test-irc.c b/tests/irc/core/test-irc.c
index c96956df..3eaf7020 100644
--- a/tests/irc/core/test-irc.c
+++ b/tests/irc/core/test-irc.c
@@ -197,7 +197,9 @@ int main(int argc, char **argv)
g_free(name);
}
+#if GLIB_CHECK_VERSION(2,38,0)
g_test_set_nonfatal_assertions();
+#endif
return g_test_run();
}
diff --git a/themes/default.theme b/themes/default.theme
index 956d7c4f..79b1af55 100644
--- a/themes/default.theme
+++ b/themes/default.theme
@@ -251,6 +251,7 @@ abstracts = {
# default background for all statusbars. You can also give
# the default foreground color for statusbar items.
sb_background = "%4%w";
+ window_border = "%4%w";
# default backround for "default" statusbar group
#sb_default_bg = "%4";
diff --git a/utils/tap-test b/utils/tap-test
index 481e333e..b3ef8b04 100755
--- a/utils/tap-test
+++ b/utils/tap-test
@@ -2,4 +2,22 @@
# run a GTest in tap mode. The test binary is passed as $1
-$1 -k --tap
+t="$1"; shift
+if ${PKG_CONFIG:-pkg-config} --atleast-version 2.40 glib-2.0; then
+exec "$t" -k --tap "$@"
+else # GTest does not support tap yet
+ (((("$t" "$@"; echo $? >&3) | ${AM_TAP_AWK:-awk} '
+{
+ if (/: /) {
+ i++
+ ok = /: OK/
+ sub(/:/, " #")
+ print (ok ? "ok " : "not ok ") i " " $0
+ } else {
+ print "# " $0
+ }
+} END {
+ print 1 ".." i
+}
+' >&4) 3>&1) | (read xs; exit $xs)) 4>&1
+fi