diff options
Diffstat (limited to 'src/fe-text')
-rw-r--r-- | src/fe-text/Makefile.am | 46 | ||||
-rw-r--r-- | src/fe-text/gui-entry.c | 177 | ||||
-rw-r--r-- | src/fe-text/gui-entry.h | 22 | ||||
-rw-r--r-- | src/fe-text/gui-mainwindows.c | 66 | ||||
-rw-r--r-- | src/fe-text/gui-mainwindows.h | 21 | ||||
-rw-r--r-- | src/fe-text/gui-printtext.c | 334 | ||||
-rw-r--r-- | src/fe-text/gui-printtext.h | 28 | ||||
-rw-r--r-- | src/fe-text/gui-readline.c | 374 | ||||
-rw-r--r-- | src/fe-text/gui-readline.h | 10 | ||||
-rw-r--r-- | src/fe-text/gui-special-vars.c | 61 | ||||
-rw-r--r-- | src/fe-text/gui-special-vars.h | 7 | ||||
-rw-r--r-- | src/fe-text/gui-statusbar-items.c | 691 | ||||
-rw-r--r-- | src/fe-text/gui-statusbar-items.h | 7 | ||||
-rw-r--r-- | src/fe-text/gui-statusbar.c | 237 | ||||
-rw-r--r-- | src/fe-text/gui-statusbar.h | 21 | ||||
-rw-r--r-- | src/fe-text/gui-textwidget.c | 390 | ||||
-rw-r--r-- | src/fe-text/gui-textwidget.h | 7 | ||||
-rw-r--r-- | src/fe-text/gui-windows.c | 780 | ||||
-rw-r--r-- | src/fe-text/gui-windows.h | 93 | ||||
-rw-r--r-- | src/fe-text/irssi.c | 156 | ||||
-rw-r--r-- | src/fe-text/module-formats.c | 30 | ||||
-rw-r--r-- | src/fe-text/module-formats.h | 11 | ||||
-rw-r--r-- | src/fe-text/module.h | 6 | ||||
-rw-r--r-- | src/fe-text/screen.c | 254 | ||||
-rw-r--r-- | src/fe-text/screen.h | 31 |
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 |