summaryrefslogtreecommitdiff
path: root/src/fe-text
diff options
context:
space:
mode:
Diffstat (limited to 'src/fe-text')
-rw-r--r--src/fe-text/Makefile.am46
-rw-r--r--src/fe-text/gui-entry.c177
-rw-r--r--src/fe-text/gui-entry.h22
-rw-r--r--src/fe-text/gui-mainwindows.c66
-rw-r--r--src/fe-text/gui-mainwindows.h21
-rw-r--r--src/fe-text/gui-printtext.c334
-rw-r--r--src/fe-text/gui-printtext.h28
-rw-r--r--src/fe-text/gui-readline.c374
-rw-r--r--src/fe-text/gui-readline.h10
-rw-r--r--src/fe-text/gui-special-vars.c61
-rw-r--r--src/fe-text/gui-special-vars.h7
-rw-r--r--src/fe-text/gui-statusbar-items.c691
-rw-r--r--src/fe-text/gui-statusbar-items.h7
-rw-r--r--src/fe-text/gui-statusbar.c237
-rw-r--r--src/fe-text/gui-statusbar.h21
-rw-r--r--src/fe-text/gui-textwidget.c390
-rw-r--r--src/fe-text/gui-textwidget.h7
-rw-r--r--src/fe-text/gui-windows.c780
-rw-r--r--src/fe-text/gui-windows.h93
-rw-r--r--src/fe-text/irssi.c156
-rw-r--r--src/fe-text/module-formats.c30
-rw-r--r--src/fe-text/module-formats.h11
-rw-r--r--src/fe-text/module.h6
-rw-r--r--src/fe-text/screen.c254
-rw-r--r--src/fe-text/screen.h31
25 files changed, 3860 insertions, 0 deletions
diff --git a/src/fe-text/Makefile.am b/src/fe-text/Makefile.am
new file mode 100644
index 00000000..c651cf0e
--- /dev/null
+++ b/src/fe-text/Makefile.am
@@ -0,0 +1,46 @@
+bin_PROGRAMS = irssi-text
+
+INCLUDES = \
+ $(GLIB_CFLAGS) \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/core/ \
+ -I$(top_srcdir)/src/irc/core/ \
+ -I$(top_srcdir)/src/fe-common/core/ \
+ -I$(top_srcdir)/src/fe-common/irc/ \
+ $(CURSES_INCLUDEDIR)
+
+irssi_text_DEPENDENCIES = @COMMON_LIBS@
+
+irssi_text_LDADD = \
+ @COMMON_LIBS@ \
+ $(PROG_LIBS) \
+ $(CURSES_LIBS) \
+ $(INTLLIBS) \
+ $(PERL_LDFLAGS)
+
+irssi_text_SOURCES = \
+ gui-entry.c \
+ gui-mainwindows.c \
+ gui-printtext.c \
+ gui-readline.c \
+ gui-special-vars.c \
+ gui-statusbar.c \
+ gui-statusbar-items.c \
+ gui-textwidget.c \
+ gui-windows.c \
+ irssi.c \
+ module-formats.c \
+ screen.c
+
+noinst_HEADERS = \
+ gui-entry.h \
+ gui-mainwindows.h \
+ gui-printtext.h \
+ gui-readline.h \
+ gui-special-vars.h \
+ gui-statusbar.h \
+ gui-statusbar-items.h \
+ gui-textwidget.h \
+ gui-windows.h \
+ module-formats.h \
+ screen.h
diff --git a/src/fe-text/gui-entry.c b/src/fe-text/gui-entry.c
new file mode 100644
index 00000000..d4505195
--- /dev/null
+++ b/src/fe-text/gui-entry.c
@@ -0,0 +1,177 @@
+/*
+ gui-entry.c : irssi
+
+ Copyright (C) 1999 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+
+#include "screen.h"
+
+static GString *entry;
+static int promptlen, pos, scrstart, scrpos;
+static char *prompt;
+
+static void entry_screenpos(void)
+{
+ if (pos-scrstart < COLS-1-promptlen && pos-scrstart > 0) {
+ scrpos = pos-scrstart;
+ return;
+ }
+
+ if (pos < COLS-1-promptlen) {
+ scrstart = 0;
+ scrpos = pos;
+ } else {
+ scrpos = COLS-1-promptlen;
+ scrstart = pos-scrpos;
+ }
+}
+
+static void entry_update(void)
+{
+ char *p;
+ int n, len;
+
+ len = entry->len-scrstart > COLS-promptlen ?
+ COLS-promptlen : entry->len-scrstart;
+
+ set_color(0);
+ move(LINES-1, promptlen);
+
+ for (p = entry->str+scrstart, n = 0; n < len; n++, p++) {
+ if ((unsigned char) *p >= 32)
+ addch((unsigned char) *p);
+ else {
+ set_color(ATTR_REVERSE);
+ addch(*p+'A'-1);
+ set_color(0);
+ }
+ }
+ clrtoeol();
+
+ move_cursor(LINES-1, scrpos+promptlen);
+ screen_refresh();
+}
+
+void gui_entry_set_prompt(const char *str)
+{
+ if (str != NULL) {
+ if (prompt != NULL) g_free(prompt);
+ prompt = g_strdup(str);
+
+ promptlen = strlen(prompt);
+ if (promptlen > 20) {
+ promptlen = 20;
+ prompt[20] = '\0';
+ }
+ }
+
+ set_color(0);
+ mvaddstr(LINES-1, 0, prompt);
+
+ entry_screenpos();
+ entry_update();
+}
+
+void gui_entry_set_text(const char *str)
+{
+ g_return_if_fail(str != NULL);
+
+ g_string_assign(entry, str);
+ pos = entry->len;
+
+ entry_screenpos();
+ entry_update();
+}
+
+char *gui_entry_get_text(void)
+{
+ return entry->str;
+}
+
+void gui_entry_insert_text(const char *str)
+{
+ g_return_if_fail(str != NULL);
+
+ g_string_insert(entry, pos, str);
+ pos += strlen(str);
+
+ entry_screenpos();
+ entry_update();
+}
+
+void gui_entry_insert_char(char chr)
+{
+ g_string_insert_c(entry, pos, chr);
+ pos++;
+
+ entry_screenpos();
+ entry_update();
+}
+
+void gui_entry_erase(int size)
+{
+ if (pos < size) return;
+
+ pos -= size;
+ g_string_erase(entry, pos, size);
+
+ entry_screenpos();
+ entry_update();
+}
+
+int gui_entry_get_pos(void)
+{
+ return pos;
+}
+
+void gui_entry_set_pos(int p)
+{
+ if (p >= 0 && p <= entry->len)
+ pos = p;
+}
+
+void gui_entry_move_pos(int p)
+{
+ if (pos+p >= 0 && pos+p <= entry->len)
+ pos += p;
+
+ entry_screenpos();
+ entry_update();
+}
+
+void gui_entry_redraw(void)
+{
+ gui_entry_set_prompt(NULL);
+
+ entry_screenpos();
+ entry_update();
+}
+
+void gui_entry_init(void)
+{
+ entry = g_string_new(NULL);
+ pos = scrpos = 0;
+ prompt = NULL; promptlen = 0;
+}
+
+void gui_entry_deinit(void)
+{
+ if (prompt != NULL) g_free(prompt);
+ g_string_free(entry, TRUE);
+}
diff --git a/src/fe-text/gui-entry.h b/src/fe-text/gui-entry.h
new file mode 100644
index 00000000..443d2509
--- /dev/null
+++ b/src/fe-text/gui-entry.h
@@ -0,0 +1,22 @@
+#ifndef __GUI_ENTRY_H
+#define __GUI_ENTRY_H
+
+void gui_entry_set_prompt(const char *str);
+
+void gui_entry_set_text(const char *str);
+char *gui_entry_get_text(void);
+
+void gui_entry_insert_text(const char *str);
+void gui_entry_insert_char(char chr);
+void gui_entry_erase(int size);
+
+int gui_entry_get_pos(void);
+void gui_entry_set_pos(int pos);
+void gui_entry_move_pos(int pos);
+
+void gui_entry_redraw(void);
+
+void gui_entry_init(void);
+void gui_entry_deinit(void);
+
+#endif
diff --git a/src/fe-text/gui-mainwindows.c b/src/fe-text/gui-mainwindows.c
new file mode 100644
index 00000000..d5d66c1d
--- /dev/null
+++ b/src/fe-text/gui-mainwindows.c
@@ -0,0 +1,66 @@
+/*
+ gui-mainwindows.c : irssi
+
+ Copyright (C) 1999 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "signals.h"
+
+#include "windows.h"
+#include "gui-mainwindows.h"
+
+GList *mainwindows;
+
+MAIN_WINDOW_REC *gui_mainwindow_create(void)
+{
+ MAIN_WINDOW_REC *window;
+
+ window = g_new0(MAIN_WINDOW_REC, 1);
+ mainwindows = g_list_append(mainwindows, window);
+
+ return window;
+}
+
+void gui_mainwindow_destroy(MAIN_WINDOW_REC *window)
+{
+ g_return_if_fail(window != NULL);
+ if (window->destroying) return;
+
+ mainwindows = g_list_remove(mainwindows, window);
+
+ window->destroying = TRUE;
+ while (window->children != NULL)
+ window_destroy(window->children->data);
+ window->destroying = FALSE;
+
+ g_free(window);
+
+ if (mainwindows == NULL)
+ signal_emit("gui exit", 0);
+}
+
+void gui_mainwindows_init(void)
+{
+ mainwindows = NULL;
+}
+
+void gui_mainwindows_deinit(void)
+{
+ while (mainwindows != NULL)
+ gui_mainwindow_destroy(mainwindows->data);
+}
diff --git a/src/fe-text/gui-mainwindows.h b/src/fe-text/gui-mainwindows.h
new file mode 100644
index 00000000..b91f35a9
--- /dev/null
+++ b/src/fe-text/gui-mainwindows.h
@@ -0,0 +1,21 @@
+#ifndef __GUI_MAINWINDOWS_H
+#define __GUI_MAINWINDOWS_H
+
+#include "windows.h"
+
+typedef struct {
+ WINDOW_REC *active;
+ GList *children;
+
+ int destroying;
+} MAIN_WINDOW_REC;
+
+extern GList *mainwindows;
+
+void gui_mainwindows_init(void);
+void gui_mainwindows_deinit(void);
+
+MAIN_WINDOW_REC *gui_mainwindow_create(void);
+void gui_mainwindow_destroy(MAIN_WINDOW_REC *window);
+
+#endif
diff --git a/src/fe-text/gui-printtext.c b/src/fe-text/gui-printtext.c
new file mode 100644
index 00000000..1ef4aa32
--- /dev/null
+++ b/src/fe-text/gui-printtext.c
@@ -0,0 +1,334 @@
+/*
+ gui-printtext.c : irssi
+
+ Copyright (C) 1999 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "signals.h"
+#include "commands.h"
+#include "settings.h"
+
+#include "printtext.h"
+#include "windows.h"
+#include "themes.h"
+
+#include "screen.h"
+#include "gui-mainwindows.h"
+#include "gui-windows.h"
+
+#define TEXT_CHUNK_USABLE_SIZE (LINE_TEXT_CHUNK_SIZE-2-sizeof(char*))
+
+static gint mirc_colors[] = { 15, 0, 1, 2, 4, 6, 5, 4, 14, 10, 3, 11, 9, 13, 8, 7, 15 };
+static gint max_textwidget_lines;
+
+static LINE_REC *create_line(GUI_WINDOW_REC *gui, gint level)
+{
+ g_return_val_if_fail(gui != NULL, NULL);
+ g_return_val_if_fail(gui->cur_text != NULL, NULL);
+
+ gui->cur_line = g_mem_chunk_alloc(gui->line_chunk);
+ gui->cur_line->text = gui->cur_text->buffer+gui->cur_text->pos;
+ gui->cur_line->level = (gint32) GPOINTER_TO_INT(level);
+ gui->cur_line->time = time(NULL);
+
+ gui->last_color = -1;
+ gui->last_flags = 0;
+
+ gui->lines = g_list_append(gui->lines, gui->cur_line);
+ if (gui->startline == NULL)
+ {
+ gui->startline = gui->lines;
+ gui->bottom_startline = gui->lines;
+ }
+ return gui->cur_line;
+}
+
+static TEXT_CHUNK_REC *create_text_chunk(GUI_WINDOW_REC *gui)
+{
+ TEXT_CHUNK_REC *rec;
+ guchar *buffer;
+ gchar *ptr;
+
+ g_return_val_if_fail(gui != NULL, NULL);
+
+ rec = g_new(TEXT_CHUNK_REC, 1);
+ rec->pos = 0;
+ rec->lines = 0;
+
+ if (gui->cur_line != NULL && gui->cur_line->text != NULL)
+ {
+ /* mark the next block text block position.. */
+ buffer = (guchar *) gui->cur_text->buffer+gui->cur_text->pos;
+ if (gui->cur_text->pos+2+sizeof(gchar *) > LINE_TEXT_CHUNK_SIZE)
+ g_error("create_text_chunk() : buffer overflow?!");
+ *buffer++ = 0; *buffer++ = LINE_CMD_CONTINUE;
+ ptr = rec->buffer;
+ memcpy(buffer, &ptr, sizeof(gchar *));
+ }
+ gui->cur_text = rec;
+ gui->text_chunks = g_slist_append(gui->text_chunks, rec);
+ return rec;
+}
+
+static void text_chunk_free(GUI_WINDOW_REC *gui, TEXT_CHUNK_REC *chunk)
+{
+ g_return_if_fail(gui != NULL);
+ g_return_if_fail(chunk != NULL);
+
+ gui->text_chunks = g_slist_remove(gui->text_chunks, chunk);
+ g_free(chunk);
+}
+
+static void remove_first_line(WINDOW_REC *window)
+{
+ GUI_WINDOW_REC *gui;
+ TEXT_CHUNK_REC *chunk;
+
+ g_return_if_fail(window != NULL);
+
+ gui = WINDOW_GUI(window);
+ chunk = gui->text_chunks->data;
+
+ if (--chunk->lines == 0)
+ text_chunk_free(gui, chunk);
+
+ if (gui->startline->prev == NULL)
+ {
+ gui->startline = gui->startline->next;
+ gui->subline = 0;
+ }
+ if (gui->bottom_startline->prev == NULL)
+ {
+ gui->bottom_startline = gui->bottom_startline->next;
+ gui->bottom_subline = 0;
+ }
+
+ window->lines--;
+ g_mem_chunk_free(gui->line_chunk, gui->lines->data);
+ gui->lines = g_list_remove(gui->lines, gui->lines->data);
+
+ if (gui->startline->prev == NULL && is_window_visible(window))
+ gui_window_redraw(window);
+}
+
+static void get_colors(gint flags, gint *fg, gint *bg)
+{
+ if (flags & PRINTFLAG_MIRC_COLOR)
+ {
+ /* mirc colors */
+ *fg = *fg < 0 || *fg > 16 ?
+ current_theme->default_color : mirc_colors[*fg];
+ *bg = *bg < 0 || *bg > 16 ? 0 : mirc_colors[*bg];
+ }
+ else
+ {
+ /* default colors */
+ *fg = *fg < 0 || *fg > 15 ?
+ current_theme->default_color : *fg;
+ *bg = *bg < 0 || *bg > 15 ? 0 : *bg;
+
+ if (*fg > 8) *fg -= 8;
+ }
+
+ if (flags & PRINTFLAG_REVERSE)
+ {
+ gint tmp;
+
+ tmp = *fg; *fg = *bg; *bg = tmp;
+ }
+
+ if (*fg == 8) *fg |= ATTR_COLOR8;
+ if (flags & PRINTFLAG_BOLD) *fg |= 8;
+ if (flags & PRINTFLAG_UNDERLINE) *fg |= ATTR_UNDERLINE;
+ if (flags & PRINTFLAG_BLINK) *bg |= 0x80;
+}
+
+static void linebuf_add(GUI_WINDOW_REC *gui, gchar *str, gint len)
+{
+ gint left;
+
+ if (len == 0) return;
+
+ while (gui->cur_text->pos+len >= TEXT_CHUNK_USABLE_SIZE)
+ {
+ left = TEXT_CHUNK_USABLE_SIZE-gui->cur_text->pos;
+ if (str[left-1] == 0) left--; /* don't split the command! */
+ memcpy(gui->cur_text->buffer+gui->cur_text->pos, str, left);
+ gui->cur_text->pos += left;
+ create_text_chunk(gui);
+ len -= left; str += left;
+ }
+
+ memcpy(gui->cur_text->buffer+gui->cur_text->pos, str, len);
+ gui->cur_text->pos += len;
+}
+
+static void line_add_colors(GUI_WINDOW_REC *gui, gint fg, gint bg, gint flags)
+{
+ guchar buffer[12];
+ gint color, pos;
+
+ color = (fg & 0x0f) | (bg << 4);
+ pos = 0;
+
+ if (((fg & ATTR_COLOR8) == 0 && (fg|(bg << 4)) != gui->last_color) ||
+ ((fg & ATTR_COLOR8) && (fg & 0xf0) != (gui->last_color & 0xf0)))
+ {
+ buffer[pos++] = 0;
+ buffer[pos++] = (gchar) color;
+ }
+
+ if ((flags & PRINTFLAG_UNDERLINE) != (gui->last_flags & PRINTFLAG_UNDERLINE))
+ {
+ buffer[pos++] = 0;
+ buffer[pos++] = LINE_CMD_UNDERLINE;
+ }
+ if (fg & ATTR_COLOR8)
+ {
+ buffer[pos++] = 0;
+ buffer[pos++] = LINE_CMD_COLOR8;
+ }
+ if (flags & PRINTFLAG_BEEP)
+ {
+ buffer[pos++] = 0;
+ buffer[pos++] = LINE_CMD_BEEP;
+ }
+ if (flags & PRINTFLAG_INDENT)
+ {
+ buffer[pos++] = 0;
+ buffer[pos++] = LINE_CMD_INDENT;
+ }
+
+ linebuf_add(gui, (gchar *) buffer, pos);
+
+ gui->last_flags = flags;
+ gui->last_color = fg | (bg << 4);
+}
+
+static void gui_printtext(WINDOW_REC *window, gpointer fgcolor, gpointer bgcolor, gpointer pflags, gchar *str, gpointer level)
+{
+ GUI_WINDOW_REC *gui;
+ LINE_REC *line;
+ gboolean visible;
+ gint fg, bg, flags, lines, n;
+
+ g_return_if_fail(window != NULL);
+
+ gui = WINDOW_GUI(window);
+ if (max_textwidget_lines > 0 && max_textwidget_lines <= window->lines)
+ remove_first_line(window);
+
+ visible = is_window_visible(window) && gui->bottom;
+ flags = GPOINTER_TO_INT(pflags);
+ fg = GPOINTER_TO_INT(fgcolor);
+ bg = GPOINTER_TO_INT(bgcolor);
+
+ if (gui->cur_text == NULL)
+ create_text_chunk(gui);
+
+ /* \n can be only at the start of the line.. */
+ if (*str == '\n')
+ {
+ linebuf_add(gui, "\0\x80", 2); /* mark EOL */
+ line = create_line(gui, 0);
+ gui_window_newline(gui, visible);
+ str++;
+ gui->cur_text->lines++;
+ gui->last_subline = 0;
+ }
+ else
+ {
+ line = gui->cur_line != NULL ? gui->cur_line :
+ create_line(gui, 0);
+ if (line->level == 0) line->level = GPOINTER_TO_INT(level);
+ }
+
+ get_colors(flags, &fg, &bg);
+ line_add_colors(gui, fg, bg, flags);
+ linebuf_add(gui, str, strlen(str));
+
+ /* temporarily mark the end of line. */
+ memcpy(gui->cur_text->buffer+gui->cur_text->pos, "\0\x80", 2);
+
+ if (visible)
+ {
+ /* draw the line to screen. */
+ lines = gui_window_line_draw(gui, line, first_text_line+gui->ypos, gui->last_subline, -1);
+ }
+ else
+ {
+ /* we still need to update the bottom's position */
+ lines = gui_window_get_linecount(gui, line)-1-gui->last_subline;
+ for (n = 0; n < lines; n++)
+ gui_window_newline(gui, visible);
+ }
+ if (lines > 0) gui->last_subline += lines;
+}
+
+static void cmd_clear(gchar *data)
+{
+ GUI_WINDOW_REC *gui;
+ gint n;
+
+ gui = WINDOW_GUI(active_win);
+
+ if (is_window_visible(active_win))
+ {
+ for (n = first_text_line; n < last_text_line; n++)
+ {
+ move(n, 0);
+ clrtoeol();
+ }
+ screen_refresh();
+ }
+
+ gui->ypos = -1;
+ gui->bottom_startline = gui->startline = g_list_last(gui->lines);
+ gui->bottom_subline = gui->subline = gui->last_subline+1;
+ gui->empty_linecount = last_text_line-first_text_line;
+ gui->bottom = TRUE;
+}
+
+static void sig_printtext_finished(WINDOW_REC *window)
+{
+ if (is_window_visible(window))
+ screen_refresh();
+}
+
+static void read_settings(void)
+{
+ max_textwidget_lines = settings_get_int("max_textwidget_lines");
+}
+
+void gui_printtext_init(void)
+{
+ signal_add("gui print text", (SIGNAL_FUNC) gui_printtext);
+ command_bind("clear", NULL, (SIGNAL_FUNC) cmd_clear);
+ signal_add("print text finished", (SIGNAL_FUNC) sig_printtext_finished);
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+
+ read_settings();
+}
+
+void gui_printtext_deinit(void)
+{
+ signal_remove("gui print text", (SIGNAL_FUNC) gui_printtext);
+ command_unbind("clear", (SIGNAL_FUNC) cmd_clear);
+ signal_remove("print text finished", (SIGNAL_FUNC) sig_printtext_finished);
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+}
diff --git a/src/fe-text/gui-printtext.h b/src/fe-text/gui-printtext.h
new file mode 100644
index 00000000..6c6e24d9
--- /dev/null
+++ b/src/fe-text/gui-printtext.h
@@ -0,0 +1,28 @@
+#ifndef __GUI_PRINTTEXT_H
+#define __GUI_PRINTTEXT_H
+
+enum
+{
+ BLACK = 0,
+ BLUE,
+ GREEN,
+ CYAN,
+ RED,
+ MAGENTA,
+ YELLOW,
+ WHITE,
+ BBLACK,
+ BBLUE,
+ BGREEN,
+ BCYAN,
+ BRED,
+ BMAGENTA,
+ BYELLOW,
+ BWHITE,
+ NUM_COLORS
+};
+
+void gui_printtext_init(void);
+void gui_printtext_deinit(void);
+
+#endif
diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c
new file mode 100644
index 00000000..e53c628b
--- /dev/null
+++ b/src/fe-text/gui-readline.c
@@ -0,0 +1,374 @@
+/*
+ gui-readline.c : irssi
+
+ Copyright (C) 1999 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "signals.h"
+#include "server.h"
+#include "misc.h"
+
+#include "completion.h"
+#include "command-history.h"
+#include "keyboard.h"
+#include "translation.h"
+#include "windows.h"
+
+#include "screen.h"
+#include "gui-entry.h"
+#include "gui-mainwindows.h"
+#include "gui-windows.h"
+
+#include <signal.h>
+
+static gint readtag, sigint_count = 0;
+static time_t idle_time;
+
+static void window_prev_page(void)
+{
+ gui_window_scroll(active_win, -(last_text_line-first_text_line)/2);
+}
+
+static void window_next_page(void)
+{
+ gui_window_scroll(active_win, (last_text_line-first_text_line)/2);
+}
+
+static char *get_key_name(int key)
+{
+ static char str[MAX_INT_STRLEN];
+
+ switch (key) {
+ case KEY_HOME:
+ return "Home";
+ case KEY_END:
+ return "End";
+ case KEY_PPAGE:
+ return "Prior";
+ case KEY_NPAGE:
+ return "Next";
+ case KEY_UP:
+ return "Up";
+ case KEY_DOWN:
+ return "Down";
+ case KEY_LEFT:
+ return "Left";
+ case KEY_RIGHT:
+ return "Right";
+ default:
+ ltoa(str, key);
+ return str;
+ }
+}
+
+void handle_key(gint key)
+{
+ const char *text;
+ char *str;
+ int c;
+
+ /* Quit if we get 5 CTRL-C's in a row. */
+ if (key != 3)
+ sigint_count = 0;
+ else if (++sigint_count >= 5)
+ raise(SIGTERM);
+
+ idle_time = time(NULL);
+ switch (key)
+ {
+ case 27:
+ c = getch();
+ if (c == toupper(c) && c != tolower(c))
+ str = g_strdup_printf("ALT-SHIFT-%c", c);
+ else {
+ if (c < 256)
+ str = g_strdup_printf("ALT-%c", toupper(c));
+ else
+ str = g_strdup_printf("ALT-%s", get_key_name(c));
+ }
+ key_pressed(str, NULL);
+ g_free(str);
+ break;
+
+ case KEY_HOME:
+ /* home */
+ gui_entry_set_pos(0);
+ gui_entry_move_pos(0);
+ break;
+ case KEY_END:
+ /* end */
+ gui_entry_set_pos(strlen(gui_entry_get_text()));
+ gui_entry_move_pos(0);
+ break;
+ case KEY_PPAGE:
+ /* page up */
+ window_prev_page();
+ break;
+ case KEY_NPAGE:
+ /* page down */
+ window_next_page();
+ break;
+
+ case KEY_UP:
+ /* up */
+ text = command_history_prev(active_win, gui_entry_get_text());
+ gui_entry_set_text(text);
+ break;
+ case KEY_DOWN:
+ /* down */
+ text = command_history_next(active_win, gui_entry_get_text());
+ gui_entry_set_text(text);
+ break;
+ case KEY_RIGHT:
+ /* right */
+ gui_entry_move_pos(1);
+ break;
+ case KEY_LEFT:
+ /* left */
+ gui_entry_move_pos(-1);
+ break;
+
+ case 21:
+ /* Ctrl-U, clear line */
+ gui_entry_set_text("");
+ break;
+
+ case 9:
+ key_pressed("Tab", NULL);
+ break;
+
+ case 8:
+ case 127:
+ case KEY_BACKSPACE:
+ gui_entry_erase(1);
+ break;
+
+ case 0:
+ /* Ctrl-space - ignore */
+ break;
+ case 1:
+ /* C-A, home */
+ gui_entry_set_pos(0);
+ gui_entry_move_pos(0);
+ break;
+ case 5:
+ /* C-E, end */
+ gui_entry_set_pos(strlen(gui_entry_get_text()));
+ gui_entry_move_pos(0);
+ break;
+
+ case '\n':
+ case 13:
+ key_pressed("Return", NULL);
+
+ str = gui_entry_get_text();
+ if (*str == '\0') break;
+
+ translate_output(str);
+ signal_emit("send command", 3, str, active_win->active_server, active_win->active);
+
+ command_history_add(active_win, gui_entry_get_text(), FALSE);
+ gui_entry_set_text("");
+ command_history_clear_pos(active_win);
+ break;
+
+ default:
+ if (key > 0 && key < 32)
+ {
+ str = g_strdup_printf("CTRL-%c", key == 31 ? '-' : key+'A'-1);
+ key_pressed(str, NULL);
+ g_free(str);
+ break;
+ }
+
+ if (key < 256)
+ {
+ gchar str[2];
+
+ str[0] = toupper(key); str[1] = '\0';
+ key_pressed(str, NULL);
+ gui_entry_insert_char((gchar) key);
+ }
+ break;
+ }
+}
+
+void readline(void)
+{
+ gint key;
+
+ for (;;)
+ {
+ key = getch();
+ if (key == ERR) break;
+
+ handle_key(key);
+ }
+}
+
+time_t get_idle_time(void)
+{
+ return idle_time;
+}
+
+static void sig_prev_page(void)
+{
+ window_prev_page();
+}
+
+static void sig_next_page(void)
+{
+ window_next_page();
+}
+
+static void sig_change_window(gchar *data)
+{
+ signal_emit("command window goto", 3, data, active_win->active_server, active_win->active);
+}
+
+static void sig_completion(void)
+{
+ gchar *line;
+ gint pos;
+
+ pos = gui_entry_get_pos();
+
+ line = completion_line(active_win, gui_entry_get_text(), &pos);
+ if (line != NULL)
+ {
+ gui_entry_set_text(line);
+ gui_entry_set_pos(pos);
+ g_free(line);
+ }
+}
+
+static void sig_replace(void)
+{
+ gchar *line;
+ gint pos;
+
+ pos = gui_entry_get_pos();
+
+ line = auto_completion(gui_entry_get_text(), &pos);
+ if (line != NULL)
+ {
+ gui_entry_set_text(line);
+ gui_entry_set_pos(pos);
+ g_free(line);
+ }
+}
+
+static void sig_prev_window(void)
+{
+ signal_emit("command window prev", 3, "", active_win->active_server, active_win->active);
+}
+
+static void sig_next_window(void)
+{
+ signal_emit("command window next", 3, "", active_win->active_server, active_win->active);
+}
+
+static void sig_window_goto_active(void)
+{
+ signal_emit("command window goto", 3, "active", active_win->active_server, active_win->active);
+}
+
+static void sig_prev_channel(void)
+{
+ signal_emit("command channel prev", 3, "", active_win->active_server, active_win->active);
+}
+
+static void sig_next_channel(void)
+{
+ signal_emit("command channel next", 3, "", active_win->active_server, active_win->active);
+}
+
+static void sig_addchar(gchar *data)
+{
+ gui_entry_insert_char(*data);
+}
+
+static void signal_window_auto_changed(WINDOW_REC *window)
+{
+ command_history_next(active_win, gui_entry_get_text());
+ gui_entry_set_text("");
+}
+
+void gui_readline_init(void)
+{
+ static gchar changekeys[] = "1234567890QWERTYUIO";
+ gchar *key, *data;
+ gint n;
+
+ idle_time = time(NULL);
+ readtag = g_input_add(0, G_INPUT_READ, (GInputFunction) readline, NULL);
+
+ key_bind("completion", NULL, "Nick completion", "Tab", (SIGNAL_FUNC) sig_completion);
+ key_bind("check replaces", NULL, "Check word replaces", " ", (SIGNAL_FUNC) sig_replace);
+ key_bind("check replaces", NULL, NULL, "Return", (SIGNAL_FUNC) sig_replace);
+ key_bind("window prev", NULL, "Previous window", "CTRL-P", (SIGNAL_FUNC) sig_prev_window);
+ key_bind("window prev", NULL, NULL, "ALT-Left", (SIGNAL_FUNC) sig_prev_window);
+ key_bind("window next", NULL, "Next window", "CTRL-N", (SIGNAL_FUNC) sig_next_window);
+ key_bind("window next", NULL, NULL, "ALT-Right", (SIGNAL_FUNC) sig_next_window);
+ key_bind("window active", NULL, "Go to next window with the highest activity", "ALT-A", (SIGNAL_FUNC) sig_window_goto_active);
+ key_bind("channel next", NULL, "Next channel", "CTRL-X", (SIGNAL_FUNC) sig_next_channel);
+ key_bind("channel prev", NULL, "Next channel", NULL, (SIGNAL_FUNC) sig_prev_channel);
+
+ key_bind("redraw", NULL, "Redraw window", "CTRL-L", (SIGNAL_FUNC) irssi_redraw);
+ key_bind("prev page", NULL, "Previous page", "ALT-P", (SIGNAL_FUNC) sig_prev_page);
+ key_bind("next page", NULL, "Next page", "ALT-N", (SIGNAL_FUNC) sig_next_page);
+
+ key_bind("special char", "\x02", "Insert special character", "CTRL-B", (SIGNAL_FUNC) sig_addchar);
+ key_bind("special char", "\x1f", NULL, "CTRL--", (SIGNAL_FUNC) sig_addchar);
+ key_bind("special char", "\x03", NULL, "CTRL-C", (SIGNAL_FUNC) sig_addchar);
+ key_bind("special char", "\x16", NULL, "CTRL-V", (SIGNAL_FUNC) sig_addchar);
+ key_bind("special char", "\x07", NULL, "CTRL-G", (SIGNAL_FUNC) sig_addchar);
+ key_bind("special char", "\x0f", NULL, "CTRL-O", (SIGNAL_FUNC) sig_addchar);
+
+ for (n = 0; changekeys[n] != '\0'; n++)
+ {
+ key = g_strdup_printf("ALT-%c", changekeys[n]);
+ data = g_strdup_printf("%d", n+1);
+ key_bind("change window", data, "Change window", key, (SIGNAL_FUNC) sig_change_window);
+ g_free(data); g_free(key);
+ }
+
+ signal_add("window changed automatic", (SIGNAL_FUNC) signal_window_auto_changed);
+}
+
+void gui_readline_deinit(void)
+{
+ g_source_remove(readtag);
+
+ key_unbind("completion", (SIGNAL_FUNC) sig_completion);
+ key_unbind("check replaces", (SIGNAL_FUNC) sig_replace);
+ key_unbind("window prev", (SIGNAL_FUNC) sig_prev_window);
+ key_unbind("window next", (SIGNAL_FUNC) sig_next_window);
+ key_unbind("window active", (SIGNAL_FUNC) sig_window_goto_active);
+ key_unbind("channel next", (SIGNAL_FUNC) sig_next_channel);
+ key_unbind("channel prev", (SIGNAL_FUNC) sig_prev_channel);
+
+ key_unbind("redraw", (SIGNAL_FUNC) irssi_redraw);
+ key_unbind("prev page", (SIGNAL_FUNC) sig_prev_page);
+ key_unbind("next page", (SIGNAL_FUNC) sig_next_page);
+
+ key_unbind("special char", (SIGNAL_FUNC) sig_addchar);
+ key_unbind("change window", (SIGNAL_FUNC) sig_change_window);
+
+ signal_remove("window changed automatic", (SIGNAL_FUNC) signal_window_auto_changed);
+}
diff --git a/src/fe-text/gui-readline.h b/src/fe-text/gui-readline.h
new file mode 100644
index 00000000..d6be0d59
--- /dev/null
+++ b/src/fe-text/gui-readline.h
@@ -0,0 +1,10 @@
+#ifndef __GUI_READLINE_H
+#define __GUI_READLINE_H
+
+void readline(void);
+time_t get_idle_time(void);
+
+void gui_readline_init(void);
+void gui_readline_deinit(void);
+
+#endif
diff --git a/src/fe-text/gui-special-vars.c b/src/fe-text/gui-special-vars.c
new file mode 100644
index 00000000..ac648ff1
--- /dev/null
+++ b/src/fe-text/gui-special-vars.c
@@ -0,0 +1,61 @@
+/*
+ gui-special-vars.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "special-vars.h"
+
+#include "gui-entry.h"
+#include "gui-readline.h"
+
+/* idle time */
+static char *expando_idletime(void *server, void *item, int *free_ret)
+{
+ int diff;
+
+ *free_ret = TRUE;
+ diff = (int) (time(NULL) - get_idle_time());
+ return g_strdup_printf("%d", diff);
+}
+
+/* current contents of the input line */
+static char *expando_inputline(void *server, void *item, int *free_ret)
+{
+ return gui_entry_get_text();
+}
+
+/* FIXME: value of cutbuffer */
+static char *expando_cutbuffer(void *server, void *item, int *free_ret)
+{
+ return NULL;
+}
+
+void gui_special_vars_init(void)
+{
+ expando_create("E", expando_idletime);
+ expando_create("L", expando_inputline);
+ expando_create("U", expando_cutbuffer);
+}
+
+void gui_special_vars_deinit(void)
+{
+ expando_destroy("E", expando_idletime);
+ expando_destroy("L", expando_inputline);
+ expando_destroy("U", expando_cutbuffer);
+}
diff --git a/src/fe-text/gui-special-vars.h b/src/fe-text/gui-special-vars.h
new file mode 100644
index 00000000..392efc85
--- /dev/null
+++ b/src/fe-text/gui-special-vars.h
@@ -0,0 +1,7 @@
+#ifndef __GUI_SPECIAL_VARS_H
+#define __GUI_SPECIAL_VARS_H
+
+void gui_special_vars_init(void);
+void gui_special_vars_deinit(void);
+
+#endif
diff --git a/src/fe-text/gui-statusbar-items.c b/src/fe-text/gui-statusbar-items.c
new file mode 100644
index 00000000..1bb1c6f0
--- /dev/null
+++ b/src/fe-text/gui-statusbar-items.c
@@ -0,0 +1,691 @@
+/*
+ gui-statusbar-items.c : irssi
+
+ Copyright (C) 1999 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "signals.h"
+#include "server.h"
+#include "misc.h"
+#include "settings.h"
+
+#include "irc.h"
+#include "channels.h"
+#include "query.h"
+#include "irc-server.h"
+#include "nicklist.h"
+
+#include "windows.h"
+
+#include "screen.h"
+#include "gui-statusbar.h"
+#include "gui-mainwindows.h"
+#include "gui-windows.h"
+
+/* how often to redraw lagging time */
+#define LAG_REFRESH_TIME 10
+/* If we haven't been able to check lag for this long, "(??)" is added after
+ the lag */
+#define MAX_LAG_UNKNOWN_TIME 30
+
+/* clock */
+static int clock_tag, clock_timetag;
+static time_t clock_last;
+
+/* nick */
+static int nick_tag;
+
+/* channel */
+static int channel_tag;
+
+/* activity */
+static int activity_tag;
+static GList *activity_list;
+
+/* more */
+static int more_tag;
+
+/* lag */
+static int lag_tag, lag_timetag, lag_min_show;
+static time_t lag_last_draw;
+
+/* topic */
+static int topic_tag;
+
+/* redraw clock */
+static void statusbar_clock(int xpos, int ypos, int size)
+{
+ struct tm *tm;
+ gchar str[5];
+
+ clock_last = time(NULL);
+ tm = localtime(&clock_last);
+
+ sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min);
+
+ move(ypos, xpos);
+ set_color((1 << 4)+3); addch('[');
+ set_color((1 << 4)+15); addstr(str);
+ set_color((1 << 4)+3); addch(']');
+
+ screen_refresh();
+}
+
+/* check if we need to redraw clock.. */
+static int statusbar_clock_timeout(void)
+{
+ struct tm *tm;
+ time_t t;
+ int min;
+
+ tm = localtime(&clock_last);
+ min = tm->tm_min;
+
+ t = time(NULL);
+ tm = localtime(&t);
+
+ if (tm->tm_min != min)
+ {
+ /* minute changed, redraw! */
+ gui_statusbar_redraw(clock_tag);
+ }
+ return 1;
+}
+
+/* redraw nick */
+static void statusbar_nick(int xpos, int ypos, int size)
+{
+ CHANNEL_REC *channel;
+ IRC_SERVER_REC *server;
+ NICK_REC *nickrec;
+ int size_needed;
+ int umode_size;
+ gchar nick[10];
+
+ server = (IRC_SERVER_REC *) (active_win == NULL ? NULL : active_win->active_server);
+
+ umode_size = server == NULL || server->usermode == NULL ? 0 : strlen(server->usermode)+3;
+
+ /* nick */
+ if (server == NULL || server->nick == NULL)
+ {
+ nick[0] = '\0';
+ nickrec = NULL;
+ }
+ else
+ {
+ strncpy(nick, server->nick, 9);
+ nick[9] = '\0';
+
+ channel = irc_item_channel(active_win->active);
+ nickrec = channel == NULL ? NULL : nicklist_find(channel, server->nick);
+ }
+
+ size_needed = 2 + strlen(nick) + umode_size +
+ (server != NULL && server->usermode_away ? 7 : 0) +
+ (nickrec != NULL && (nickrec->op || nickrec->voice) ? 1 : 0); /* @ + */
+
+ if (size != size_needed)
+ {
+ /* we need more (or less..) space! */
+ gui_statusbar_resize(nick_tag, size_needed);
+ return;
+ }
+
+ /* size ok, draw the nick */
+ move(ypos, xpos);
+
+ set_color((1 << 4)+3); addch('[');
+ if (nickrec != NULL && (nickrec->op || nickrec->voice))
+ {
+ set_color((1 << 4)+15); addch(nickrec->op ? '@' : '+');
+ }
+ set_color((1 << 4)+7); addstr(nick);
+ if (umode_size)
+ {
+ set_color((1 << 4)+15); addch('(');
+ set_color((1 << 4)+3); addch('+');
+ set_color((1 << 4)+7); addstr(server->usermode);
+ set_color((1 << 4)+15); addch(')');
+ if (server->usermode_away)
+ {
+ set_color((1 << 4)+7); addstr(" (");
+ set_color((1 << 4)+10); addstr("zZzZ");
+ set_color((1 << 4)+7); addch(')');
+ }
+ }
+ set_color((1 << 4)+3); addch(']');
+ screen_refresh();
+}
+
+static void sig_statusbar_nick_redraw(void)
+{
+ gui_statusbar_redraw(nick_tag);
+}
+
+/* redraw channel */
+static void statusbar_channel(int xpos, int ypos, int size)
+{
+ WI_ITEM_REC *item;
+ CHANNEL_REC *channel;
+ SERVER_REC *server;
+ gchar channame[21], window[MAX_INT_STRLEN], *mode;
+ int size_needed;
+ int mode_size;
+
+ server = active_win == NULL ? NULL : active_win->active_server;
+
+ ltoa(window, active_win == NULL ? 0 :
+ g_slist_index(windows, active_win)+1);
+
+ item = active_win != NULL && irc_item_check(active_win->active) ?
+ active_win->active : NULL;
+ if (item == NULL)
+ {
+ /* display server tag */
+ channame[0] = '\0';
+ mode = NULL;
+ mode_size = 0;
+
+ size_needed = 3 + strlen(window) + (server == NULL ? 0 : strlen(server->tag));
+ }
+ else
+ {
+ /* display channel + mode */
+ strncpy(channame, item->name, 20); channame[20] = '\0';
+
+ channel = irc_item_channel(item);
+ if (channel == NULL) {
+ mode_size = 0;
+ mode = NULL;
+ } else {
+ mode = channel_get_mode(channel);
+ mode_size = strlen(mode);
+ if (mode_size > 0) mode_size += 3; /* (+) */
+ }
+
+ size_needed = 3 + strlen(window) + strlen(channame) + mode_size;
+ }
+
+ if (size != size_needed)
+ {
+ /* we need more (or less..) space! */
+ gui_statusbar_resize(channel_tag, size_needed);
+ if (mode != NULL) g_free(mode);
+ return;
+ }
+
+ move(ypos, xpos);
+ set_color((1 << 4)+3); addch('[');
+
+ /* window number */
+ set_color((1 << 4)+7); addstr(window);
+ set_color((1 << 4)+3); addch(':');
+
+ if (channame[0] == '\0' && server != NULL)
+ {
+ /* server tag */
+ set_color((1 << 4)+7); addstr(server->tag);
+ }
+ else if (channame[0] != '\0')
+ {
+ /* channel + mode */
+ set_color((1 << 4)+7); addstr(channame);
+ if (mode_size)
+ {
+ set_color((1 << 4)+15); addch('(');
+ set_color((1 << 4)+3); addch('+');
+ set_color((1 << 4)+7); addstr(mode);
+ set_color((1 << 4)+15); addch(')');
+ }
+ }
+ set_color((1 << 4)+3); addch(']');
+ screen_refresh();
+
+ if (mode != NULL) g_free(mode);
+}
+
+static void sig_statusbar_channel_redraw(void)
+{
+ gui_statusbar_redraw(channel_tag);
+}
+
+static void draw_activity(gchar *title, gboolean act, gboolean det)
+{
+ WINDOW_REC *window;
+ GList *tmp;
+ gchar str[(sizeof(int) * CHAR_BIT + 2) / 3 + 1];
+ gboolean first, is_det;
+
+ set_color((1 << 4)+7); addstr(title);
+
+ first = TRUE;
+ for (tmp = activity_list; tmp != NULL; tmp = tmp->next)
+ {
+ window = tmp->data;
+
+ is_det = window->new_data == NEWDATA_MSG_FORYOU;
+ if (is_det && !det) continue;
+ if (!is_det && !act) continue;
+
+ if (first)
+ first = FALSE;
+ else
+ {
+ set_color((1 << 4)+3);
+ addch(',');
+ }
+
+ sprintf(str, "%d", g_slist_index(windows, window)+1);
+ switch (window->new_data)
+ {
+ case NEWDATA_TEXT:
+ set_color((1 << 4)+3);
+ break;
+ case NEWDATA_MSG:
+ set_color((1 << 4)+15);
+ break;
+ case NEWDATA_MSG_FORYOU:
+ set_color((1 << 4)+13);
+ break;
+ }
+ addstr(str);
+ }
+}
+
+/* redraw activity */
+static void statusbar_activity(int xpos, int ypos, int size)
+{
+ WINDOW_REC *window;
+ GList *tmp;
+ gchar str[MAX_INT_STRLEN];
+ int size_needed;
+ gboolean act, det;
+
+ size_needed = 0; act = det = FALSE;
+ for (tmp = activity_list; tmp != NULL; tmp = tmp->next)
+ {
+ window = tmp->data;
+
+ size_needed += 1+g_snprintf(str, sizeof(str), "%d", g_slist_index(windows, window)+1);
+
+ if (!use_colors && window->new_data == NEWDATA_MSG_FORYOU)
+ det = TRUE;
+ else
+ act = TRUE;
+ }
+
+ if (act) size_needed += 6; /* [Act: ], -1 */
+ if (det) size_needed += 6; /* [Det: ], -1 */
+ if (act && det) size_needed--;
+
+ if (size != size_needed)
+ {
+ /* we need more (or less..) space! */
+ gui_statusbar_resize(activity_tag, size_needed);
+ return;
+ }
+
+ if (size == 0)
+ return;
+
+ move(ypos, xpos);
+ set_color((1 << 4)+3); addch('[');
+ if (act) draw_activity("Act: ", TRUE, !det);
+ if (act && det) addch(' ');
+ if (det) draw_activity("Det: ", FALSE, TRUE);
+ set_color((1 << 4)+3); addch(']');
+
+ screen_refresh();
+}
+
+static void sig_statusbar_activity_hilight(WINDOW_REC *window, gpointer oldlevel)
+{
+ int pos, inspos;
+ GList *tmp;
+
+ g_return_if_fail(window != NULL);
+
+ if (settings_get_bool("toggle_actlist_moves"))
+ {
+ /* Move the window to the first in the activity list */
+ if (g_list_find(activity_list, window) != NULL)
+ activity_list = g_list_remove(activity_list, window);
+ if (window->new_data != 0)
+ activity_list = g_list_prepend(activity_list, window);
+ gui_statusbar_redraw(activity_tag);
+ return;
+ }
+
+ if (g_list_find(activity_list, window) != NULL)
+ {
+ /* already in activity list */
+ if (window->new_data == 0)
+ {
+ /* remove from activity list */
+ activity_list = g_list_remove(activity_list, window);
+ gui_statusbar_redraw(activity_tag);
+ }
+ else if (window->new_data != GPOINTER_TO_INT(oldlevel))
+ {
+ /* different level as last time, just redraw it. */
+ gui_statusbar_redraw(activity_tag);
+ }
+ return;
+ }
+
+ if (window->new_data == 0)
+ return;
+
+ /* add window to activity list .. */
+ pos = g_slist_index(windows, window);
+
+ inspos = 0;
+ for (tmp = activity_list; tmp != NULL; tmp = tmp->next, inspos++)
+ {
+ if (pos < g_slist_index(windows, tmp->data))
+ {
+ activity_list = g_list_insert(activity_list, window, inspos);
+ break;
+ }
+ }
+ if (tmp == NULL)
+ activity_list = g_list_append(activity_list, window);
+
+ gui_statusbar_redraw(activity_tag);
+}
+
+static void sig_statusbar_activity_window_destroyed(WINDOW_REC *window)
+{
+ g_return_if_fail(window != NULL);
+
+ if (g_list_find(activity_list, window) != NULL)
+ {
+ activity_list = g_list_remove(activity_list, window);
+ gui_statusbar_redraw(activity_tag);
+ }
+}
+
+/* redraw -- more -- */
+static void statusbar_more(int xpos, int ypos, int size)
+{
+ if (size != 10) return;
+
+ move(ypos, xpos);
+ set_color((1 << 4)+15); addstr("-- more --");
+ screen_refresh();
+}
+
+static void sig_statusbar_more_check_remove(WINDOW_REC *window)
+{
+ g_return_if_fail(window != NULL);
+
+ if (!is_window_visible(window))
+ return;
+
+ if (more_tag != -1 && WINDOW_GUI(window)->bottom)
+ {
+ gui_statusbar_remove(more_tag);
+ more_tag = -1;
+ }
+}
+
+static void sig_statusbar_more_check(WINDOW_REC *window)
+{
+ g_return_if_fail(window != NULL);
+
+ if (WINDOW_GUI(window)->parent->active != window)
+ return;
+
+ if (!WINDOW_GUI(window)->bottom)
+ {
+ if (more_tag == -1)
+ more_tag = gui_statusbar_allocate(10, FALSE, FALSE, 0, statusbar_more);
+ }
+ else if (more_tag != -1)
+ {
+ gui_statusbar_remove(more_tag);
+ more_tag = -1;
+ }
+}
+
+static void statusbar_lag(int xpos, int ypos, int size)
+{
+ IRC_SERVER_REC *server;
+ GString *str;
+ int size_needed, lag_unknown;
+ time_t now;
+
+ now = time(NULL);
+ str = g_string_new(NULL);
+
+ server = (IRC_SERVER_REC *) (active_win == NULL ? NULL : active_win->active_server);
+ if (server == NULL || server->lag_last_check == 0)
+ size_needed = 0;
+ else if (server->lag_sent == 0 || now-server->lag_sent < 5) {
+ lag_unknown = now-server->lag_last_check > MAX_LAG_UNKNOWN_TIME;
+
+ if (server->lag < lag_min_show && !lag_unknown)
+ size_needed = 0; /* small lag, don't display */
+ else {
+ g_string_sprintf(str, "%d.%02d", server->lag/1000, (server->lag % 1000)/10);
+ if (lag_unknown)
+ g_string_append(str, " (??)");
+ size_needed = str->len+7;
+ }
+ } else {
+ /* big lag, still waiting .. */
+ g_string_sprintf(str, "%ld (??)", now-server->lag_sent);
+ size_needed = str->len+7;
+ }
+
+ if (size != size_needed)
+ {
+ /* we need more (or less..) space! */
+ gui_statusbar_resize(lag_tag, size_needed);
+ g_string_free(str, TRUE);
+ return;
+ }
+
+ if (size != 0)
+ {
+ lag_last_draw = now;
+ move(ypos, xpos);
+ set_color((1 << 4)+3); addch('[');
+ set_color((1 << 4)+7); addstr("Lag: ");
+
+ set_color((1 << 4)+15); addstr(str->str);
+ set_color((1 << 4)+3); addch(']');
+
+ screen_refresh();
+ }
+ g_string_free(str, TRUE);
+}
+
+static void sig_statusbar_lag_redraw(void)
+{
+ gui_statusbar_redraw(lag_tag);
+}
+
+static int statusbar_lag_timeout(void)
+{
+ /* refresh statusbar every 10 seconds */
+ if (time(NULL)-lag_last_draw < LAG_REFRESH_TIME)
+ return 1;
+
+ gui_statusbar_redraw(lag_tag);
+ return 1;
+}
+
+static void statusbar_topic(int xpos, int ypos, int size)
+{
+ CHANNEL_REC *channel;
+ QUERY_REC *query;
+ char *str, *topic;
+
+ if (size != COLS-2) {
+ /* get all space for topic */
+ gui_statusbar_resize(topic_tag, COLS-2);
+ return;
+ }
+
+ move(ypos, xpos);
+ set_bg((1<<4)+7); clrtoeol(); set_bg(0);
+
+ if (active_win == NULL)
+ return;
+
+ topic = NULL;
+ channel = irc_item_channel(active_win->active);
+ query = irc_item_query(active_win->active);
+ if (channel != NULL && channel->topic != NULL) topic = channel->topic;
+ if (query != NULL && query->address != NULL) topic = query->address;
+ if (topic == NULL) return;
+
+ str = g_strdup_printf("%.*s", size, topic);
+ set_color((1<<4)+15); addstr(str);
+ g_free(str);
+
+ screen_refresh();
+}
+
+static void sig_statusbar_topic_redraw(void)
+{
+ gui_statusbar_redraw(topic_tag);
+}
+
+static void read_settings(void)
+{
+ int ypos;
+
+ if (topic_tag == -1 && settings_get_bool("toggle_show_topicbar")) {
+ ypos = gui_statusbar_create(TRUE);
+ topic_tag = gui_statusbar_allocate(0, FALSE, TRUE, ypos, statusbar_topic);
+ signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ signal_add("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ } else if (topic_tag != -1 && !settings_get_bool("toggle_show_topicbar")) {
+ gui_statusbar_delete(TRUE, 0);
+ topic_tag = -1;
+ signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ signal_remove("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
+ }
+
+ lag_min_show = settings_get_int("lag_min_show")*10;
+}
+
+void gui_statusbar_items_init(void)
+{
+ settings_add_int("misc", "lag_min_show", 100);
+
+ /* clock */
+ clock_tag = gui_statusbar_allocate(7, FALSE, FALSE, 0, statusbar_clock);
+ clock_timetag = g_timeout_add(1000, (GSourceFunc) statusbar_clock_timeout, NULL);
+
+ /* nick */
+ nick_tag = gui_statusbar_allocate(2, FALSE, FALSE, 0, statusbar_nick);
+ signal_add("server connected", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_add("channel wholist", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_add("nick mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_add("user mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_add("server nick changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_add("away mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+
+ /* channel */
+ channel_tag = gui_statusbar_allocate(2, FALSE, FALSE, 0, statusbar_channel);
+ signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
+ signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
+ signal_add("channel mode changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
+ signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
+
+ /* activity */
+ activity_list = NULL;
+ activity_tag = gui_statusbar_allocate(0, FALSE, FALSE, 0, statusbar_activity);
+ signal_add("window activity", (SIGNAL_FUNC) sig_statusbar_activity_hilight);
+ signal_add("window destroyed", (SIGNAL_FUNC) sig_statusbar_activity_window_destroyed);
+
+ /* more */
+ more_tag = -1;
+ signal_add("gui page scrolled", (SIGNAL_FUNC) sig_statusbar_more_check_remove);
+ signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_more_check);
+ signal_add("gui print text", (SIGNAL_FUNC) sig_statusbar_more_check);
+
+ /* lag */
+ lag_tag = gui_statusbar_allocate(0, FALSE, FALSE, 0, statusbar_lag);
+ lag_timetag = g_timeout_add(1000*LAG_REFRESH_TIME, (GSourceFunc) statusbar_lag_timeout, NULL);
+ signal_add("server lag", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
+ signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
+
+ /* topic bar */
+ topic_tag = -1;
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+
+ read_settings();
+}
+
+void gui_statusbar_items_deinit(void)
+{
+ /* clock */
+ gui_statusbar_remove(clock_tag);
+
+ /* nick */
+ gui_statusbar_remove(nick_tag);
+ g_source_remove(clock_timetag);
+ signal_remove("server connected", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_remove("channel wholist", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_remove("nick mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_remove("user mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_remove("server nick changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+ signal_remove("away mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
+
+ /* channel */
+ gui_statusbar_remove(channel_tag);
+ signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
+ signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
+ signal_remove("channel mode changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
+ signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw);
+
+ /* activity */
+ gui_statusbar_remove(activity_tag);
+ signal_remove("window activity", (SIGNAL_FUNC) sig_statusbar_activity_hilight);
+ signal_remove("window destroyed", (SIGNAL_FUNC) sig_statusbar_activity_window_destroyed);
+ g_list_free(activity_list);
+
+ /* more */
+ if (more_tag != -1) gui_statusbar_remove(more_tag);
+ signal_remove("gui page scrolled", (SIGNAL_FUNC) sig_statusbar_more_check_remove);
+ signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_more_check);
+ signal_remove("gui print text", (SIGNAL_FUNC) sig_statusbar_more_check);
+
+ /* lag */
+ gui_statusbar_remove(lag_tag);
+ g_source_remove(lag_timetag);
+ signal_remove("server lag", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
+ signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
+
+ /* topic */
+ if (topic_tag != -1) gui_statusbar_delete(TRUE, 0);
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+}
diff --git a/src/fe-text/gui-statusbar-items.h b/src/fe-text/gui-statusbar-items.h
new file mode 100644
index 00000000..f71415f0
--- /dev/null
+++ b/src/fe-text/gui-statusbar-items.h
@@ -0,0 +1,7 @@
+#ifndef __GUI_STATUSBAR_ITEMS_H
+#define __GUI_STATUSBAR_ITEMS_H
+
+void gui_statusbar_items_init(void);
+void gui_statusbar_items_deinit(void);
+
+#endif
diff --git a/src/fe-text/gui-statusbar.c b/src/fe-text/gui-statusbar.c
new file mode 100644
index 00000000..130993c2
--- /dev/null
+++ b/src/fe-text/gui-statusbar.c
@@ -0,0 +1,237 @@
+/*
+ gui-statusbar.c : irssi
+
+ Copyright (C) 1999 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "signals.h"
+#include "server.h"
+
+#include "windows.h"
+
+#include "screen.h"
+#include "gui-statusbar.h"
+#include "gui-mainwindows.h"
+#include "gui-windows.h"
+
+typedef struct
+{
+ gint tag;
+
+ gint xpos, ypos;
+ gint size;
+ gboolean right_justify, up;
+ STATUSBAR_FUNC func;
+}
+STATUSBAR_REC;
+
+static GList *sbars;
+static gint sbars_tag;
+
+static void gui_statusbar_redraw_line(gboolean up, gint ypos)
+{
+ GList *tmp;
+ gint xpos, rxpos;
+
+ xpos = 1;
+ for (tmp = sbars; tmp != NULL; tmp = tmp->next)
+ {
+ STATUSBAR_REC *rec = tmp->data;
+
+ if (!rec->right_justify)
+ {
+ if (rec->up == up && rec->ypos == ypos && xpos+rec->size < COLS)
+ {
+ rec->xpos = xpos;
+ rec->func(xpos, rec->ypos + (rec->up ? 0 : last_text_line), rec->size);
+ if (rec->size > 0) xpos += rec->size+1;
+ }
+ }
+ }
+
+ rxpos = COLS-1;
+ for (tmp = sbars; tmp != NULL; tmp = tmp->next)
+ {
+ STATUSBAR_REC *rec = tmp->data;
+
+ if (rec->right_justify)
+ {
+ if (rec->up == up && rec->ypos == ypos && rxpos-rec->size > xpos)
+ {
+ rec->xpos = rxpos-rec->size;
+ rec->func(rec->xpos, rec->ypos + (rec->up ? 0 : last_text_line), rec->size);
+ if (rec->size > 0) rxpos -= rec->size+1;
+ }
+ }
+ }
+}
+
+static void gui_statusbar_redraw_all(void)
+{
+ gint n;
+
+ screen_refresh_freeze();
+ set_bg((1<<4)+15);
+ for (n = 0; n < first_text_line; n++)
+ {
+ move(n, 0); clrtoeol();
+ }
+ for (n = last_text_line; n < LINES-1; n++)
+ {
+ move(n, 0); clrtoeol();
+ }
+ set_bg(0);
+
+ for (n = 0; n < LINES-1; n++)
+ {
+ gui_statusbar_redraw_line(FALSE, n);
+ gui_statusbar_redraw_line(TRUE, n);
+ }
+ screen_refresh_thaw();
+}
+
+void gui_statusbar_redraw(gint tag)
+{
+ GList *tmp;
+
+ if (tag == -1)
+ {
+ gui_statusbar_redraw_all();
+ return;
+ }
+
+ for (tmp = sbars; tmp != NULL; tmp = tmp->next)
+ {
+ STATUSBAR_REC *rec = tmp->data;
+
+ if (rec->tag == tag)
+ {
+ rec->func(rec->xpos, rec->ypos + (rec->up ? 0 : last_text_line), rec->size);
+ break;
+ }
+ }
+}
+
+/* create new statusbar, return position */
+gint gui_statusbar_create(gboolean up)
+{
+ gint pos;
+
+ pos = up ? first_text_line++ :
+ (LINES-2)-last_text_line--;
+
+ set_bg((1<<4)+15);
+ move(up ? pos : last_text_line+pos, 0); clrtoeol();
+ set_bg(0);
+
+ gui_windows_resize(-1, FALSE);
+ return pos;
+}
+
+void gui_statusbar_delete(gboolean up, gint ypos)
+{
+ GList *tmp, *next;
+
+ if (up && first_text_line > 0)
+ first_text_line--;
+ else if (!up && last_text_line < LINES-1)
+ last_text_line++;
+
+ for (tmp = sbars; tmp != NULL; tmp = next)
+ {
+ STATUSBAR_REC *rec = tmp->data;
+
+ next = tmp->next;
+ if (rec->up == up && rec->ypos == ypos)
+ gui_statusbar_remove(rec->tag);
+ else if (rec->up == up && rec->ypos > ypos)
+ rec->ypos--;
+ }
+
+ gui_windows_resize(1, FALSE);
+}
+
+/* allocate area in statusbar, returns tag or -1 if failed */
+gint gui_statusbar_allocate(gint size, gboolean right_justify, gboolean up, gint ypos, STATUSBAR_FUNC func)
+{
+ STATUSBAR_REC *rec;
+
+ g_return_val_if_fail(func != NULL, -1);
+
+ rec = g_new0(STATUSBAR_REC, 1);
+ sbars = g_list_append(sbars, rec);
+
+ rec->tag = ++sbars_tag;
+ rec->xpos = -1;
+ rec->up = up;
+ rec->ypos = ypos;
+ rec->size = size;
+ rec->right_justify = right_justify;
+ rec->func = func;
+
+ gui_statusbar_redraw_all();
+ return rec->tag;
+}
+
+void gui_statusbar_resize(gint tag, gint size)
+{
+ GList *tmp;
+
+ for (tmp = sbars; tmp != NULL; tmp = tmp->next)
+ {
+ STATUSBAR_REC *rec = tmp->data;
+
+ if (rec->tag == tag)
+ {
+ rec->size = size;
+ gui_statusbar_redraw_all();
+ break;
+ }
+ }
+}
+
+void gui_statusbar_remove(gint tag)
+{
+ GList *tmp;
+
+ for (tmp = sbars; tmp != NULL; tmp = tmp->next)
+ {
+ STATUSBAR_REC *rec = tmp->data;
+
+ if (rec->tag == tag)
+ {
+ g_free(rec);
+ sbars = g_list_remove(sbars, rec);
+ if (!quitting) gui_statusbar_redraw_all();
+ break;
+ }
+ }
+}
+
+void gui_statusbar_init(void)
+{
+ sbars = NULL;
+ sbars_tag = 0;
+
+ gui_statusbar_create(FALSE);
+}
+
+void gui_statusbar_deinit(void)
+{
+ gui_statusbar_delete(FALSE, 0);
+}
diff --git a/src/fe-text/gui-statusbar.h b/src/fe-text/gui-statusbar.h
new file mode 100644
index 00000000..bdaba584
--- /dev/null
+++ b/src/fe-text/gui-statusbar.h
@@ -0,0 +1,21 @@
+#ifndef __GUI_STATUSBAR_H
+#define __GUI_STATUSBAR_H
+
+typedef void (*STATUSBAR_FUNC) (gint xpos, gint ypos, gint size);
+
+/* create new statusbar, return position */
+gint gui_statusbar_create(gboolean up);
+void gui_statusbar_delete(gboolean up, gint ypos);
+
+/* allocate area in statusbar, returns tag or -1 if failed */
+gint gui_statusbar_allocate(gint size, gboolean right_justify, gboolean up, gint ypos, STATUSBAR_FUNC func);
+void gui_statusbar_resize(gint tag, gint size);
+void gui_statusbar_remove(gint tag);
+
+/* redraw item, -1 = all */
+void gui_statusbar_redraw(gint tag);
+
+void gui_statusbar_init(void);
+void gui_statusbar_deinit(void);
+
+#endif
diff --git a/src/fe-text/gui-textwidget.c b/src/fe-text/gui-textwidget.c
new file mode 100644
index 00000000..c4d6d2f4
--- /dev/null
+++ b/src/fe-text/gui-textwidget.c
@@ -0,0 +1,390 @@
+/*
+ gui-textwidget.c : irssi
+
+ Copyright (C) 1999 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "module-formats.h"
+#include "signals.h"
+#include "commands.h"
+#include "misc.h"
+#include "levels.h"
+#include "settings.h"
+
+#include "windows.h"
+
+#include "screen.h"
+#include "gui-mainwindows.h"
+#include "gui-windows.h"
+
+static gchar *gui_window_line2text(LINE_REC *line)
+{
+ GString *str;
+ gint color;
+ gchar *ret, *ptr, *tmp;
+
+ g_return_val_if_fail(line != NULL, NULL);
+
+ str = g_string_new(NULL);
+
+ color = 0;
+ for (ptr = line->text; ; ptr++)
+ {
+ if (*ptr != 0)
+ {
+ g_string_append_c(str, *ptr);
+ continue;
+ }
+
+ ptr++;
+ if ((*ptr & 0x80) == 0)
+ {
+ /* set color */
+ color = *ptr;
+ g_string_sprintfa(str, "\003%c%c", (color & 0x07)+1, ((color & 0xf0) >> 4)+1);
+ if (color & 0x08) g_string_sprintfa(str, "\002");
+ }
+ else switch ((guchar) *ptr)
+ {
+ case LINE_CMD_EOL:
+ ret = str->str;
+ g_string_free(str, FALSE);
+ return ret;
+ case LINE_CMD_CONTINUE:
+ memcpy(&tmp, ptr+1, sizeof(gchar *));
+ ptr = tmp-1;
+ break;
+ case LINE_CMD_UNDERLINE:
+ g_string_append_c(str, 31);
+ break;
+ case LINE_CMD_COLOR8:
+ g_string_sprintfa(str, "\003%c%c", 9, ((color & 0xf0) >> 4)+1);
+ color &= 0xfff0;
+ color |= 8|ATTR_COLOR8;
+ break;
+ case LINE_CMD_BEEP:
+ break;
+ case LINE_CMD_INDENT:
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+#define LASTLOG_FLAG_NEW 0x01
+#define LASTLOG_FLAG_NOHEADERS 0x02
+#define LASTLOG_FLAG_WORD 0x04
+#define LASTLOG_FLAG_REGEXP 0x08
+
+static int lastlog_parse_args(char *args, int *flags)
+{
+ char **arglist, **tmp;
+ int level;
+
+ /* level can be specified in arguments.. */
+ level = 0; *flags = 0;
+ arglist = g_strsplit(args, " ", -1);
+ for (tmp = arglist; *tmp != NULL; tmp++) {
+ if (strcmp(*tmp, "-") == 0)
+ *flags |= LASTLOG_FLAG_NOHEADERS;
+ else if (g_strcasecmp(*tmp, "-new") == 0)
+ *flags |= LASTLOG_FLAG_NEW;
+ else if (g_strcasecmp(*tmp, "-word") == 0)
+ *flags |= LASTLOG_FLAG_WORD;
+ else if (g_strcasecmp(*tmp, "-regexp") == 0)
+ *flags |= LASTLOG_FLAG_REGEXP;
+ else
+ level |= level2bits(tmp[0]+1);
+ }
+ if (level == 0) level = MSGLEVEL_ALL;
+ g_strfreev(arglist);
+
+ return level;
+}
+
+#define lastlog_match(line, level) \
+ (((line)->level & level) != 0 && ((line)->level & MSGLEVEL_LASTLOG) == 0)
+
+static GList *lastlog_window_startline(int only_new)
+{
+ GList *startline, *tmp;
+
+ startline = WINDOW_GUI(active_win)->lines;
+ if (!only_new) return startline;
+
+ for (tmp = startline; tmp != NULL; tmp = tmp->next) {
+ LINE_REC *rec = tmp->data;
+
+ if (rec->level & MSGLEVEL_LASTLOG)
+ startline = tmp;
+ }
+
+ return startline;
+}
+
+static GList *lastlog_find_startline(GList *list, int count, int start, int level)
+{
+ GList *tmp;
+
+ if (count <= 0) return list;
+
+ for (tmp = g_list_last(list); tmp != NULL; tmp = tmp->prev) {
+ LINE_REC *rec = tmp->data;
+
+ if (!lastlog_match(rec, level))
+ continue;
+
+ if (start > 0) {
+ start--;
+ continue;
+ }
+
+ if (--count == 0)
+ return tmp;
+ }
+
+ return list;
+}
+
+static void cmd_lastlog(const char *data)
+{
+ GList *startline, *list, *tmp;
+ char *params, *str, *args, *text, *countstr, *start;
+ struct tm *tm;
+ int level, flags, count;
+
+ g_return_if_fail(data != NULL);
+
+ params = cmd_get_params(data, 4 | PARAM_FLAG_OPTARGS, &args, &text, &countstr, &start);
+ if (*start == '\0' && is_numeric(text, 0)) {
+ if (is_numeric(countstr, 0))
+ start = countstr;
+ countstr = text;
+ text = "";
+ }
+ count = atol(countstr);
+ if (count == 0) count = -1;
+
+ level = lastlog_parse_args(args, &flags);
+ startline = lastlog_window_startline(flags & LASTLOG_FLAG_NEW);
+
+ if ((flags & LASTLOG_FLAG_NOHEADERS) == 0)
+ printformat(NULL, NULL, MSGLEVEL_LASTLOG, IRCTXT_LASTLOG_START);
+
+ list = gui_window_find_text(active_win, text, startline, flags & LASTLOG_FLAG_REGEXP, flags & LASTLOG_FLAG_WORD);
+ tmp = lastlog_find_startline(list, count, atol(start), level);
+
+ for (; tmp != NULL && (count < 0 || count > 0); tmp = tmp->next, count--) {
+ LINE_REC *rec = tmp->data;
+
+ if (!lastlog_match(rec, level))
+ continue;
+
+ text = gui_window_line2text(rec);
+ if (settings_get_bool("toggle_show_timestamps"))
+ printtext(NULL, NULL, MSGLEVEL_LASTLOG, text);
+ else {
+ tm = localtime(&rec->time);
+
+ str = g_strdup_printf("[%02d:%02d] %s", tm->tm_hour, tm->tm_min, text);
+ printtext(NULL, NULL, MSGLEVEL_LASTLOG, str);
+ g_free(str);
+ }
+ g_free(text);
+ }
+
+ if ((flags & LASTLOG_FLAG_NOHEADERS) == 0)
+ printformat(NULL, NULL, MSGLEVEL_LASTLOG, IRCTXT_LASTLOG_END);
+
+ g_list_free(list);
+ g_free(params);
+}
+
+static void cmd_scrollback(gchar *data, SERVER_REC *server, WI_ITEM_REC *item)
+{
+ command_runsub("scrollback", data, server, item);
+}
+
+static void cmd_scrollback_clear(gchar *data)
+{
+ gui_window_clear(active_win);
+}
+
+static void scrollback_goto_pos(WINDOW_REC *window, GList *pos)
+{
+ GUI_WINDOW_REC *gui;
+
+ g_return_if_fail(window != NULL);
+ g_return_if_fail(pos != NULL);
+
+ gui = WINDOW_GUI(window);
+
+ if (g_list_find(gui->bottom_startline, pos->data) == NULL)
+ {
+ gui->startline = pos;
+ gui->subline = 0;
+ gui->bottom = FALSE;
+ }
+ else
+ {
+ /* reached the last line */
+ if (gui->bottom) return;
+
+ gui->bottom = TRUE;
+ gui->startline = gui->bottom_startline;
+ gui->subline = gui->bottom_subline;
+ gui->ypos = last_text_line-first_text_line-1;
+ }
+
+ if (is_window_visible(window))
+ gui_window_redraw(window);
+ signal_emit("gui page scrolled", 1, window);
+}
+
+static void cmd_scrollback_goto(gchar *data)
+{
+ GList *pos;
+ gchar *params, *arg1, *arg2;
+ gint lines;
+
+ params = cmd_get_params(data, 2, &arg1, &arg2);
+ if (*arg2 == '\0' && (*arg1 == '-' || *arg1 == '+'))
+ {
+ /* go forward/backward n lines */
+ if (sscanf(arg1 + (*arg1 == '-' ? 0 : 1), "%d", &lines) == 1)
+ gui_window_scroll(active_win, lines);
+ }
+ else if (*arg2 == '\0' && strchr(arg1, ':') == NULL && strchr(arg1, '.') == NULL &&
+ sscanf(arg1, "%d", &lines) == 1)
+ {
+ /* go to n'th line. */
+ pos = g_list_nth(WINDOW_GUI(active_win)->lines, lines);
+ if (pos != NULL)
+ scrollback_goto_pos(active_win, pos);
+ }
+ else
+ {
+ struct tm tm;
+ time_t stamp;
+ gint day, month;
+
+ /* [dd.mm | -<days ago>] hh:mi[:ss] */
+ stamp = time(NULL);
+ if (*arg1 == '-')
+ {
+ /* -<days ago> */
+ if (sscanf(arg1+1, "%d", &day) == 1)
+ stamp -= day*3600*24;
+ memcpy(&tm, localtime(&stamp), sizeof(struct tm));
+ }
+ else if (*arg2 != '\0')
+ {
+ /* dd.mm */
+ if (sscanf(arg1, "%d.%d", &day, &month) == 2)
+ {
+ month--;
+ memcpy(&tm, localtime(&stamp), sizeof(struct tm));
+
+ if (tm.tm_mon < month)
+ tm.tm_year--;
+ tm.tm_mon = month;
+ tm.tm_mday = day;
+ stamp = mktime(&tm);
+ }
+ }
+ else
+ {
+ /* move time argument to arg2 */
+ arg2 = arg1;
+ }
+
+ /* hh:mi[:ss] */
+ memcpy(&tm, localtime(&stamp), sizeof(struct tm));
+ tm.tm_sec = 0;
+ sscanf(arg2, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+ stamp = mktime(&tm);
+
+ /* find the first line after timestamp */
+ for (pos = WINDOW_GUI(active_win)->lines; pos != NULL; pos = pos->next)
+ {
+ LINE_REC *rec = pos->data;
+
+ if (rec->time >= stamp)
+ {
+ scrollback_goto_pos(active_win, pos);
+ break;
+ }
+ }
+ }
+ g_free(params);
+}
+
+static void cmd_scrollback_home(gchar *data)
+{
+ GUI_WINDOW_REC *gui;
+
+ gui = WINDOW_GUI(active_win);
+
+ if (gui->bottom_startline == gui->startline)
+ return;
+
+ gui->bottom = FALSE;
+ gui->startline = gui->lines;
+ gui->subline = 0;
+
+ if (is_window_visible(active_win))
+ gui_window_redraw(active_win);
+ signal_emit("gui page scrolled", 1, active_win);
+}
+
+static void cmd_scrollback_end(gchar *data)
+{
+ GUI_WINDOW_REC *gui;
+
+ gui = WINDOW_GUI(active_win);
+
+ gui->bottom = TRUE;
+ gui->startline = gui->bottom_startline;
+ gui->subline = gui->bottom_subline;
+ gui->ypos = last_text_line-first_text_line-1;
+
+ if (is_window_visible(active_win))
+ gui_window_redraw(active_win);
+ signal_emit("gui page scrolled", 1, active_win);
+}
+
+void gui_textwidget_init(void)
+{
+ command_bind("lastlog", NULL, (SIGNAL_FUNC) cmd_lastlog);
+ command_bind("scrollback", NULL, (SIGNAL_FUNC) cmd_scrollback);
+ command_bind("scrollback clear", NULL, (SIGNAL_FUNC) cmd_scrollback_clear);
+ command_bind("scrollback goto", NULL, (SIGNAL_FUNC) cmd_scrollback_goto);
+ command_bind("scrollback home", NULL, (SIGNAL_FUNC) cmd_scrollback_home);
+ command_bind("scrollback end", NULL, (SIGNAL_FUNC) cmd_scrollback_end);
+}
+
+void gui_textwidget_deinit(void)
+{
+ command_unbind("lastlog", (SIGNAL_FUNC) cmd_lastlog);
+ command_unbind("scrollback", (SIGNAL_FUNC) cmd_scrollback);
+ command_unbind("scrollback clear", (SIGNAL_FUNC) cmd_scrollback_clear);
+ command_unbind("scrollback goto", (SIGNAL_FUNC) cmd_scrollback_goto);
+ command_unbind("scrollback home", (SIGNAL_FUNC) cmd_scrollback_home);
+ command_unbind("scrollback end", (SIGNAL_FUNC) cmd_scrollback_end);
+}
diff --git a/src/fe-text/gui-textwidget.h b/src/fe-text/gui-textwidget.h
new file mode 100644
index 00000000..f27ae7fb
--- /dev/null
+++ b/src/fe-text/gui-textwidget.h
@@ -0,0 +1,7 @@
+#ifndef __GUI_TEXTWIDGET_H
+#define __GUI_TEXTWIDGET_H
+
+void gui_textwidget_init(void);
+void gui_textwidget_deinit(void);
+
+#endif
diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c
new file mode 100644
index 00000000..0afcf011
--- /dev/null
+++ b/src/fe-text/gui-windows.c
@@ -0,0 +1,780 @@
+/*
+ gui-windows.c : irssi
+
+ Copyright (C) 1999 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "signals.h"
+#include "commands.h"
+#include "server.h"
+#include "misc.h"
+
+#include "irc.h"
+#include "channels.h"
+#include "windows.h"
+
+#include "screen.h"
+#include "gui-entry.h"
+#include "gui-mainwindows.h"
+#include "gui-windows.h"
+
+#include <regex.h>
+
+#define DEFAULT_INDENT_POS 10
+
+int first_text_line = 0, last_text_line = 0;
+
+static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window, MAIN_WINDOW_REC *parent)
+{
+ GUI_WINDOW_REC *gui;
+
+ gui = g_new0(GUI_WINDOW_REC, 1);
+ gui->parent = parent;
+
+ gui->bottom = TRUE;
+ gui->line_chunk = g_mem_chunk_new("line chunk", sizeof(LINE_REC),
+ sizeof(LINE_REC)*100, G_ALLOC_AND_FREE);
+ gui->empty_linecount = last_text_line-first_text_line-1;
+
+ return gui;
+}
+
+static void gui_window_deinit(GUI_WINDOW_REC *gui)
+{
+ g_slist_foreach(gui->text_chunks, (GFunc) g_free, NULL);
+ g_slist_free(gui->text_chunks);
+
+ g_mem_chunk_destroy(gui->line_chunk);
+ g_list_free(gui->lines);
+
+ g_free(gui);
+}
+
+static void gui_window_created(WINDOW_REC *window)
+{
+ MAIN_WINDOW_REC *parent;
+
+ g_return_if_fail(window != NULL);
+
+ parent = (active_win == NULL || WINDOW_GUI(active_win) == NULL) ?
+ gui_mainwindow_create() : WINDOW_GUI(active_win)->parent;
+ if (parent->children == NULL) parent->active = window;
+ parent->children = g_list_append(parent->children, window);
+
+ window->gui_data = gui_window_init(window, parent);
+ signal_emit("gui window created", 1, window);
+}
+
+static void gui_window_destroyed(WINDOW_REC *window)
+{
+ MAIN_WINDOW_REC *parent;
+ GUI_WINDOW_REC *gui;
+
+ g_return_if_fail(window != NULL);
+
+ gui = WINDOW_GUI(window);
+ parent = gui->parent;
+ parent->children = g_list_remove(parent->children, window);
+
+ signal_emit("gui window destroyed", 1, window);
+
+ gui_window_deinit(gui);
+ window->gui_data = NULL;
+
+ if (parent->children == NULL)
+ gui_mainwindow_destroy(parent);
+
+ if (windows != NULL && active_win == window && !quitting)
+ window_set_active(windows->data);
+}
+
+void gui_window_clear(WINDOW_REC *window)
+{
+ MAIN_WINDOW_REC *parent;
+
+ g_return_if_fail(window != NULL);
+
+ parent = WINDOW_GUI(window)->parent;
+ gui_window_deinit(WINDOW_GUI(window));
+ window->gui_data = gui_window_init(window, parent);
+
+ window->lines = 0;
+
+ if (is_window_visible(window))
+ gui_window_redraw(window);
+}
+
+gint gui_window_update_bottom(GUI_WINDOW_REC *gui, gint lines)
+{
+ gint linecount, last_linecount;
+
+ if (gui->bottom_startline == NULL)
+ return -1;
+
+ while (lines < 0)
+ {
+ if (gui->bottom_subline > 0)
+ gui->bottom_subline--;
+ else
+ {
+ if (gui->bottom_startline->prev == NULL)
+ return -1;
+ gui->bottom_startline = gui->bottom_startline->prev;
+
+ linecount = gui_window_get_linecount(gui, gui->bottom_startline->data);
+ gui->bottom_subline = linecount-1;
+ }
+ lines++;
+ }
+
+ last_linecount = linecount = -1;
+ while (lines > 0)
+ {
+ if (linecount == -1)
+ last_linecount = linecount = gui_window_get_linecount(gui, gui->bottom_startline->data);
+
+ if (linecount > gui->bottom_subline+1)
+ gui->bottom_subline++;
+ else
+ {
+ gui->bottom_subline = 0;
+ linecount = -1;
+
+ if (gui->bottom_startline->next == NULL)
+ break;
+ gui->bottom_startline = gui->bottom_startline->next;
+ }
+ lines--;
+ }
+
+ return last_linecount;
+}
+
+void gui_window_newline(GUI_WINDOW_REC *gui, gboolean visible)
+{
+ gboolean last_line;
+ gint linecount;
+
+ g_return_if_fail(gui != NULL);
+
+ gui->xpos = 0;
+ last_line = gui->ypos >= last_text_line-first_text_line-1;
+
+ if (gui->empty_linecount > 0)
+ {
+ /* window buffer height isn't even the size of the screen yet */
+ gui->empty_linecount--;
+ linecount = gui_window_get_linecount(gui, gui->startline->data);
+ }
+ else
+ {
+ linecount = gui_window_update_bottom(gui, 1);
+ }
+
+ if (!last_line || !gui->bottom)
+ {
+ gui->ypos++;
+ }
+ else if (gui->bottom)
+ {
+ if (gui->subline >= linecount)
+ {
+ /* after screen gets full after /CLEAR we end up here.. */
+ gui->startline = gui->startline->next;
+ gui->subline = 0;
+
+ linecount = gui_window_update_bottom(gui, 1);
+ }
+
+ if (linecount > 1+gui->subline)
+ gui->subline++;
+ else
+ {
+ gui->startline = gui->startline->next;
+ gui->subline = 0;
+ }
+
+ if (visible)
+ {
+ scroll_up(first_text_line, last_text_line-1);
+ move(last_text_line-1, 0); clrtoeol();
+ }
+ }
+}
+
+/* get number of real lines that line record takes - this really should share
+ at least some code with gui_window_line_draw().. */
+gint gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line)
+{
+ gchar *ptr, *last_space_ptr, *tmp;
+ gint lines, xpos, indent_pos, last_space;
+
+ g_return_val_if_fail(gui != NULL, -1);
+ g_return_val_if_fail(line != NULL, -1);
+
+ if (line->text == NULL)
+ return 0;
+
+ xpos = 0; lines = 1; indent_pos = DEFAULT_INDENT_POS;
+ last_space = 0; last_space_ptr = NULL;
+ for (ptr = line->text;; ptr++)
+ {
+ if (*ptr == '\0')
+ {
+ /* command */
+ ptr++;
+ switch ((guchar) *ptr)
+ {
+ case LINE_CMD_EOL:
+ return lines;
+ case LINE_CMD_CONTINUE:
+ memcpy(&tmp, ptr+1, sizeof(gchar *));
+ ptr = tmp-1;
+ break;
+ case LINE_CMD_INDENT:
+ indent_pos = xpos;
+ break;
+ }
+ continue;
+ }
+
+ if (xpos == COLS)
+ {
+ xpos = indent_pos >= COLS-5 ? DEFAULT_INDENT_POS : indent_pos;
+
+ if (last_space > indent_pos && last_space > 10)
+ {
+ ptr = last_space_ptr;
+ while (*ptr == ' ') ptr++;
+ }
+
+ last_space = 0;
+ lines++;
+ ptr--;
+ continue;
+ }
+
+ xpos++;
+ if (*ptr == ' ')
+ {
+ last_space = xpos-1;
+ last_space_ptr = ptr+1;
+ }
+ }
+}
+
+/* draw line - ugly code.. */
+gint gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, gint ypos, gint skip, gint max)
+{
+ gchar *ptr, *last_space_ptr, *tmp;
+ gint lines, xpos, color, indent_pos, last_space, last_space_color;
+
+ g_return_val_if_fail(gui != NULL, -1);
+ g_return_val_if_fail(line != NULL, -1);
+
+ if (line->text == NULL)
+ return 0;
+
+ move(ypos, 0);
+ xpos = 0; color = 0; lines = -1; indent_pos = DEFAULT_INDENT_POS;
+ last_space = last_space_color = 0; last_space_ptr = NULL;
+ for (ptr = line->text;; ptr++)
+ {
+ if (*ptr == '\0')
+ {
+ /* command */
+ ptr++;
+ if ((*ptr & 0x80) == 0)
+ {
+ /* set color */
+ color = (color & ATTR_UNDERLINE) | *ptr;
+ }
+ else switch ((guchar) *ptr)
+ {
+ case LINE_CMD_EOL:
+ return lines;
+ case LINE_CMD_CONTINUE:
+ memcpy(&tmp, ptr+1, sizeof(gchar *));
+ ptr = tmp-1;
+ break;
+ case LINE_CMD_UNDERLINE:
+ color ^= ATTR_UNDERLINE;
+ break;
+ case LINE_CMD_COLOR8:
+ color &= 0xfff0;
+ color |= 8|ATTR_COLOR8;
+ break;
+ case LINE_CMD_BEEP:
+ beep();
+ break;
+ case LINE_CMD_INDENT:
+ indent_pos = xpos;
+ break;
+ }
+ set_color(color);
+ continue;
+ }
+
+ if (xpos == COLS)
+ {
+ xpos = indent_pos >= COLS-5 ? DEFAULT_INDENT_POS : indent_pos;
+
+ if (last_space > indent_pos && last_space > 10)
+ {
+ /* remove the last word */
+ if (!skip)
+ {
+ move(ypos, last_space);
+ set_color(0);
+ clrtoeol();
+ }
+
+ /* skip backwards to draw the line again. */
+ ptr = last_space_ptr;
+ color = last_space_color;
+ if (!skip) set_color(color);
+ while (*ptr == ' ') ptr++;
+ }
+ last_space = 0;
+
+ if (skip > 0)
+ {
+ if (--skip == 0) set_color(color);
+ }
+ else
+ {
+ if (lines == max)
+ return lines;
+ if (max != -1)
+ ypos++;
+ else
+ {
+ gui_window_newline(gui, TRUE);
+ ypos = first_text_line+gui->ypos;
+ }
+ lines++;
+ }
+ move(ypos, indent_pos);
+
+ /* we could have \0.. */
+ ptr--;
+ continue;
+ }
+
+ xpos++;
+ if (*ptr == ' ')
+ {
+ last_space = xpos-1;
+ last_space_color = color;
+ last_space_ptr = ptr+1;
+ }
+
+ if (skip) continue;
+ if (lines == -1) lines = 0;
+
+ if ((guchar) *ptr >= 32)
+ addch((guchar) *ptr);
+ else
+ {
+ /* low-ascii */
+ set_color(ATTR_REVERSE);
+ addch(*ptr+'A'-1);
+ set_color(color);
+ }
+ }
+}
+
+void gui_window_redraw(WINDOW_REC *window)
+{
+ GUI_WINDOW_REC *gui;
+ GList *line;
+ gint ypos, lines, skip, max;
+
+ g_return_if_fail(window != NULL);
+
+ gui = WINDOW_GUI(window);
+
+ for (ypos = first_text_line; ypos < last_text_line; ypos++)
+ {
+ set_color(0);
+ move(ypos, 0);
+ clrtoeol();
+ }
+
+ skip = gui->subline;
+ ypos = first_text_line;
+ for (line = gui->startline; line != NULL; line = line->next)
+ {
+ LINE_REC *rec = line->data;
+
+ max = last_text_line - ypos-1;
+ if (max < 0) break;
+
+ lines = gui_window_line_draw(gui, rec, ypos, skip, max);
+ skip = 0;
+
+ ypos += lines+1;
+ }
+ screen_refresh();
+}
+
+static void gui_window_scroll_up(GUI_WINDOW_REC *gui, gint lines)
+{
+ LINE_REC *line;
+ gint count, linecount;
+
+ if (gui->startline == NULL)
+ return;
+
+ count = lines-gui->subline; gui->ypos += gui->subline;
+ gui->subline = 0;
+
+ while (gui->startline->prev != NULL && count > 0)
+ {
+ gui->startline = gui->startline->prev;
+
+ line = gui->startline->data;
+ linecount = gui_window_get_linecount(gui, line);
+ count -= linecount;
+ gui->ypos += linecount;
+ }
+
+ if (count < 0)
+ {
+ gui->subline = -count;
+ gui->ypos -= -count;
+ }
+
+ gui->bottom = (gui->ypos >= -1 && gui->ypos <= last_text_line-first_text_line-1);
+}
+
+static void gui_window_scroll_down(GUI_WINDOW_REC *gui, gint lines)
+{
+ LINE_REC *line;
+ gint count, linecount;
+
+ if (gui->startline == gui->bottom_startline && gui->subline == gui->bottom_subline)
+ return;
+
+ count = lines+gui->subline; gui->ypos += gui->subline;
+ gui->subline = 0;
+
+ while (count > 0)
+ {
+ line = gui->startline->data;
+
+ linecount = gui_window_get_linecount(gui, line);
+ count -= linecount;
+ gui->ypos -= linecount;
+
+ if (gui->startline == gui->bottom_startline &&
+ linecount+count > gui->bottom_subline)
+ {
+ /* reached the last screenful of text */
+ gui->subline = gui->bottom_subline;
+ gui->ypos += linecount;
+ gui->ypos -= gui->subline;
+ break;
+ }
+
+ if (count <= 0)
+ {
+ gui->subline = linecount+count;
+ gui->ypos += -count;
+ break;
+ }
+
+ if (gui->startline->next == NULL)
+ {
+ gui->subline = linecount;
+ break;
+ }
+ gui->startline = gui->startline->next;
+ }
+
+ gui->bottom = (gui->ypos >= -1 && gui->ypos <= last_text_line-first_text_line-1);
+}
+
+void gui_window_scroll(WINDOW_REC *window, gint lines)
+{
+ GUI_WINDOW_REC *gui;
+
+ g_return_if_fail(window != NULL);
+
+ gui = WINDOW_GUI(window);
+
+ if (lines < 0)
+ gui_window_scroll_up(gui, -lines);
+ else
+ gui_window_scroll_down(gui, lines);
+
+ if (is_window_visible(window))
+ gui_window_redraw(window);
+ signal_emit("gui page scrolled", 1, window);
+}
+
+static void window_update_prompt(WINDOW_REC *window)
+{
+ WI_ITEM_REC *item;
+ char *text, *str;
+
+ item = window->active;
+ if (item != NULL)
+ text = item->name;
+ else if (window->name != NULL)
+ text = window->name;
+ else {
+ gui_entry_set_prompt("");
+ return;
+ }
+
+ /* set prompt */
+ str = g_strdup_printf("[%1.17s] ", text);
+ gui_entry_set_prompt(str);
+ if (*str != '\0') g_free(str);
+}
+
+static void signal_window_changed(WINDOW_REC *window)
+{
+ g_return_if_fail(window != NULL);
+
+ WINDOW_GUI(window)->parent->active = window;
+
+ screen_refresh_freeze();
+ window_update_prompt(window);
+ gui_window_redraw(window);
+ screen_refresh_thaw();
+}
+
+static void signal_window_item_update(WINDOW_REC *window)
+{
+ CHANNEL_REC *channel;
+
+ channel = irc_item_channel(window->active);
+ if (channel != NULL) {
+ /* redraw channel widgets */
+ signal_emit("channel topic changed", 1, channel);
+ signal_emit("channel mode changed", 1, channel);
+ }
+
+ window_update_prompt(window);
+}
+
+GList *gui_window_find_text(WINDOW_REC *window, gchar *text, GList *startline, int regexp, int fullword)
+{
+ regex_t preg;
+ GList *tmp;
+ GList *matches;
+ gchar *str, *ptr;
+ gint n, size;
+
+ g_return_val_if_fail(window != NULL, NULL);
+ g_return_val_if_fail(text != NULL, NULL);
+
+ text = g_strdup(text); g_strup(text);
+ matches = NULL; size = 1024; str = g_malloc(1024);
+
+ if (regcomp(&preg, text, REG_EXTENDED|REG_NOSUB) != 0) {
+ g_free(text);
+ return 0;
+ }
+
+ if (startline == NULL) startline = WINDOW_GUI(window)->lines;
+ for (tmp = startline; tmp != NULL; tmp = tmp->next)
+ {
+ LINE_REC *rec = tmp->data;
+
+ for (n = 0, ptr = rec->text; ; ptr++)
+ {
+ if (*ptr != 0)
+ {
+ if (n+2 > size)
+ {
+ size += 1024;
+ str = g_realloc(str, size);
+ }
+ str[n++] = toupper(*ptr);
+ }
+ else
+ {
+ ptr++;
+
+ if ((guchar) *ptr == LINE_CMD_CONTINUE)
+ {
+ gchar *tmp;
+
+ memcpy(&tmp, ptr+1, sizeof(gchar *));
+ ptr = tmp-1;
+ }
+ else if ((guchar) *ptr == LINE_CMD_EOL)
+ break;
+ }
+ }
+ str[n] = '\0';
+
+ if (regexp ? /*regexec(&preg, str, 0, NULL, 0) == 0*/regexp_match(str, text) :
+ fullword ? stristr_full(str, text) != NULL :
+ strstr(str, text) != NULL) {
+ /* matched */
+ matches = g_list_append(matches, rec);
+ }
+ }
+ regfree(&preg);
+
+ if (str != NULL) g_free(str);
+ g_free(text);
+ return matches;
+}
+
+static void gui_window_horiz_resize(WINDOW_REC *window)
+{
+ GUI_WINDOW_REC *gui;
+ gint linecount;
+
+ gui = WINDOW_GUI(window);
+ if (gui->lines == NULL) return;
+
+ linecount = gui_window_get_linecount(gui, g_list_last(gui->lines)->data);
+ gui->last_subline = linecount-1;
+
+ /* fake a /CLEAR and scroll window up one page */
+ gui->ypos = -1;
+ gui->bottom = TRUE;
+ gui->empty_linecount = last_text_line-first_text_line-1;
+
+ gui->bottom_startline = gui->startline = g_list_last(gui->lines);
+ gui->bottom_subline = gui->subline = gui->last_subline+1;
+ gui_window_scroll(window, -gui->empty_linecount-1);
+
+ gui->bottom_startline = gui->startline;
+ gui->bottom_subline = gui->subline;
+
+ /* remove the empty lines from the end */
+ if (gui->bottom && gui->startline == gui->lines)
+ gui->empty_linecount = (last_text_line-first_text_line-1);
+ else
+ gui->empty_linecount = 0;
+}
+
+void gui_windows_resize(gint ychange, gboolean xchange)
+{
+ GUI_WINDOW_REC *gui;
+ WINDOW_REC *window;
+ GSList *tmp;
+
+ screen_refresh_freeze();
+ for (tmp = windows; tmp != NULL; tmp = tmp->next)
+ {
+ window = tmp->data;
+
+ gui = WINDOW_GUI(window);
+
+ if (xchange)
+ {
+ /* window width changed, we'll need to recalculate a few things.. */
+ gui_window_horiz_resize(window);
+ continue;
+ }
+
+ if (ychange < 0 && gui->empty_linecount > 0)
+ {
+ /* empty space at the bottom of the screen - just eat it. */
+ gui->empty_linecount += ychange;
+ if (gui->empty_linecount < 0)
+ gui->empty_linecount = 0;
+ }
+ else if (gui->bottom && gui->startline == gui->lines && ychange > 0)
+ {
+ /* less than screenful of text, add empty space */
+ gui->empty_linecount += ychange;
+ }
+ else
+ {
+ gui_window_update_bottom(WINDOW_GUI(window), -ychange);
+ gui_window_scroll(window, -ychange);
+ }
+ }
+
+ irssi_redraw();
+ screen_refresh_thaw();
+}
+
+static void cmd_window_move(gchar *data)
+{
+ GSList *w1, *w2;
+ WINDOW_REC *window;
+
+ g_return_if_fail(data != NULL);
+
+ window = active_win;
+ w1 = g_slist_find(windows, window);
+ if (g_strcasecmp(data, "LEFT") == 0 || g_strncasecmp(data, "PREV", 4) == 0)
+ {
+ w2 = g_slist_nth(windows, g_slist_index(windows, window)-1);
+ if (w2 == NULL)
+ {
+ window = w1->data;
+ windows = g_slist_remove(windows, window);
+ windows = g_slist_append(windows, window);
+ w2 = g_slist_last(windows);
+ }
+ }
+ else if (g_strcasecmp(data, "RIGHT") == 0 || g_strcasecmp(data, "NEXT") == 0)
+ {
+ w2 = w1->next;
+ if (w2 == NULL)
+ {
+ window = w1->data;
+ windows = g_slist_remove(windows, window);
+ windows = g_slist_prepend(windows, window);
+ }
+ }
+ else
+ return;
+
+ if (w2 != NULL)
+ {
+ window = w1->data;
+ w1->data = w2->data;
+ w2->data = window;
+ }
+
+ window_set_active(window);
+}
+
+void gui_windows_init(void)
+{
+ signal_add("window created", (SIGNAL_FUNC) gui_window_created);
+ signal_add("window destroyed", (SIGNAL_FUNC) gui_window_destroyed);
+ signal_add("window changed", (SIGNAL_FUNC) signal_window_changed);
+ signal_add("window item changed", (SIGNAL_FUNC) signal_window_item_update);
+ signal_add("window name changed", (SIGNAL_FUNC) signal_window_item_update);
+ signal_add("window item remove", (SIGNAL_FUNC) signal_window_item_update);
+ command_bind("window move", NULL, (SIGNAL_FUNC) cmd_window_move);
+}
+
+void gui_windows_deinit(void)
+{
+ signal_remove("window created", (SIGNAL_FUNC) gui_window_created);
+ signal_remove("window destroyed", (SIGNAL_FUNC) gui_window_destroyed);
+ signal_remove("window changed", (SIGNAL_FUNC) signal_window_changed);
+ signal_remove("window item changed", (SIGNAL_FUNC) signal_window_item_update);
+ signal_remove("window name changed", (SIGNAL_FUNC) signal_window_item_update);
+ signal_remove("window item remove", (SIGNAL_FUNC) signal_window_item_update);
+ command_unbind("window move", (SIGNAL_FUNC) cmd_window_move);
+}
diff --git a/src/fe-text/gui-windows.h b/src/fe-text/gui-windows.h
new file mode 100644
index 00000000..14a3a982
--- /dev/null
+++ b/src/fe-text/gui-windows.h
@@ -0,0 +1,93 @@
+#ifndef __GUI_WINDOWS_H
+#define __GUI_WINDOWS_H
+
+#include "server.h"
+#include "gui-mainwindows.h"
+
+#define WINDOW_GUI(a) ((GUI_WINDOW_REC *) ((a)->gui_data))
+
+#define is_window_visible(win) \
+ (WINDOW_GUI(win)->parent->active == (win))
+
+#define LINE_TEXT_CHUNK_SIZE 2048
+
+/* 7 first bits of LINE_REC's info byte. */
+enum
+{
+ LINE_CMD_EOL=0x80, /* line ends here. */
+ LINE_CMD_CONTINUE, /* line continues in next block */
+ LINE_CMD_COLOR8, /* change to dark grey, normally 8 = bold black */
+ LINE_CMD_UNDERLINE, /* enable/disable underlining */
+ LINE_CMD_BEEP, /* beep */
+ LINE_CMD_INDENT /* if line is split, indent it at this position */
+};
+
+typedef struct
+{
+ gchar *text; /* text in the line. \0 means that the next char will be a
+ color or command. <= 127 = color or if 8.bit is set, the
+ first 7 bits are the command. See LINE_CMD_xxxx. */
+
+ gint32 level;
+ time_t time;
+}
+LINE_REC;
+
+typedef struct
+{
+ gchar buffer[LINE_TEXT_CHUNK_SIZE];
+ gint pos;
+ gint lines;
+}
+TEXT_CHUNK_REC;
+
+typedef struct
+{
+ MAIN_WINDOW_REC *parent;
+
+ GMemChunk *line_chunk;
+ GSList *text_chunks;
+ GList *lines;
+
+ LINE_REC *cur_line;
+ TEXT_CHUNK_REC *cur_text;
+
+ gint xpos, ypos; /* cursor position in screen */
+ GList *startline; /* line at the top of the screen */
+ gint subline; /* number of "real lines" to skip from `startline' */
+
+ GList *bottom_startline; /* marks the bottom of the text buffer */
+ gint bottom_subline;
+ gint empty_linecount; /* how many empty lines are in screen.
+ a screenful when started or used /CLEAR */
+ gboolean bottom; /* window is at the bottom of the text buffer */
+
+ /* for gui-printtext.c */
+ gint last_subline;
+ gint last_color, last_flags;
+}
+GUI_WINDOW_REC;
+
+extern gint first_text_line, last_text_line;
+
+void gui_windows_init(void);
+void gui_windows_deinit(void);
+
+WINDOW_REC *gui_window_create(MAIN_WINDOW_REC *parent);
+
+void gui_window_set_server(WINDOW_REC *window, SERVER_REC *server);
+GList *gui_window_find_text(WINDOW_REC *window, gchar *text, GList *startline, int regexp, int fullword);
+
+/* get number of real lines that line record takes */
+gint gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line);
+gint gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, gint ypos, gint skip, gint max);
+
+void gui_window_clear(WINDOW_REC *window);
+void gui_window_redraw(WINDOW_REC *window);
+void gui_windows_resize(gint ychange, gboolean xchange);
+
+void gui_window_newline(GUI_WINDOW_REC *gui, gboolean visible);
+gint gui_window_update_bottom(GUI_WINDOW_REC *gui, gint lines);
+void gui_window_scroll(WINDOW_REC *window, gint lines);
+
+#endif
diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c
new file mode 100644
index 00000000..723d5d9e
--- /dev/null
+++ b/src/fe-text/irssi.c
@@ -0,0 +1,156 @@
+/*
+ irssi.c : irssi
+
+ Copyright (C) 1999-2000 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "args.h"
+#include "signals.h"
+#include "core.h"
+
+#include "irc-core.h"
+#include "fe-common-core.h"
+#include "fe-common-irc.h"
+
+#include "screen.h"
+#include "gui-entry.h"
+#include "gui-mainwindows.h"
+#include "gui-printtext.h"
+#include "gui-readline.h"
+#include "gui-special-vars.h"
+#include "gui-statusbar.h"
+#include "gui-statusbar-items.h"
+#include "gui-textwidget.h"
+#include "gui-windows.h"
+
+#include <signal.h>
+
+void irc_init(void);
+void irc_deinit(void);
+
+static GMainLoop *main_loop;
+int quitting;
+
+static void sig_exit(void)
+{
+ g_main_quit(main_loop);
+}
+
+/* redraw irssi's screen.. */
+void irssi_redraw(void)
+{
+ clear();
+
+ /* current window */
+ gui_window_redraw(active_win);
+ /* statusbar */
+ gui_statusbar_redraw(-1);
+ /* entry line */
+ gui_entry_redraw();
+}
+
+static void textui_init(void)
+{
+ static struct poptOption options[] = {
+ POPT_AUTOHELP
+ { NULL, '\0', 0, NULL }
+ };
+
+ args_register(options);
+
+ irssi_gui = IRSSI_GUI_TEXT;
+ core_init();
+ irc_init();
+ fe_common_core_init();
+ fe_common_irc_init();
+ signal_add("gui exit", (SIGNAL_FUNC) sig_exit);
+}
+
+static void textui_finish_init(void)
+{
+ quitting = FALSE;
+
+ screen_refresh_freeze();
+ gui_entry_init();
+ gui_mainwindows_init();
+ gui_printtext_init();
+ gui_readline_init();
+ gui_special_vars_init();
+ gui_textwidget_init();
+ gui_windows_init();
+
+ fe_common_core_finish_init();
+ fe_common_irc_finish_init();
+
+ gui_statusbar_init();
+ gui_statusbar_items_init();
+
+ signal_emit("irssi init finished", 0);
+ screen_refresh_thaw();
+}
+
+static void textui_deinit(void)
+{
+ quitting = TRUE;
+ signal(SIGINT, SIG_DFL);
+
+ signal_remove("gui exit", (SIGNAL_FUNC) sig_exit);
+ gui_textwidget_deinit();
+ gui_special_vars_deinit();
+ gui_statusbar_items_deinit();
+ gui_statusbar_deinit();
+ gui_printtext_deinit();
+ gui_readline_deinit();
+ gui_mainwindows_deinit();
+ gui_windows_deinit();
+ gui_entry_deinit();
+ deinit_screen();
+
+ fe_common_irc_deinit();
+ fe_common_core_deinit();
+ irc_deinit();
+ core_deinit();
+}
+
+int main(int argc, char **argv)
+{
+#ifdef HAVE_SOCKS
+ SOCKSinit(argv[0]);
+#endif
+
+ textui_init();
+ args_execute(argc, argv);
+
+ if (!init_screen())
+ {
+ printf("Can't initialize screen handling, quitting.\n");
+ return 1;
+ }
+
+ textui_finish_init();
+ main_loop = g_main_new(TRUE);
+ g_main_run(main_loop);
+ g_main_destroy(main_loop);
+ textui_deinit();
+
+#ifdef MEM_DEBUG
+ ig_mem_profile();
+#endif
+
+ return 0;
+}
diff --git a/src/fe-text/module-formats.c b/src/fe-text/module-formats.c
new file mode 100644
index 00000000..fc7f0a63
--- /dev/null
+++ b/src/fe-text/module-formats.c
@@ -0,0 +1,30 @@
+/*
+ module-formats.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "printtext.h"
+
+FORMAT_REC gui_text_formats[] =
+{
+ { MODULE_NAME, N_("Text user interface"), 0 },
+
+ { "lastlog_start", N_("%_Lastlog:"), 0 },
+ { "lastlog_end", N_("%_End of Lastlog"), 0 },
+};
diff --git a/src/fe-text/module-formats.h b/src/fe-text/module-formats.h
new file mode 100644
index 00000000..d8f7a3b8
--- /dev/null
+++ b/src/fe-text/module-formats.h
@@ -0,0 +1,11 @@
+#include "printtext.h"
+
+enum {
+ IRCTXT_MODULE_NAME,
+
+ IRCTXT_LASTLOG_START,
+ IRCTXT_LASTLOG_END
+};
+
+extern FORMAT_REC gui_text_formats[];
+#define MODULE_FORMATS gui_text_formats
diff --git a/src/fe-text/module.h b/src/fe-text/module.h
new file mode 100644
index 00000000..55e08e40
--- /dev/null
+++ b/src/fe-text/module.h
@@ -0,0 +1,6 @@
+#include "common.h"
+
+#define MODULE_NAME "gui-text"
+
+extern int quitting;
+void irssi_redraw(void);
diff --git a/src/fe-text/screen.c b/src/fe-text/screen.c
new file mode 100644
index 00000000..19c79f5a
--- /dev/null
+++ b/src/fe-text/screen.c
@@ -0,0 +1,254 @@
+/*
+ screen.c : All virtual screen management, real screen management is in
+ con_???.c files.
+
+ Copyright (C) 1999 Timo Sirainen
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "signals.h"
+#include "settings.h"
+
+#include "screen.h"
+#include "gui-readline.h"
+#include "gui-windows.h"
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <signal.h>
+
+#ifndef COLOR_PAIRS
+#define COLOR_PAIRS 64
+#endif
+
+#define MIN_SCREEN_WIDTH 20
+
+static gint scrx, scry;
+gboolean use_colors;
+static gint freeze_refresh;
+
+#ifdef SIGWINCH
+
+static void sig_winch(int p)
+{
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+ gint ychange, xchange;
+
+ /* Get new window size */
+ if (ioctl(0, TIOCGWINSZ, &ws) < 0)
+ return;
+
+ if (ws.ws_row == LINES && ws.ws_col == COLS)
+ {
+ /* Same size, abort. */
+ return;
+ }
+
+ if (ws.ws_col < MIN_SCREEN_WIDTH)
+ ws.ws_col = MIN_SCREEN_WIDTH;
+
+ /* Resize curses terminal */
+ ychange = ws.ws_row-LINES;
+ xchange = ws.ws_col-COLS;
+#ifdef HAVE_CURSES_RESIZETERM
+ resizeterm(ws.ws_row, ws.ws_col);
+#else
+ deinit_screen();
+ init_screen();
+#endif
+
+ last_text_line += ychange;
+ gui_windows_resize(ychange, xchange != 0);
+#endif
+}
+#endif
+
+/* SIGINT != ^C .. any better way to make this work? */
+void sigint_handler(int p)
+{
+ ungetch(3);
+ readline();
+}
+
+static void read_settings(void)
+{
+ use_colors = settings_get_bool("colors");
+ irssi_redraw();
+}
+
+/* Initialize screen, detect screen length */
+gint init_screen(void)
+{
+ gchar ansi_tab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+ gint num;
+
+ if (!initscr()) return 0;
+
+ if (COLS < MIN_SCREEN_WIDTH)
+ COLS = MIN_SCREEN_WIDTH;
+
+ signal(SIGINT, sigint_handler);
+ cbreak(); noecho(); idlok(stdscr, 1);
+#ifdef HAVE_CURSES_IDCOK
+ idcok(stdscr, 1);
+#endif
+ intrflush(stdscr, FALSE); halfdelay(1); keypad(stdscr, 1);
+
+ settings_add_bool("lookandfeel", "colors", TRUE);
+
+ use_colors = settings_get_bool("colors") && has_colors();
+ if (has_colors()) start_color();
+
+#ifdef HAVE_NCURSES_USE_DEFAULT_COLORS
+ /* this lets us to use the "default" background color for colors <= 7 so
+ background pixmaps etc. show up right */
+ use_default_colors();
+
+ for (num = 1; num < COLOR_PAIRS; num++)
+ init_pair(num, ansi_tab[num & 7], num <= 7 ? -1 : ansi_tab[num >> 3]);
+
+ init_pair(63, 0, -1); /* hm.. not THAT good idea, but probably more people
+ want dark grey than white on white.. */
+#else
+ for (num = 1; num < COLOR_PAIRS; num++)
+ init_pair(num, ansi_tab[num & 7], ansi_tab[num >> 3]);
+ init_pair(63, 0, 0);
+#endif
+
+ scrx = scry = 0;
+ if (last_text_line == 0)
+ {
+ first_text_line = 0;
+ last_text_line = LINES-1;
+ }
+#ifdef SIGWINCH
+ signal(SIGWINCH, sig_winch);
+#endif
+
+ freeze_refresh = 0;
+ clear();
+
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+ return 1;
+}
+
+/* Deinitialize screen */
+void deinit_screen(void)
+{
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+ endwin();
+}
+
+void set_color(gint col)
+{
+ gint attr;
+
+ if (!use_colors)
+ {
+ if ((col & 0x70) != 0)
+ attr = A_REVERSE;
+ else
+ attr = 0;
+ }
+ else
+ {
+ if (col & ATTR_COLOR8)
+ attr = A_DIM | COLOR_PAIR(63);
+ else
+ attr = COLOR_PAIR((col&7) + (col&0x70)/2);
+ }
+
+ if (col & 0x08) attr |= A_BOLD;
+ if (col & 0x80) attr |= A_BLINK;
+
+ if (col & ATTR_UNDERLINE) attr |= A_UNDERLINE;
+ if (col & ATTR_REVERSE) attr |= A_REVERSE;
+
+ attrset(attr);
+}
+
+void set_bg(gint col)
+{
+ gint attr;
+
+ if (!use_colors)
+ {
+ if ((col & 0x70) != 0)
+ attr = A_REVERSE;
+ else
+ attr = 0;
+ }
+ else
+ {
+ if (col == 8)
+ attr = A_DIM | COLOR_PAIR(63);
+ else
+ attr = COLOR_PAIR((col&7) + (col&0x70)/2);
+ }
+
+ if (col & 0x08) attr |= A_BOLD;
+ if (col & 0x80) attr |= A_BLINK;
+
+ bkgdset(' ' | attr);
+}
+
+/* Scroll area up */
+void scroll_up(gint y1, gint y2)
+{
+ scrollok(stdscr, TRUE);
+ setscrreg(y1, y2); scrl(1);
+ scrollok(stdscr, FALSE);
+}
+
+/* Scroll area down */
+void scroll_down(gint y1, gint y2)
+{
+ scrollok(stdscr, TRUE);
+ setscrreg(y1, y2); scrl(-1);
+ scrollok(stdscr, FALSE);
+}
+
+void move_cursor(gint y, gint x)
+{
+ scry = y;
+ scrx = x;
+}
+
+void screen_refresh_freeze(void)
+{
+ freeze_refresh++;
+}
+
+void screen_refresh_thaw(void)
+{
+ if (freeze_refresh > 0)
+ {
+ freeze_refresh--;
+ if (freeze_refresh == 0) screen_refresh();
+ }
+}
+
+void screen_refresh(void)
+{
+ if (freeze_refresh == 0)
+ {
+ move(scry, scrx);
+ refresh();
+ }
+}
diff --git a/src/fe-text/screen.h b/src/fe-text/screen.h
new file mode 100644
index 00000000..3fc5694e
--- /dev/null
+++ b/src/fe-text/screen.h
@@ -0,0 +1,31 @@
+#ifndef __SCREEN_H
+#define __SCREEN_H
+
+#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+#define ATTR_UNDERLINE 0x100
+#define ATTR_COLOR8 0x200
+#define ATTR_REVERSE 0x400
+
+extern gboolean use_colors;
+
+gint init_screen(void); /* Initialize screen, detect screen length */
+void deinit_screen(void); /* Deinitialize screen */
+
+void set_color(gint col);
+void set_bg(gint col);
+
+void scroll_up(gint y1, gint y2); /* Scroll area up */
+void scroll_down(gint y1, gint y2); /* Scroll area down */
+
+void move_cursor(gint y, gint x);
+
+void screen_refresh_freeze(void);
+void screen_refresh_thaw(void);
+void screen_refresh(void);
+
+#endif