summaryrefslogtreecommitdiffstats
path: root/src/fe-text/gui-printtext.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fe-text/gui-printtext.c')
-rw-r--r--src/fe-text/gui-printtext.c429
1 files changed, 429 insertions, 0 deletions
diff --git a/src/fe-text/gui-printtext.c b/src/fe-text/gui-printtext.c
new file mode 100644
index 0000000..d317456
--- /dev/null
+++ b/src/fe-text/gui-printtext.c
@@ -0,0 +1,429 @@
+/*
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/settings.h>
+#include <irssi/src/core/signals.h>
+
+#include <irssi/src/fe-common/core/formats.h>
+#include <irssi/src/fe-common/core/printtext.h>
+#include <irssi/src/fe-common/core/themes.h>
+
+#include <irssi/src/fe-text/term.h>
+#include <irssi/src/fe-text/gui-printtext.h>
+#include <irssi/src/fe-text/gui-windows.h>
+
+/* Terminal indexed colour map */
+int mirc_colors[] = { 15, 0, 1, 2, 12, 4, 5, 6, 14, 10, 3, 11, 9, 13, 8, 7,
+ /* 16-27 */ 52, 94, 100, 58, 22, 29, 23, 24, 17, 54, 53, 89,
+ /* 28-39 */ 88, 130, 142, 64, 28, 35, 30, 25, 18, 91, 90, 125,
+ /* 40-51 */ 124, 166, 184, 106, 34, 49, 37, 33, 19, 129, 127, 161,
+ /* 52-63 */ 196, 208, 226, 154, 46, 86, 51, 75, 21, 171, 201, 198,
+ /* 64-75 */ 203, 215, 227, 191, 83, 122, 87, 111, 63, 177, 207, 205,
+ /* 76-87 */ 217, 223, 229, 193, 157, 158, 159, 153, 147, 183, 219, 212,
+ /* 88-98 */ 16, 233, 235, 237, 239, 241, 244, 247, 250, 254, 231, -1 };
+
+/* RGB colour map */
+int mirc_colors24[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ /* 16-27 */ 0x470000, 0x472100, 0x474700, 0x324700, 0x004700, 0x00472c, 0x004747, 0x002747, 0x000047, 0x2e0047, 0x470047, 0x47002a,
+ /* 28-39 */ 0x740000, 0x743a00, 0x747400, 0x517400, 0x007400, 0x007449, 0x007474, 0x004074, 0x000074, 0x4b0074, 0x740074, 0x740045,
+ /* 40-51 */ 0xb50000, 0xb56300, 0xb5b500, 0x7db500, 0x00b500, 0x00b571, 0x00b5b5, 0x0063b5, 0x0000b5, 0x7500b5, 0xb500b5, 0xb5006b,
+ /* 52-63 */ 0xff0000, 0xff8c00, 0xffff00, 0xb2ff00, 0x00ff00, 0x00ffa0, 0x00ffff, 0x008cff, 0x0000ff, 0xa500ff, 0xff00ff, 0xff0098,
+ /* 64-75 */ 0xff5959, 0xffb459, 0xffff71, 0xcfff60, 0x6fff6f, 0x65ffc9, 0x6dffff, 0x59b4ff, 0x5959ff, 0xc459ff, 0xff66ff, 0xff59bc,
+ /* 76-87 */ 0xff9c9c, 0xffd39c, 0xffff9c, 0xe2ff9c, 0x9cff9c, 0x9cffdb, 0x9cffff, 0x9cd3ff, 0x9c9cff, 0xdc9cff, 0xff9cff, 0xff94d3,
+ /* 88-98 */ 0x000000, 0x131313, 0x282828, 0x363636, 0x4d4d4d, 0x656565, 0x818181, 0x9f9f9f, 0xbcbcbc, 0xe2e2e2, 0xffffff, -1 };
+
+static int scrollback_lines, scrollback_time, scrollback_burst_remove;
+/*
+ * If positive, remove lines older than scrollback_max_age seconds.
+ * Deletion is triggered by the "gui print text finished" signal (i.e. a message
+ * for the window). Note: "Day changed to" message also cause messages to be
+ * deleted within 1 day latency.
+ */
+static int scrollback_max_age;
+
+static int next_xpos, next_ypos;
+
+static GHashTable *indent_functions;
+static INDENT_FUNC default_indent_func;
+
+void gui_register_indent_func(const char *name, INDENT_FUNC func)
+{
+ gpointer key, value;
+ GSList *list;
+
+ if (g_hash_table_lookup_extended(indent_functions, name, &key, &value)) {
+ list = value;
+ g_hash_table_remove(indent_functions, key);
+ } else {
+ key = g_strdup(name);
+ list = NULL;
+ }
+
+ list = g_slist_append(list, (void *) func);
+ g_hash_table_insert(indent_functions, key, list);
+}
+
+void gui_unregister_indent_func(const char *name, INDENT_FUNC func)
+{
+ gpointer key, value;
+ GSList *list;
+
+ if (g_hash_table_lookup_extended(indent_functions, name, &key, &value)) {
+ list = value;
+
+ list = g_slist_remove(list, (void *) func);
+ g_hash_table_remove(indent_functions, key);
+ if (list == NULL)
+ g_free(key);
+ else
+ g_hash_table_insert(indent_functions, key, list);
+ }
+
+ if (default_indent_func == func)
+ gui_set_default_indent(NULL);
+
+ textbuffer_views_unregister_indent_func(func);
+}
+
+void gui_set_default_indent(const char *name)
+{
+ GSList *list;
+
+ list = name == NULL ? NULL :
+ g_hash_table_lookup(indent_functions, name);
+ default_indent_func = list == NULL ? NULL :
+ (INDENT_FUNC) list->data;
+ gui_windows_reset_settings();
+}
+
+INDENT_FUNC get_default_indent_func(void)
+{
+ return default_indent_func;
+}
+
+void gui_printtext(int xpos, int ypos, const char *str)
+{
+ next_xpos = xpos;
+ next_ypos = ypos;
+
+ printtext_gui(str);
+
+ next_xpos = next_ypos = -1;
+}
+
+void gui_printtext_internal(int xpos, int ypos, const char *str)
+{
+ next_xpos = xpos;
+ next_ypos = ypos;
+
+ printtext_gui_internal(str);
+
+ next_xpos = next_ypos = -1;
+}
+
+static void view_add_eol(TEXT_BUFFER_VIEW_REC *view, LINE_REC **line);
+
+void gui_printtext_after_time(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str, time_t time)
+{
+ GUI_WINDOW_REC *gui;
+
+ gui = WINDOW_GUI(dest->window);
+
+ if (prev == NULL && !gui->view->buffer->last_eol) {
+ /* we have an unfinished line in the buffer still */
+ view_add_eol(gui->view, &gui->insert_after);
+ }
+
+ gui->use_insert_after = TRUE;
+ gui->insert_after = prev;
+ gui->insert_after_time = time;
+ format_send_to_gui(dest, str);
+ gui->use_insert_after = FALSE;
+ signal_emit("gui print text after finished", 4, dest->window, gui->insert_after, prev,
+ dest);
+}
+
+void gui_printtext_after(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str)
+{
+ gui_printtext_after_time(dest, prev, str, 0);
+}
+
+void gui_printtext_window_border(int x, int y)
+{
+ char *v0, *v1;
+ int len;
+ if (current_theme != NULL) {
+ v1 = theme_format_expand(current_theme, "{window_border} ");
+ len = format_real_length(v1, 1);
+ v1[len] = '\0';
+ }
+ else {
+ v1 = g_strdup(" ");
+ }
+
+ if (*v1 == '\0') {
+ g_free(v1);
+ v1 = g_strdup(" ");
+ }
+
+ if (clrtoeol_info->color != NULL) {
+ char *color = g_strdup(clrtoeol_info->color);
+ len = format_real_length(color, 0);
+ color[len] = '\0';
+ v0 = g_strconcat(color, v1, NULL);
+ g_free(color);
+ g_free(v1);
+ } else {
+ v0 = v1;
+ }
+
+ gui_printtext(x, y, v0);
+ g_free(v0);
+}
+
+static void remove_old_lines(TEXT_BUFFER_VIEW_REC *view)
+{
+ LINE_REC *line;
+ time_t cur_time = time(NULL);
+ time_t old_time;
+
+ old_time = cur_time - scrollback_time + 1;
+ if (view->buffer->lines_count >=
+ scrollback_lines+scrollback_burst_remove) {
+ /* remove lines by line count */
+ while (view->buffer->lines_count > scrollback_lines) {
+ line = view->buffer->first_line;
+ if (line->info.time >= old_time ||
+ scrollback_lines == 0) {
+ /* too new line, don't remove yet - also
+ if scrollback_lines is 0, we want to check
+ only scrollback_time setting. */
+ break;
+ }
+ textbuffer_view_remove_line(view, line);
+ }
+ }
+
+ if (scrollback_max_age > 0) {
+ old_time = cur_time - scrollback_max_age;
+ while (view->buffer->lines_count > 0) {
+ line = view->buffer->first_line;
+ if (line->info.time >= old_time) {
+ /*
+ * The first line is newer than the threshold
+ * time -> no need to remove more lines.
+ */
+ break;
+ }
+ textbuffer_view_remove_line(view, line);
+ }
+ }
+}
+
+void gui_printtext_get_colors(int *flags, int *fg, int *bg, int *attr)
+{
+ *attr = 0;
+ if (*flags & GUI_PRINT_FLAG_MIRC_COLOR) {
+ /* mirc colors - extended colours proposal */
+ gboolean use_24_map = FALSE;
+#ifdef TERM_TRUECOLOR
+ use_24_map = settings_get_bool("colors_ansi_24bit");
+#endif
+ if (*bg >= 0) {
+ if (use_24_map && mirc_colors24[*bg % 100] != -1) {
+ *bg = mirc_colors24[*bg % 100];
+ *flags |= GUI_PRINT_FLAG_COLOR_24_BG;
+ } else {
+ *bg = mirc_colors[*bg % 100];
+ *flags &= ~GUI_PRINT_FLAG_COLOR_24_BG;
+ /* ignore mirc color 99 = -1 (reset) */
+ if (*bg != -1 && settings_get_bool("mirc_blink_fix")) {
+ if (*bg < 16) /* ansi bit flip :-( */
+ *bg = (*bg&8) | (*bg&4)>>2 | (*bg&2) | (*bg&1)<<2;
+ *bg = term_color256map[*bg&0xff] & 7;
+ }
+ }
+ }
+ if (*fg >= 0) {
+ if (use_24_map && mirc_colors24[*fg % 100] != -1) {
+ *fg = mirc_colors24[*fg % 100];
+ *flags |= GUI_PRINT_FLAG_COLOR_24_FG;
+ } else {
+ *fg = mirc_colors[*fg % 100];
+ *flags &= ~GUI_PRINT_FLAG_COLOR_24_FG;
+ }
+ }
+ }
+
+ if (*flags & GUI_PRINT_FLAG_COLOR_24_FG)
+ *attr |= ATTR_FGCOLOR24;
+ else if (*fg < 0 || *fg > 255) {
+ *fg = -1;
+ *attr |= ATTR_RESETFG;
+ }
+ else
+ *attr |= *fg;
+
+ if (*flags & GUI_PRINT_FLAG_COLOR_24_BG)
+ *attr |= ATTR_BGCOLOR24;
+ else if (*bg < 0 || *bg > 255) {
+ *bg = -1;
+ *attr |= ATTR_RESETBG;
+ }
+ else
+ *attr |= (*bg << BG_SHIFT);
+
+ if (*flags & GUI_PRINT_FLAG_REVERSE) *attr |= ATTR_REVERSE;
+ if (*flags & GUI_PRINT_FLAG_ITALIC) *attr |= ATTR_ITALIC;
+ if (*flags & GUI_PRINT_FLAG_BOLD) *attr |= ATTR_BOLD;
+ if (*flags & GUI_PRINT_FLAG_UNDERLINE) *attr |= ATTR_UNDERLINE;
+ if (*flags & GUI_PRINT_FLAG_BLINK) *attr |= ATTR_BLINK;
+}
+
+static void view_add_eol(TEXT_BUFFER_VIEW_REC *view, LINE_REC **line)
+{
+ static const unsigned char eol[] = { 0, LINE_CMD_EOL };
+
+ *line = textbuffer_insert(view->buffer, *line, eol, 2, NULL);
+ textbuffer_view_insert_line(view, *line);
+}
+
+static void print_text_no_window(int flags, int fg, int bg, int attr, const char *str)
+{
+ g_return_if_fail(next_xpos != -1);
+
+ term_set_color2(root_window, attr, fg, bg);
+
+ term_move(root_window, next_xpos, next_ypos);
+ if (flags & GUI_PRINT_FLAG_CLRTOEOL) {
+ if (clrtoeol_info->window != NULL) {
+ term_window_clrtoeol_abs(clrtoeol_info->window, next_ypos);
+ } else {
+ term_clrtoeol(root_window);
+ }
+ }
+ next_xpos += term_addstr(root_window, str);
+}
+
+static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor,
+ void *bgcolor, void *pflags,
+ const char *str, TEXT_DEST_REC *dest)
+{
+ GUI_WINDOW_REC *gui;
+ TEXT_BUFFER_VIEW_REC *view;
+ LINE_REC *insert_after;
+ LINE_INFO_REC lineinfo = { 0 };
+ int fg, bg, flags, attr;
+
+ flags = GPOINTER_TO_INT(pflags);
+ fg = GPOINTER_TO_INT(fgcolor);
+ bg = GPOINTER_TO_INT(bgcolor);
+ gui_printtext_get_colors(&flags, &fg, &bg, &attr);
+
+ if (window == NULL) {
+ print_text_no_window(flags, fg, bg, attr, str);
+ return;
+ }
+
+ if (dest != NULL && dest->flags & PRINT_FLAG_FORMAT) {
+ return;
+ }
+
+ gui = WINDOW_GUI(window);
+ view = gui->view;
+
+ lineinfo.level = dest == NULL ? 0 : dest->level;
+ lineinfo.time =
+ (gui->use_insert_after && gui->insert_after_time) ? gui->insert_after_time : time(NULL);
+ lineinfo.format =
+ dest != NULL && dest->flags & PRINT_FLAG_FORMAT ? LINE_INFO_FORMAT_SET : NULL;
+
+ insert_after = gui->use_insert_after ?
+ gui->insert_after : view->buffer->cur_line;
+
+ if (flags & GUI_PRINT_FLAG_NEWLINE) {
+ view_add_eol(view, &insert_after);
+ }
+ textbuffer_line_add_colors(view->buffer, &insert_after, fg, bg, flags);
+
+ /* for historical reasons, the \n will set
+ GUI_PRINT_FLAG_NEWLINE and print an empty string. in this
+ special case, ignore the empty string which would otherwise
+ start another new line */
+ if (~flags & GUI_PRINT_FLAG_NEWLINE || *str != '\0') {
+ insert_after = textbuffer_insert(view->buffer, insert_after, (unsigned char *) str,
+ strlen(str), &lineinfo);
+ }
+
+ if (gui->use_insert_after)
+ gui->insert_after = insert_after;
+}
+
+static void sig_gui_printtext_finished(WINDOW_REC *window, TEXT_DEST_REC *dest)
+{
+ TEXT_BUFFER_VIEW_REC *view;
+ LINE_REC *insert_after;
+
+ view = WINDOW_GUI(window)->view;
+ insert_after = WINDOW_GUI(window)->use_insert_after ?
+ WINDOW_GUI(window)->insert_after : view->buffer->cur_line;
+
+ if (insert_after != NULL)
+ view_add_eol(view, &insert_after);
+ remove_old_lines(view);
+}
+
+static void read_settings(void)
+{
+ scrollback_lines = settings_get_int("scrollback_lines");
+ scrollback_time = settings_get_time("scrollback_time")/1000;
+ scrollback_max_age = settings_get_time("scrollback_max_age")/1000;
+ scrollback_burst_remove = settings_get_int("scrollback_burst_remove");
+}
+
+void gui_printtext_init(void)
+{
+ next_xpos = next_ypos = -1;
+ default_indent_func = NULL;
+ indent_functions = g_hash_table_new((GHashFunc) g_str_hash,
+ (GCompareFunc) g_str_equal);
+
+ settings_add_int("history", "scrollback_lines", 500);
+ settings_add_time("history", "scrollback_time", "1day");
+ settings_add_time("history", "scrollback_max_age", "0");
+ settings_add_int("history", "scrollback_burst_remove", 10);
+
+ signal_add("gui print text", (SIGNAL_FUNC) sig_gui_print_text);
+ signal_add("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+
+ read_settings();
+}
+
+void gui_printtext_deinit(void)
+{
+ g_hash_table_destroy(indent_functions);
+
+ signal_remove("gui print text", (SIGNAL_FUNC) sig_gui_print_text);
+ signal_remove("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+}