#include "module.h" #include #include #include #include #include #include #include #include #include #include #include #include #include TEXT_BUFFER_REC *color_buf; int scrollback_format; static void collector_free(GSList **collector) { while (*collector) { GSList *next = (*collector)->next->next; i_refstr_release((*collector)->data); g_free((*collector)->next->data); g_slist_free_1((*collector)->next); g_slist_free_1((*collector)); *collector = next; } } void textbuffer_format_rec_free(TEXT_BUFFER_FORMAT_REC *rec) { int n; if (rec == NULL) return; if (rec == LINE_INFO_FORMAT_SET) return; i_refstr_release(rec->module); i_refstr_release(rec->format); i_refstr_release(rec->server_tag); i_refstr_release(rec->target); i_refstr_release(rec->nick); if (rec->nargs >= 1) { i_refstr_release(rec->args[0]); } for (n = 1; n < rec->nargs; n++) { g_free(rec->args[n]); } rec->nargs = 0; g_free(rec->args); collector_free(&rec->expando_cache); g_slice_free(TEXT_BUFFER_FORMAT_REC, rec); } static TEXT_BUFFER_FORMAT_REC *format_rec_new(const char *module, const char *format_tag, const char *server_tag, const char *target, const char *nick, int nargs, const char **args) { int n; TEXT_BUFFER_FORMAT_REC *ret = g_slice_new0(TEXT_BUFFER_FORMAT_REC); ret->module = i_refstr_intern(module); ret->format = i_refstr_intern(format_tag); ret->server_tag = i_refstr_intern(server_tag); ret->target = i_refstr_intern(target); ret->nick = i_refstr_intern(nick); ret->nargs = nargs; ret->args = g_new0(char *, nargs); if (nargs >= 1) { ret->args[0] = i_refstr_intern(args[0]); } for (n = 1; n < nargs; n++) { ret->args[n] = g_strdup(args[n]); } return ret; } static LINE_INFO_REC *store_lineinfo_tmp(TEXT_DEST_REC *dest) { GUI_WINDOW_REC *gui; TEXT_BUFFER_VIEW_REC *view; TEXT_BUFFER_REC *buffer; LINE_INFO_REC *lineinfo; gui = WINDOW_GUI(dest->window); view = gui->view; buffer = view->buffer; lineinfo = g_new0(LINE_INFO_REC, 1); lineinfo->level = dest->level; lineinfo->time = (gui->use_insert_after && gui->insert_after_time) ? gui->insert_after_time : time(NULL); buffer->cur_info = g_slist_prepend(buffer->cur_info, lineinfo); return lineinfo; } static void free_lineinfo_tmp(WINDOW_REC *window) { GUI_WINDOW_REC *gui; TEXT_BUFFER_REC *buffer; LINE_INFO_REC *info; gui = WINDOW_GUI(window); buffer = gui->view->buffer; if (buffer->cur_info == NULL) return; info = buffer->cur_info->data; buffer->cur_info = g_slist_delete_link(buffer->cur_info, buffer->cur_info); textbuffer_format_rec_free(info->format); g_free(info); } static void sig_print_format(THEME_REC *theme, const char *module, TEXT_DEST_REC *dest, void *formatnump, const char **args) { int formatnum; FORMAT_REC *formats; LINE_INFO_REC *info; if (!scrollback_format) return; info = store_lineinfo_tmp(dest); formatnum = GPOINTER_TO_INT(formatnump); formats = g_hash_table_lookup(default_formats, module); info->format = format_rec_new(module, formats[formatnum].tag, dest->server_tag, dest->target, dest->nick, formats[formatnum].params, args); special_push_collector(&info->format->expando_cache); info->format->flags = dest->flags; dest->flags |= PRINT_FLAG_FORMAT; signal_continue(5, theme, module, dest, formatnump, args); special_pop_collector(); free_lineinfo_tmp(dest->window); } static void sig_print_noformat(TEXT_DEST_REC *dest, const char *text) { LINE_INFO_REC *info; if (!scrollback_format) return; special_push_collector(NULL); info = store_lineinfo_tmp(dest); info->format = format_rec_new(NULL, NULL, dest->server_tag, dest->target, dest->nick, 2, (const char *[]){ NULL, text }); special_push_collector(&info->format->expando_cache); info->format->flags = dest->flags; dest->flags |= PRINT_FLAG_FORMAT; signal_continue(2, dest, text); special_pop_collector(); free_lineinfo_tmp(dest->window); } static GSList *reverse_collector(GSList *a1) { GSList *b1, *c1; c1 = NULL; while (a1) { b1 = a1->next->next; a1->next->next = c1; c1 = a1; a1 = b1; } return c1; } static void sig_gui_print_text_finished(WINDOW_REC *window) { GUI_WINDOW_REC *gui; LINE_REC *insert_after; LINE_INFO_REC *info; TEXT_BUFFER_REC *buffer; gui = WINDOW_GUI(window); buffer = gui->view->buffer; insert_after = gui->use_insert_after ? gui->insert_after : buffer->cur_line; if (buffer->cur_info == NULL) return; info = buffer->cur_info->data; if (info->format == NULL) return; info->format->expando_cache = reverse_collector(info->format->expando_cache); info->level |= MSGLEVEL_FORMAT; /* the line will be inserted into the view with textbuffer_view_insert_line by gui-printtext.c:view_add_eol */ insert_after = textbuffer_insert(buffer, insert_after, (const unsigned char[]){}, 0, info); /* the TEXT_BUFFER_FORMAT_REC pointer is now owned by the textbuffer */ info->format = LINE_INFO_FORMAT_SET; if (gui->use_insert_after) gui->insert_after = insert_after; } static void parse_colors_collector(const WINDOW_REC *window, const void *fgcolor_int, const void *bgcolor_int, const void *flags_int, const char *textpiece, const TEXT_DEST_REC *dest) { int fg, bg, flags, attr; flags = GPOINTER_TO_INT(flags_int); fg = GPOINTER_TO_INT(fgcolor_int); bg = GPOINTER_TO_INT(bgcolor_int); gui_printtext_get_colors(&flags, &fg, &bg, &attr); if (flags & GUI_PRINT_FLAG_NEWLINE) { g_string_append_c(color_buf->cur_text, '\n'); } format_gui_flags(color_buf->cur_text, &color_buf->last_fg, &color_buf->last_bg, &color_buf->last_flags, fg, bg, flags); g_string_append(color_buf->cur_text, textpiece); } static char *parse_colors(TEXT_DEST_REC *dest, const char *text) { char *tmp; if (text == NULL) return NULL; color_buf = textbuffer_create(NULL); format_send_as_gui_flags(dest, text, (SIGNAL_FUNC) parse_colors_collector); tmp = g_strdup(color_buf->cur_text->str); textbuffer_destroy(color_buf); color_buf = NULL; return tmp; } char *textbuffer_line_get_text(TEXT_BUFFER_REC *buffer, LINE_REC *line) { TEXT_DEST_REC dest; GUI_WINDOW_REC *gui; char *tmp, *text = NULL; g_return_val_if_fail(buffer != NULL, NULL); g_return_val_if_fail(buffer->window != NULL, NULL); gui = WINDOW_GUI(buffer->window); if (line == NULL || gui == NULL) return NULL; if (line->info.level & MSGLEVEL_FORMAT && line->info.format != NULL) { LINE_REC *curr; THEME_REC *theme; int formatnum; TEXT_BUFFER_FORMAT_REC *format_rec; char *str; curr = line; line = NULL; format_rec = curr->info.format; format_create_dest( &dest, format_rec->server_tag != NULL ? server_find_tag(format_rec->server_tag) : NULL, format_rec->target, curr->info.level & ~MSGLEVEL_FORMAT, buffer->window); theme = window_get_theme(dest.window); special_fill_cache(format_rec->expando_cache); if (format_rec->format != NULL) { char *arglist[MAX_FORMAT_PARAMS] = { 0 }; formatnum = format_find_tag(format_rec->module, format_rec->format); memcpy(arglist, format_rec->args, format_rec->nargs * sizeof(char *)); text = format_get_text_theme_charargs(theme, format_rec->module, &dest, formatnum, arglist); } else { text = g_strdup(format_rec->args[1]); } if (*text != '\0') { current_time = curr->info.time; tmp = format_get_level_tag(theme, &dest); str = !theme->info_eol ? format_add_linestart(text, tmp) : format_add_lineend(text, tmp); g_free_not_null(tmp); g_free_not_null(text); text = str; tmp = format_get_line_start(theme, &dest, curr->info.time); str = !theme->info_eol ? format_add_linestart(text, tmp) : format_add_lineend(text, tmp); g_free_not_null(tmp); g_free_not_null(text); text = str; /* str = g_strconcat(text, "\n", NULL); */ /* g_free(text); */ dest.flags |= PRINT_FLAG_FORMAT; current_time = (time_t) -1; } else if (format_rec->format != NULL) { g_free(text); text = NULL; } special_fill_cache(NULL); } else { format_create_dest(&dest, NULL, NULL, line->info.level, buffer->window); text = g_strdup(line->info.text); } tmp = parse_colors(&dest, text); g_free(text); return tmp; } static void read_settings(void) { scrollback_format = settings_get_bool("scrollback_format"); } void textbuffer_formats_init(void) { settings_add_bool("lookandfeel", "scrollback_format", TRUE); read_settings(); signal_add("print format", (SIGNAL_FUNC) sig_print_format); signal_add("print noformat", (SIGNAL_FUNC) sig_print_noformat); signal_add_first("gui print text finished", (SIGNAL_FUNC) sig_gui_print_text_finished); signal_add("setup changed", (SIGNAL_FUNC) read_settings); } void textbuffer_formats_deinit(void) { signal_remove("setup changed", (SIGNAL_FUNC) read_settings); signal_remove("print format", (SIGNAL_FUNC) sig_print_format); signal_remove("print noformat", (SIGNAL_FUNC) sig_print_noformat); signal_remove("gui print text finished", (SIGNAL_FUNC) sig_gui_print_text_finished); }