summaryrefslogtreecommitdiffstats
path: root/src/perl/textui
diff options
context:
space:
mode:
Diffstat (limited to 'src/perl/textui')
-rw-r--r--src/perl/textui/Makefile.PL.in8
-rw-r--r--src/perl/textui/Statusbar.xs167
-rw-r--r--src/perl/textui/TextBuffer.xs110
-rw-r--r--src/perl/textui/TextBufferView.xs115
-rw-r--r--src/perl/textui/TextUI.pm26
-rw-r--r--src/perl/textui/TextUI.xs318
-rw-r--r--src/perl/textui/meson.build37
-rw-r--r--src/perl/textui/module.h17
-rw-r--r--src/perl/textui/typemap24
-rw-r--r--src/perl/textui/wrapper_buffer_line.h90
10 files changed, 912 insertions, 0 deletions
diff --git a/src/perl/textui/Makefile.PL.in b/src/perl/textui/Makefile.PL.in
new file mode 100644
index 0000000..2b0a148
--- /dev/null
+++ b/src/perl/textui/Makefile.PL.in
@@ -0,0 +1,8 @@
+use ExtUtils::MakeMaker;our $AM_DEFAULT_VERBOSITY='@AM_DEFAULT_VERBOSITY@';require "@top_srcdir@/src/perl/Makefile_silent.pm";
+
+WriteMakefile('NAME' => 'Irssi::TextUI',
+ 'LIBS' => '',
+ 'OBJECT' => '$(O_FILES)',
+ 'TYPEMAPS' => ['../common/typemap', '../ui/typemap'],
+ 'INC' => '-I../../.. @GLIB_CFLAGS@',
+ 'VERSION_FROM' => '@srcdir@/TextUI.pm');
diff --git a/src/perl/textui/Statusbar.xs b/src/perl/textui/Statusbar.xs
new file mode 100644
index 0000000..111deaa
--- /dev/null
+++ b/src/perl/textui/Statusbar.xs
@@ -0,0 +1,167 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+
+static GHashTable *perl_sbar_defs;
+
+static int check_sbar_destroy(char *key, char *value, char *script)
+{
+ if (strncmp(value, script, strlen(script)) == 0 &&
+ value[strlen(script)] == ':') {
+ statusbar_item_unregister(key);
+ g_free(key);
+ g_free(value);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void script_unregister_statusbars(PERL_SCRIPT_REC *script)
+{
+ g_hash_table_foreach_remove(perl_sbar_defs,
+ (GHRFunc) check_sbar_destroy,
+ script->package);
+}
+
+void perl_statusbar_init(void)
+{
+ perl_sbar_defs = g_hash_table_new((GHashFunc) g_str_hash,
+ (GCompareFunc) g_str_equal);
+ signal_add("script destroyed", (SIGNAL_FUNC) script_unregister_statusbars);
+}
+
+static void statusbar_item_def_destroy(void *key, void *value)
+{
+ statusbar_item_unregister(key);
+ g_free(key);
+ g_free(value);
+}
+
+void perl_statusbar_deinit(void)
+{
+ signal_remove("script destroyed", (SIGNAL_FUNC) script_unregister_statusbars);
+
+ g_hash_table_foreach(perl_sbar_defs,
+ (GHFunc) statusbar_item_def_destroy, NULL);
+ g_hash_table_destroy(perl_sbar_defs);
+}
+
+static void perl_statusbar_event(char *function, SBAR_ITEM_REC *item,
+ int get_size_only)
+{
+ dSP;
+ SV *item_sv, **sv;
+ HV *hv;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(SP);
+ item_sv = plain_bless(item, "Irssi::TextUI::StatusbarItem");
+ XPUSHs(sv_2mortal(item_sv));
+ XPUSHs(sv_2mortal(newSViv(get_size_only)));
+ PUTBACK;
+
+ perl_call_pv(function, G_EVAL|G_DISCARD);
+ SPAGAIN;
+
+ if (SvTRUE(ERRSV)) {
+ PERL_SCRIPT_REC *script;
+ char *package, *error;
+
+ package = perl_function_get_package(function);
+ script = perl_script_find_package(package);
+ g_free(package);
+
+ if (script != NULL) {
+ /* make sure we don't get back here */
+ script_unregister_statusbars(script);
+ }
+
+ error = g_strdup(SvPV_nolen(ERRSV));
+ signal_emit("script error", 2, script, error);
+ g_free(error);
+ } else {
+ /* min_size and max_size can be changed, move them to SBAR_ITEM_REC */
+ hv = hvref(item_sv);
+ if (hv != NULL) {
+ sv = hv_fetch(hv, "min_size", 8, 0);
+ if (sv != NULL) item->min_size = SvIV(*sv);
+ sv = hv_fetch(hv, "max_size", 8, 0);
+ if (sv != NULL) item->max_size = SvIV(*sv);
+ }
+ }
+
+ FREETMPS;
+ LEAVE;
+}
+
+
+static void sig_perl_statusbar(SBAR_ITEM_REC *item, int get_size_only)
+{
+ char *function;
+
+ function = g_hash_table_lookup(perl_sbar_defs, item->config->name);
+ if (function != NULL)
+ perl_statusbar_event(function, item, get_size_only);
+ else {
+ /* use default function - this shouldn't actually happen.. */
+ statusbar_item_default_handler(item, get_size_only, NULL, "", TRUE);
+ }
+}
+
+MODULE = Irssi::TextUI::Statusbar PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+void
+statusbar_item_register(name, value, func = NULL)
+ char *name
+ char *value
+ char *func
+CODE:
+ statusbar_item_register(name, value, func == NULL || *func == '\0' ? NULL : sig_perl_statusbar);
+ if (func != NULL) {
+ g_hash_table_insert(perl_sbar_defs, g_strdup(name),
+ g_strdup_printf("%s::%s", perl_get_package(), func));
+ }
+
+void
+statusbar_item_unregister(name)
+ char *name
+PREINIT:
+ gpointer key, value;
+CODE:
+ if (g_hash_table_lookup_extended(perl_sbar_defs, name, &key, &value)) {
+ g_hash_table_remove(perl_sbar_defs, name);
+ g_free(key);
+ g_free(value);
+ }
+ statusbar_item_unregister(name);
+
+void
+statusbar_items_redraw(name)
+ char *name
+
+void
+statusbars_recreate_items()
+
+#*******************************
+MODULE = Irssi::TextUI::Statusbar PACKAGE = Irssi::TextUI::StatusbarItem PREFIX = statusbar_item_
+#*******************************
+
+void
+statusbar_item_default_handler(item, get_size_only, str, data, escape_vars = TRUE)
+ Irssi::TextUI::StatusbarItem item
+ int get_size_only
+ char *str
+ char *data
+ int escape_vars
+PREINIT:
+ HV *hv;
+CODE:
+ statusbar_item_default_handler(item, get_size_only,
+ *str == '\0' ? NULL : str,
+ data, escape_vars);
+ hv = hvref(ST(0));
+ (void) hv_store(hv, "min_size", 8, newSViv(item->min_size), 0);
+ (void) hv_store(hv, "max_size", 8, newSViv(item->max_size), 0);
diff --git a/src/perl/textui/TextBuffer.xs b/src/perl/textui/TextBuffer.xs
new file mode 100644
index 0000000..655dbd3
--- /dev/null
+++ b/src/perl/textui/TextBuffer.xs
@@ -0,0 +1,110 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+#include "wrapper_buffer_line.h"
+#include <irssi/src/fe-text/textbuffer-formats.h>
+
+MODULE = Irssi::TextUI::TextBuffer PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+#*******************************
+MODULE = Irssi::TextUI::TextBuffer PACKAGE = Irssi
+#*******************************
+
+int
+COLORING_STRIP()
+CODE:
+ RETVAL = COLORING_STRIP;
+OUTPUT:
+ RETVAL
+
+int
+COLORING_EXPAND()
+CODE:
+ RETVAL = COLORING_EXPAND;
+OUTPUT:
+ RETVAL
+
+int
+COLORING_UNEXPAND()
+CODE:
+ RETVAL = COLORING_UNEXPAND;
+OUTPUT:
+ RETVAL
+
+int
+COLORING_RAW()
+CODE:
+ RETVAL = COLORING_RAW;
+OUTPUT:
+ RETVAL
+
+#*******************************
+MODULE = Irssi::TextUI::TextBuffer PACKAGE = Irssi::TextUI::Line PREFIX = textbuffer_line_
+#*******************************
+
+Irssi::TextUI::Line
+textbuffer_line_prev(line)
+ Irssi::TextUI::Line line
+CODE:
+ RETVAL = perl_wrap_buffer_line(line->buffer, line->line->prev);
+OUTPUT:
+ RETVAL
+
+Irssi::TextUI::Line
+textbuffer_line_next(line)
+ Irssi::TextUI::Line line
+CODE:
+ RETVAL = perl_wrap_buffer_line(line->buffer, line->line->next);
+OUTPUT:
+ RETVAL
+
+void
+textbuffer_line_get_text(line, coloring)
+ Irssi::TextUI::Line line
+ int coloring
+PREINIT:
+ GString *str;
+ SV *result;
+PPCODE:
+ str = g_string_new(NULL);
+ 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)));
+
+Irssi::UI::LineInfoMeta
+textbuffer_line_get_meta(line)
+ Irssi::TextUI::Line line
+CODE:
+ RETVAL = line->line->info.meta;
+OUTPUT:
+ RETVAL
diff --git a/src/perl/textui/TextBufferView.xs b/src/perl/textui/TextBufferView.xs
new file mode 100644
index 0000000..e4cfe67
--- /dev/null
+++ b/src/perl/textui/TextBufferView.xs
@@ -0,0 +1,115 @@
+#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
+
+#*******************************
+MODULE = Irssi::TextUI::TextBufferView PACKAGE = Irssi::TextUI::TextBufferView PREFIX = textbuffer_view_
+#*******************************
+
+void
+textbuffer_view_set_default_indent(view, default_indent, longword_noindent)
+ Irssi::TextUI::TextBufferView view
+ int default_indent
+ int longword_noindent
+CODE:
+ textbuffer_view_set_default_indent(view, default_indent, longword_noindent, NULL);
+
+void
+textbuffer_view_set_hidden_level(view, level)
+ Irssi::TextUI::TextBufferView view
+ int level
+
+void
+textbuffer_view_set_scroll(view, scroll)
+ Irssi::TextUI::TextBufferView view
+ int scroll
+
+void
+textbuffer_view_clear(view)
+ Irssi::TextUI::TextBufferView 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)
+ Irssi::TextUI::TextBufferView view
+ int lines
+
+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)
+ Irssi::TextUI::TextBufferView view
+
+void
+textbuffer_view_remove_lines_by_level(view, level)
+ Irssi::TextUI::TextBufferView view
+ int level
+
+void
+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)
+ Irssi::TextUI::TextBufferView view
+ char *name
+
+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)
+ Irssi::TextUI::TextBufferView view
+
+#*******************************
+MODULE = Irssi::TextUI::TextBufferView PACKAGE = Irssi::UI::Window
+#*******************************
+
+Irssi::TextUI::TextBufferView
+view(window)
+ Irssi::UI::Window window
+CODE:
+ RETVAL = WINDOW_GUI(window)->view;
+OUTPUT:
+ RETVAL
diff --git a/src/perl/textui/TextUI.pm b/src/perl/textui/TextUI.pm
new file mode 100644
index 0000000..50f247c
--- /dev/null
+++ b/src/perl/textui/TextUI.pm
@@ -0,0 +1,26 @@
+#
+# Perl interface to irssi functions.
+#
+
+package Irssi::TextUI;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+
+$VERSION = "0.9";
+
+require Exporter;
+require DynaLoader;
+
+@ISA = qw(Exporter DynaLoader);
+@EXPORT = qw();
+@EXPORT_OK = qw();
+
+bootstrap Irssi::TextUI $VERSION if (!Irssi::Core::is_static());
+
+Irssi::TextUI::init();
+
+Irssi::EXPORT_ALL();
+
+1;
+
diff --git a/src/perl/textui/TextUI.xs b/src/perl/textui/TextUI.xs
new file mode 100644
index 0000000..0ebcc7a
--- /dev/null
+++ b/src/perl/textui/TextUI.xs
@@ -0,0 +1,318 @@
+#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);
+
+ (void) hv_store(hv, "first_line", 10, newSViv(window->first_line), 0);
+ (void) hv_store(hv, "last_line", 9, newSViv(window->last_line), 0);
+ (void) hv_store(hv, "width", 5, newSViv(window->width), 0);
+ (void) hv_store(hv, "height", 6, newSViv(window->height), 0);
+
+ (void) hv_store(hv, "statusbar_lines", 15, newSViv(window->statusbar_lines), 0);
+}
+
+static void perl_text_buffer_fill_hash(HV *hv, TEXT_BUFFER_REC *buffer)
+{
+ (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, buffer_line_bless(buffer, buffer->cur_line), 0);
+ (void) hv_store(hv, "last_eol", 8, newSViv(buffer->last_eol), 0);
+}
+
+static void perl_text_buffer_view_fill_hash(HV *hv, TEXT_BUFFER_VIEW_REC *view)
+{
+ (void) hv_store(hv, "buffer", 6, plain_bless(view->buffer, "Irssi::TextUI::TextBuffer"), 0);
+ (void) hv_store(hv, "width", 5, newSViv(view->width), 0);
+ (void) hv_store(hv, "height", 6, newSViv(view->height), 0);
+
+ (void) hv_store(hv, "default_indent", 14, newSViv(view->default_indent), 0);
+ (void) hv_store(hv, "longword_noindent", 17, newSViv(view->longword_noindent), 0);
+ (void) hv_store(hv, "scroll", 6, newSViv(view->scroll), 0);
+
+ (void) hv_store(hv, "ypos", 4, newSViv(view->ypos), 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,
+ 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, struct Buffer_Line_Wrapper *line)
+{
+ (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)
+{
+ (void) hv_store(hv, "last_access", 11, newSViv(cache->last_access), 0);
+ (void) hv_store(hv, "count", 5, newSViv(cache->count), 0);
+ /*LINE_CACHE_SUB_REC lines[1];*/
+}
+
+static void perl_line_info_fill_hash(HV *hv, LINE_INFO_REC *info)
+{
+ (void) hv_store(hv, "level", 5, newSViv(info->level), 0);
+ (void) hv_store(hv, "time", 4, newSViv(info->time), 0);
+}
+
+static void perl_statusbar_item_fill_hash(HV *hv, SBAR_ITEM_REC *item)
+{
+ (void) hv_store(hv, "min_size", 8, newSViv(item->min_size), 0);
+ (void) hv_store(hv, "max_size", 8, newSViv(item->max_size), 0);
+ (void) hv_store(hv, "xpos", 4, newSViv(item->xpos), 0);
+ (void) hv_store(hv, "size", 4, newSViv(item->size), 0);
+ if (item->bar->parent_window != NULL)
+ (void) hv_store(hv, "window", 6, plain_bless(item->bar->parent_window->active, "Irssi::UI::Window"), 0);
+}
+
+static SV *perl_line_signal_arg_conv(LINE_REC *line, TEXT_BUFFER_VIEW_REC *view, WINDOW_REC *window)
+{
+ if (view != NULL)
+ return buffer_line_bless(view->buffer, line);
+ else if (window != NULL)
+ return buffer_line_bless(WINDOW_GUI(window)->view->buffer, line);
+ else
+ return &PL_sv_undef;
+}
+
+static PLAIN_OBJECT_INIT_REC textui_plains[] = {
+ { "Irssi::TextUI::MainWindow", (PERL_OBJECT_FUNC) perl_main_window_fill_hash },
+ { "Irssi::TextUI::TextBuffer", (PERL_OBJECT_FUNC) perl_text_buffer_fill_hash },
+ { "Irssi::TextUI::TextBufferView", (PERL_OBJECT_FUNC) perl_text_buffer_view_fill_hash },
+ { "Irssi::TextUI::Line", (PERL_OBJECT_FUNC) perl_line_fill_hash },
+ { "Irssi::TextUI::LineCache", (PERL_OBJECT_FUNC) perl_line_cache_fill_hash },
+ { "Irssi::TextUI::LineInfo", (PERL_OBJECT_FUNC) perl_line_info_fill_hash },
+ { "Irssi::TextUI::StatusbarItem", (PERL_OBJECT_FUNC) perl_statusbar_item_fill_hash },
+
+ { NULL, NULL }
+};
+
+MODULE = Irssi::TextUI PACKAGE = Irssi::TextUI
+
+PROTOTYPES: ENABLE
+
+void
+init()
+CODE:
+ if (initialized) return;
+ perl_api_version_check("Irssi::TextUI");
+ initialized = TRUE;
+
+ irssi_add_plains(textui_plains);
+ irssi_add_signal_arg_conv("Irssi::TextUI::Line",
+ (PERL_BLESS_FUNC) perl_line_signal_arg_conv);
+ perl_statusbar_init();
+
+void
+deinit()
+CODE:
+ if (!initialized) return;
+ perl_statusbar_deinit();
+ initialized = FALSE;
+
+MODULE = Irssi::TextUI PACKAGE = Irssi
+
+void
+gui_printtext(xpos, ypos, str)
+ int xpos
+ int ypos
+ char *str
+
+void
+gui_input_set(str)
+ char *str
+CODE:
+ gui_entry_set_text(active_entry, str);
+
+void
+gui_input_set_extent(pos, text)
+ int pos
+ char *text
+PREINIT:
+ char *tt;
+CODE:
+ tt = text != NULL ? format_string_expand(text, NULL) : NULL;
+ gui_entry_set_extent(active_entry, pos, tt);
+ g_free(tt);
+
+void
+gui_input_set_extents(pos, len, left, right)
+ int pos
+ int len
+ char *left
+ char *right
+PREINIT:
+ char *tl;
+ char *tr;
+CODE:
+ tl = left != NULL ? format_string_expand(left, NULL) : NULL;
+ tr = right != NULL ? format_string_expand(right, NULL) : NULL;
+ gui_entry_set_extents(active_entry, pos, len, tl, tr);
+ g_free(tl);
+ g_free(tr);
+
+void
+gui_input_clear_extents(pos, len = 0)
+ int pos
+ int len
+CODE:
+ gui_entry_clear_extents(active_entry, pos, len);
+
+char *
+gui_input_get_extent(pos)
+ int pos
+CODE:
+ RETVAL = gui_entry_get_extent(active_entry, pos);
+OUTPUT:
+ RETVAL
+
+void
+gui_input_get_text_and_extents()
+PREINIT:
+ GSList *ret, *tmp;
+PPCODE:
+ ret = gui_entry_get_text_and_extents(active_entry);
+ for (tmp = ret; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(new_pv(tmp->data)));
+ }
+ g_slist_free_full(ret, g_free);
+
+void
+gui_input_set_text_and_extents(...)
+PREINIT:
+ GSList *list;
+ int i;
+PPCODE:
+ list = NULL;
+ for (i = items; i > 0; i--) {
+ list = g_slist_prepend(list, SvPV_nolen(ST(i-1)));
+ }
+ gui_entry_set_text_and_extents(active_entry, list);
+ g_slist_free(list);
+
+int
+gui_input_get_pos()
+CODE:
+ RETVAL = gui_entry_get_pos(active_entry);
+OUTPUT:
+ RETVAL
+
+void
+gui_input_set_pos(pos)
+ int pos
+CODE:
+ gui_entry_set_pos(active_entry, pos);
+
+int
+wcwidth(c)
+ char *c
+CODE:
+ if (term_type == TERM_TYPE_UTF8) {
+ unichar chr = g_utf8_get_char_validated((const char *) c, -1);
+
+ if (chr & 0x80000000) {
+ RETVAL = 1;
+ } else {
+ RETVAL = i_wcwidth(chr);
+ }
+ } else if (term_type != TERM_TYPE_BIG5 ||
+ c[1] == '\0' ||
+ !is_big5((unsigned char) c[0], (unsigned char) c[1])) {
+ RETVAL = i_wcwidth((unsigned char) *c);
+ } else {
+ RETVAL = 2;
+ }
+OUTPUT:
+ RETVAL
+
+MODULE = Irssi::TextUI PACKAGE = Irssi::UI::Window
+
+void
+print_after(window, prev, level, str, time = 0)
+ Irssi::UI::Window window
+ Irssi::TextUI::Line prev
+ int level
+ char *str
+ time_t time
+PREINIT:
+ TEXT_DEST_REC dest;
+ char *text;
+ char *text2;
+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, Line(prev), text2, time);
+ g_free(text);
+ g_free(text2);
+
+void
+gui_printtext_after(window, prev, level, str, time = 0)
+ Irssi::UI::Window window
+ Irssi::TextUI::Line prev
+ int level
+ char *str
+ time_t time
+PREINIT:
+ TEXT_DEST_REC dest;
+CODE:
+ format_create_dest(&dest, NULL, NULL, level, window);
+ gui_printtext_after_time(&dest, Line(prev), str, time);
+
+Irssi::TextUI::Line
+last_line_insert(window)
+ Irssi::UI::Window window
+CODE:
+ RETVAL = perl_wrap_buffer_line(WINDOW_GUI(window)->view->buffer,
+ WINDOW_GUI(window)->insert_after);
+OUTPUT:
+ RETVAL
+
+MODULE = Irssi::TextUI PACKAGE = Irssi::Server
+
+void
+gui_printtext_after(server, target, prev, level, str, time = 0)
+ Irssi::Server server
+ char *target
+ Irssi::TextUI::Line prev
+ int level
+ char *str
+ time_t time
+PREINIT:
+ TEXT_DEST_REC dest;
+CODE:
+ format_create_dest(&dest, server, target, level, NULL);
+ gui_printtext_after_time(&dest, Line(prev), str, time);
+
+BOOT:
+ irssi_boot(TextUI__Statusbar);
+ irssi_boot(TextUI__TextBuffer);
+ irssi_boot(TextUI__TextBufferView);
+
+MODULE = Irssi::TextUI PACKAGE = Irssi
+
+void
+term_refresh_freeze()
+
+void
+term_refresh_thaw()
diff --git a/src/perl/textui/meson.build b/src/perl/textui/meson.build
new file mode 100644
index 0000000..429e988
--- /dev/null
+++ b/src/perl/textui/meson.build
@@ -0,0 +1,37 @@
+libperl_Irssi_TextUI_a = shared_module('TextUI',
+ [ xsubpp.process(
+ files(
+ 'Statusbar.xs',
+ 'TextBufferView.xs',
+ 'TextBuffer.xs',
+ 'TextUI.xs',
+ ),
+ extra_args : [
+ '-typemap',
+ '../common/typemap',
+ '-typemap',
+ '../ui/typemap',
+ ],
+ ) ]
+ + files(
+ 'module.h',
+ ),
+ name_prefix : '',
+ name_suffix : perl_module_suffix,
+ install : true,
+ install_dir : perlmoddir / 'auto' / 'Irssi' / 'TextUI',
+ include_directories : rootinc,
+ implicit_include_directories : true,
+ dependencies : dep + [ perl_dep ],
+ link_with : dl_cross_perl_core,
+)
+
+install_headers(
+ files(
+ 'TextUI.pm',
+ ),
+ install_dir : perlmoddir / 'Irssi',
+)
+
+# 'Makefile.PL.in',
+# 'typemap',
diff --git a/src/perl/textui/module.h b/src/perl/textui/module.h
new file mode 100644
index 0000000..aba5bd7
--- /dev/null
+++ b/src/perl/textui/module.h
@@ -0,0 +1,17 @@
+#include <irssi/src/perl/ui/module.h>
+
+#include <irssi/src/fe-text/mainwindows.h>
+#include <irssi/src/fe-text/gui-windows.h>
+#include <irssi/src/fe-text/gui-printtext.h>
+#include <irssi/src/fe-text/statusbar.h>
+#include <irssi/src/fe-text/textbuffer.h>
+#include <irssi/src/fe-text/textbuffer-view.h>
+#include <irssi/src/fe-text/gui-entry.h>
+
+typedef MAIN_WINDOW_REC *Irssi__TextUI__MainWindow;
+typedef TEXT_BUFFER_REC *Irssi__TextUI__TextBuffer;
+typedef TEXT_BUFFER_VIEW_REC *Irssi__TextUI__TextBufferView;
+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
new file mode 100644
index 0000000..e597c58
--- /dev/null
+++ b/src/perl/textui/typemap
@@ -0,0 +1,24 @@
+TYPEMAP
+Irssi::TextUI::MainWindow T_PlainObj
+Irssi::TextUI::TextBuffer T_PlainObj
+Irssi::TextUI::TextBufferView T_PlainObj
+Irssi::TextUI::Line T_BufferLineWrapper
+Irssi::TextUI::LineCache T_PlainObj
+Irssi::TextUI::LineInfo T_PlainObj
+Irssi::TextUI::StatusbarItem T_PlainObj
+
+INPUT
+
+T_PlainObj
+ $var = irssi_ref_object($arg)
+
+T_BufferLineWrapper
+ $var = irssi_ref_buffer_line_wrap($arg)
+
+OUTPUT
+
+T_PlainObj
+ $arg = plain_bless($var, \"$ntype\");
+
+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 0000000..3431065
--- /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