diff --git a/src/perl/Makefile.am b/src/perl/Makefile.am index 0e56d7a3..45ac1eea 100644 --- a/src/perl/Makefile.am +++ b/src/perl/Makefile.am @@ -108,6 +108,7 @@ textui_sources = \ textui/TextBufferView.xs \ textui/Statusbar.xs \ textui/Makefile.PL.in \ + textui/wrapper_buffer_line.h \ textui/typemap \ textui/module.h diff --git a/src/perl/textui/TextBuffer.xs b/src/perl/textui/TextBuffer.xs index 40602272..ae3973c8 100644 --- a/src/perl/textui/TextBuffer.xs +++ b/src/perl/textui/TextBuffer.xs @@ -1,5 +1,7 @@ #define PERL_NO_GET_CONTEXT #include "module.h" +#include "wrapper_buffer_line.h" +#include MODULE = Irssi::TextUI::TextBuffer PACKAGE = Irssi PROTOTYPES: ENABLE @@ -12,7 +14,7 @@ Irssi::TextUI::Line textbuffer_line_prev(line) Irssi::TextUI::Line line CODE: - RETVAL = line->prev; + RETVAL = perl_wrap_buffer_line(line->buffer, line->line->prev); OUTPUT: RETVAL @@ -20,13 +22,12 @@ Irssi::TextUI::Line textbuffer_line_next(line) Irssi::TextUI::Line line CODE: - RETVAL = line->next; + RETVAL = perl_wrap_buffer_line(line->buffer, line->line->next); OUTPUT: RETVAL void -textbuffer_line_get_text(buffer, line, coloring) - Irssi::TextUI::TextBuffer buffer +textbuffer_line_get_text(line, coloring) Irssi::TextUI::Line line int coloring PREINIT: @@ -34,8 +35,36 @@ PREINIT: SV *result; PPCODE: str = g_string_new(NULL); - textbuffer_line2text(buffer, line, coloring, str); + textbuffer_line2text(line->buffer, line->line, coloring, str); result = new_pv(str->str); XPUSHs(sv_2mortal(result)); g_string_free(str, TRUE); +void +textbuffer_line_get_format(line) + Irssi::TextUI::Line line +PREINIT: + HV *hv; + AV *av; + LINE_REC *l; + TEXT_BUFFER_FORMAT_REC *f; + int i; +PPCODE: + hv = newHV(); + l = line->line; + if (l->info.format != NULL) { + f = l->info.format; + (void) hv_store(hv, "module", 6, new_pv(f->module), 0); + (void) hv_store(hv, "format", 6, new_pv(f->format), 0); + (void) hv_store(hv, "server_tag", 10, new_pv(f->server_tag), 0); + (void) hv_store(hv, "target", 6, new_pv(f->target), 0); + (void) hv_store(hv, "nick", 4, new_pv(f->nick), 0); + av = newAV(); + for (i = 0; i < f->nargs; i++) { + av_push(av, new_pv(f->args[i])); + } + (void) hv_store(hv, "args", 4, newRV_noinc((SV *) av), 0); + } else { + (void) hv_store(hv, "text", 4, new_pv(l->info.text), 0); + } + XPUSHs(sv_2mortal(newRV_noinc((SV *) hv))); diff --git a/src/perl/textui/TextBufferView.xs b/src/perl/textui/TextBufferView.xs index c0dc762d..43aba4e6 100644 --- a/src/perl/textui/TextBufferView.xs +++ b/src/perl/textui/TextBufferView.xs @@ -1,5 +1,6 @@ #define PERL_NO_GET_CONTEXT #include "module.h" +#include "wrapper_buffer_line.h" MODULE = Irssi::TextUI::TextBufferView PACKAGE = Irssi::TextUI::TextBuffer PREFIX = textbuffer_ PROTOTYPES: ENABLE @@ -33,6 +34,10 @@ textbuffer_view_clear(view) Irssi::TextUI::Line textbuffer_view_get_lines(view) Irssi::TextUI::TextBufferView view +CODE: + RETVAL = perl_wrap_buffer_line(view->buffer, textbuffer_view_get_lines(view)); +OUTPUT: + RETVAL void textbuffer_view_scroll(view, lines) @@ -43,16 +48,24 @@ void textbuffer_view_scroll_line(view, line) Irssi::TextUI::TextBufferView view Irssi::TextUI::Line line +CODE: + textbuffer_view_scroll_line(view, line->line); Irssi::TextUI::LineCache textbuffer_view_get_line_cache(view, line) Irssi::TextUI::TextBufferView view Irssi::TextUI::Line line +CODE: + RETVAL = textbuffer_view_get_line_cache(view, line->line); +OUTPUT: + RETVAL void textbuffer_view_remove_line(view, line) Irssi::TextUI::TextBufferView view Irssi::TextUI::Line line +CODE: + textbuffer_view_remove_line(view, line->line); void textbuffer_view_remove_all_lines(view) @@ -68,6 +81,8 @@ textbuffer_view_set_bookmark(view, name, line) Irssi::TextUI::TextBufferView view char *name Irssi::TextUI::Line line +CODE: + textbuffer_view_set_bookmark(view, name, line->line); void textbuffer_view_set_bookmark_bottom(view, name) @@ -78,6 +93,10 @@ Irssi::TextUI::Line textbuffer_view_get_bookmark(view, name) Irssi::TextUI::TextBufferView view char *name +CODE: + RETVAL = perl_wrap_buffer_line(view->buffer, textbuffer_view_get_bookmark(view, name)); +OUTPUT: + RETVAL void textbuffer_view_redraw(view) diff --git a/src/perl/textui/TextUI.xs b/src/perl/textui/TextUI.xs index af978162..e87efb65 100644 --- a/src/perl/textui/TextUI.xs +++ b/src/perl/textui/TextUI.xs @@ -1,11 +1,17 @@ #define PERL_NO_GET_CONTEXT #include "module.h" +#include "wrapper_buffer_line.h" void perl_statusbar_init(void); void perl_statusbar_deinit(void); static int initialized = FALSE; +static SV *buffer_line_bless(TEXT_BUFFER_REC *buffer, LINE_REC *line) +{ + return perl_buffer_line_bless(perl_wrap_buffer_line(buffer, line)); +} + static void perl_main_window_fill_hash(HV *hv, MAIN_WINDOW_REC *window) { (void) hv_store(hv, "active", 6, plain_bless(window->active, "Irssi::UI::Window"), 0); @@ -20,9 +26,9 @@ static void perl_main_window_fill_hash(HV *hv, MAIN_WINDOW_REC *window) static void perl_text_buffer_fill_hash(HV *hv, TEXT_BUFFER_REC *buffer) { - (void) hv_store(hv, "first_line", 10, plain_bless(buffer->first_line, "Irssi::TextUI::Line"), 0); + (void) hv_store(hv, "first_line", 10, buffer_line_bless(buffer, buffer->first_line), 0); (void) hv_store(hv, "lines_count", 11, newSViv(buffer->lines_count), 0); - (void) hv_store(hv, "cur_line", 8, plain_bless(buffer->cur_line, "Irssi::TextUI::Line"), 0); + (void) hv_store(hv, "cur_line", 8, buffer_line_bless(buffer, buffer->cur_line), 0); (void) hv_store(hv, "last_eol", 8, newSViv(buffer->last_eol), 0); } @@ -38,20 +44,22 @@ static void perl_text_buffer_view_fill_hash(HV *hv, TEXT_BUFFER_VIEW_REC *view) (void) hv_store(hv, "ypos", 4, newSViv(view->ypos), 0); - (void) hv_store(hv, "startline", 9, plain_bless(view->startline, "Irssi::TextUI::Line"), 0); + (void) hv_store(hv, "startline", 9, buffer_line_bless(view->buffer, view->startline), 0); (void) hv_store(hv, "subline", 7, newSViv(view->subline), 0); (void) hv_store(hv, "hidden_level", 12, newSViv(view->hidden_level), 0); - (void) hv_store(hv, "bottom_startline", 16, plain_bless(view->bottom_startline, "Irssi::TextUI::Line"), 0); + (void) hv_store(hv, "bottom_startline", 16, + buffer_line_bless(view->buffer, view->bottom_startline), 0); (void) hv_store(hv, "bottom_subline", 14, newSViv(view->bottom_subline), 0); (void) hv_store(hv, "empty_linecount", 15, newSViv(view->empty_linecount), 0); (void) hv_store(hv, "bottom", 6, newSViv(view->bottom), 0); } -static void perl_line_fill_hash(HV *hv, LINE_REC *line) +static void perl_line_fill_hash(HV *hv, struct Buffer_Line_Wrapper *line) { - (void) hv_store(hv, "info", 4, plain_bless(&line->info, "Irssi::TextUI::LineInfo"), 0); + (void) hv_store(hv, "info", 4, plain_bless(&Line(line)->info, "Irssi::TextUI::LineInfo"), + 0); } static void perl_line_cache_fill_hash(HV *hv, LINE_CACHE_REC *cache) @@ -242,7 +250,7 @@ CODE: format_create_dest(&dest, NULL, NULL, level, window); text = format_string_expand(str, NULL); text2 = g_strconcat(text, "\n", NULL); - gui_printtext_after_time(&dest, prev, text2, time); + gui_printtext_after_time(&dest, Line(prev), text2, time); g_free(text); g_free(text2); @@ -257,13 +265,14 @@ PREINIT: TEXT_DEST_REC dest; CODE: format_create_dest(&dest, NULL, NULL, level, window); - gui_printtext_after_time(&dest, prev, str, time); + gui_printtext_after_time(&dest, Line(prev), str, time); Irssi::TextUI::Line last_line_insert(window) Irssi::UI::Window window CODE: - RETVAL = WINDOW_GUI(window)->insert_after; + RETVAL = perl_wrap_buffer_line(WINDOW_GUI(window)->view->buffer, + WINDOW_GUI(window)->insert_after); OUTPUT: RETVAL @@ -281,7 +290,7 @@ PREINIT: TEXT_DEST_REC dest; CODE: format_create_dest(&dest, server, target, level, NULL); - gui_printtext_after_time(&dest, prev, str, time); + gui_printtext_after_time(&dest, Line(prev), str, time); BOOT: irssi_boot(TextUI__Statusbar); diff --git a/src/perl/textui/module.h b/src/perl/textui/module.h index 394c2839..aba5bd77 100644 --- a/src/perl/textui/module.h +++ b/src/perl/textui/module.h @@ -11,7 +11,7 @@ typedef MAIN_WINDOW_REC *Irssi__TextUI__MainWindow; typedef TEXT_BUFFER_REC *Irssi__TextUI__TextBuffer; typedef TEXT_BUFFER_VIEW_REC *Irssi__TextUI__TextBufferView; -typedef LINE_REC *Irssi__TextUI__Line; +typedef struct Buffer_Line_Wrapper *Irssi__TextUI__Line; typedef LINE_CACHE_REC *Irssi__TextUI__LineCache; typedef LINE_INFO_REC *Irssi__TextUI__LineInfo; typedef SBAR_ITEM_REC *Irssi__TextUI__StatusbarItem; diff --git a/src/perl/textui/typemap b/src/perl/textui/typemap index 364cdf32..7710c2d2 100644 --- a/src/perl/textui/typemap +++ b/src/perl/textui/typemap @@ -2,7 +2,7 @@ TYPEMAP Irssi::TextUI::MainWindow T_PlainObj Irssi::TextUI::TextBuffer T_PlainObj Irssi::TextUI::TextBufferView T_PlainObj -Irssi::TextUI::Line T_PlainObj +Irssi::TextUI::Line T_BufferLineWrapper Irssi::TextUI::LineCache T_PlainObj Irssi::TextUI::LineInfo T_PlainObj Irssi::TextUI::StatusbarItem T_PlainObj @@ -12,8 +12,13 @@ INPUT T_PlainObj $var = irssi_ref_object($arg) +T_BufferLineWrapper + $var = irssi_ref_buffer_line_wrap($arg) + OUTPUT T_PlainObj $arg = plain_bless($var, \"$type\"); +T_BufferLineWrapper + $arg = perl_buffer_line_bless($var); diff --git a/src/perl/textui/wrapper_buffer_line.h b/src/perl/textui/wrapper_buffer_line.h new file mode 100644 index 00000000..34310655 --- /dev/null +++ b/src/perl/textui/wrapper_buffer_line.h @@ -0,0 +1,90 @@ +#ifndef IRSSI_PERL_TEXTUI_WRAPPER_BUFFER_LINE_H +#define IRSSI_PERL_TEXTUI_WRAPPER_BUFFER_LINE_H + +/* This Buffer_Line_Wrapper is a compatibility shim so that the Perl + * API does not change in Irssi ABI 24 even though the C API was + * changed. That way scripts can continue to work unchanged. */ + +struct Buffer_Line_Wrapper { + LINE_REC *line; + TEXT_BUFFER_REC *buffer; +}; + +#define Line(wrapper) ((wrapper) == NULL ? NULL : (wrapper)->line) + +static int magic_free_buffer_line(pTHX_ SV *sv, MAGIC *mg) +{ + struct Buffer_Line_Wrapper *wrap = (struct Buffer_Line_Wrapper *) mg->mg_ptr; + g_free(wrap); + mg->mg_ptr = NULL; + sv_setiv(sv, 0); + return 0; +} + +static MGVTBL vtbl_free_buffer_line = { NULL, NULL, NULL, NULL, magic_free_buffer_line }; + +static struct Buffer_Line_Wrapper *perl_wrap_buffer_line(TEXT_BUFFER_REC *buffer, LINE_REC *line) +{ + struct Buffer_Line_Wrapper *wrap; + + if (line == NULL) + return NULL; + + wrap = g_new0(struct Buffer_Line_Wrapper, 1); + wrap->buffer = buffer; + wrap->line = line; + + return wrap; +} + +/* This function is more or less a copy of plain_bless, but with a + special divertion to put the wrapper in _wrapper and the original + line pointer in _irssi, in order to stay compatible with signals + and scripts */ +static SV *perl_buffer_line_bless(struct Buffer_Line_Wrapper *object) +{ + SV *ret, **tmp; + HV *hv; + const char *stash = "Irssi::TextUI::Line"; + + if (object == NULL) + return &PL_sv_undef; + + ret = irssi_bless_plain(stash, object); + hv = hvref(ret); + + tmp = hv_fetch(hv, "_irssi", 6, 0); + + sv_magic(*tmp, NULL, '~', NULL, 0); + + SvMAGIC(*tmp)->mg_private = 0x1551; /* HF */ + SvMAGIC(*tmp)->mg_virtual = &vtbl_free_buffer_line; + SvMAGIC(*tmp)->mg_ptr = (char *) object; + + (void) hv_store(hv, "_wrapper", 8, *tmp, 0); + /* We have to put the Line Pointer in _irssi, not the + compatibility wrapper */ + *tmp = newSViv((IV) object->line); + return ret; +} + +/* This function is a copy of irssi_ref_object, but looking up the + wrapper object in _wrapper instead */ +static void *irssi_ref_buffer_line_wrap(SV *o) +{ + SV **sv; + HV *hv; + void *p; + + hv = hvref(o); + if (hv == NULL) + return NULL; + + sv = hv_fetch(hv, "_wrapper", 8, 0); + if (sv == NULL) + croak("variable is damaged"); + p = GINT_TO_POINTER(SvIV(*sv)); + return p; +} + +#endif