Hi there,
I recently switched to irssi and I wanted to change some of its
behaviour wrt split windows. I discovered they are not supported in the
Perl interface at all. So I added some.
While doing that, I discovered that there is no consideration for
cyclical data structures: if they are encountered an infinite Perl data
structure is constructed and you crash on a stack overflow due to the
recursion. Similarly, if the same C structure is converted twice you get
different Perl objects. This is wasteful of time and memory. You can
also never find identical objects by comparing their references. I have
started to add some code for handling that but it is #ifdeffed out (I
need some way to detect when a perl object is destroyed so I can remove
it from my administration). For now, to break the cycle in the Window
<-> MainWindow references, I used an access function instead of a data
member.
Here is a diff.
There seems to be a breach of abstraction because a TextUI::MainWindow
(which is in fe-text) is accessed from a UI::Window, requiring an
include from a different subdirectory. But that's where the initial
parts of MainWindow were, I presume with reason.
Statusbar seemed missing too so I added some stuff for that too.
Index: src/perl/textui/typemap
===================================================================
--- src/perl/textui/typemap (revision 4172)
+++ src/perl/textui/typemap (working copy)
@@ -5,6 +5,7 @@
Irssi::TextUI::Line T_PlainObj
Irssi::TextUI::LineCache T_PlainObj
Irssi::TextUI::LineInfo T_PlainObj
+Irssi::TextUI::Statusbar T_PlainObj
Irssi::TextUI::StatusbarItem T_PlainObj
INPUT
Index: src/perl/textui/TextUI.xs
===================================================================
--- src/perl/textui/TextUI.xs (revision 4172)
+++ src/perl/textui/TextUI.xs (working copy)
@@ -8,13 +8,24 @@
static void perl_main_window_fill_hash(HV *hv, MAIN_WINDOW_REC *window)
{
hv_store(hv, "active", 6, plain_bless(window->active,
"Irssi::UI::Window"), 0);
+ /* TERM_WINDOW *screen_win; TODO
+ if (window->screen_win)
+ hv_store(hv, "screen_win", 10, plain_bless(window->screen_win,
"Irssi::UI:TerminalWindow"), 0);
+ */
+ hv_store(hv, "sticky_windows", 14, newSViv(window->sticky_windows), 0);
+ /* GSList *statusbars; via $win->statusbars() */
hv_store(hv, "first_line", 10, newSViv(window->first_line), 0);
hv_store(hv, "last_line", 9, newSViv(window->last_line), 0);
hv_store(hv, "width", 5, newSViv(window->width), 0);
hv_store(hv, "height", 6, newSViv(window->height), 0);
+ hv_store(hv, "statusbar_lines_top", 19,
newSViv(window->statusbar_lines_top), 0);
+ hv_store(hv, "statusbar_lines_bottom", 22,
newSViv(window->statusbar_lines_bottom), 0);
hv_store(hv, "statusbar_lines", 15, newSViv(window->statusbar_lines),
0);
+
+ hv_store(hv, "dirty", 5, newSViv(window->dirty), 0);
+ hv_store(hv, "size_dirty", 10, newSViv(window->size_dirty), 0);
}
static void perl_text_buffer_fill_hash(HV *hv, TEXT_BUFFER_REC *buffer)
@@ -66,6 +77,22 @@
hv_store(hv, "time", 4, newSViv(info->time), 0);
}
+static void perl_statusbar_fill_hash(HV *hv, STATUSBAR_REC *bar)
+{
+ /* TODO: STATUSBAR_GROUP_REC *group; */
+ /* TODO: STATUSBAR_CONFIG_REC *config; */
+ /* via $bar->parent_window()
+ if (bar->parent_window != NULL)
+ hv_store(hv, "parent_window", 13,
plain_bless(bar->parent_window, "Irssi::TextUI::MainWindow"), 0);
+ */
+ /* GSList *items; via $bar->items() */
+
+ hv_store(hv, "color", 5, new_pv(bar->color), 0);
+ hv_store(hv, "real_ypos", 8, newSViv(bar->real_ypos), 0);
+ hv_store(hv, "dirty", 5, newSViv(bar->dirty), 0);
+ hv_store(hv, "dirty_xpos", 10, newSViv(bar->dirty_xpos), 0);
+}
+
static void perl_statusbar_item_fill_hash(HV *hv, SBAR_ITEM_REC *item)
{
hv_store(hv, "min_size", 8, newSViv(item->min_size), 0);
@@ -74,6 +101,9 @@
hv_store(hv, "size", 4, newSViv(item->size), 0);
if (item->bar->parent_window != NULL)
hv_store(hv, "window", 6,
plain_bless(item->bar->parent_window->active, "Irssi::UI::Window"), 0);
+ /*
+ hv_store(hv, "bar", 3, plain_bless(item->bar,
"Irssi::TextUI::Statusbar"), 0);
+ */
}
static PLAIN_OBJECT_INIT_REC textui_plains[] = {
@@ -83,6 +113,7 @@
{ "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::Statusbar", (PERL_OBJECT_FUNC)
perl_statusbar_fill_hash },
{ "Irssi::TextUI::StatusbarItem", (PERL_OBJECT_FUNC)
perl_statusbar_item_fill_hash },
{ NULL, NULL }
@@ -164,3 +195,95 @@
void
term_refresh_thaw()
+
+MODULE = Irssi::TextUI::MainWindow PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+void
+mainwindows()
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(plain_bless(tmp->data,
"Irssi::TextUI::MainWindow")));
+ }
+
+
+Irssi::TextUI::MainWindow
+active_mainwin()
+CODE:
+ RETVAL = active_mainwin;
+OUTPUT:
+ RETVAL
+
+int
+window_refnum_left(refnum, wrap)
+ int refnum
+ int wrap
+
+int
+window_refnum_right(refnum, wrap)
+ int refnum
+ int wrap
+
+#*******************************
+MODULE = Irssi::TextUI::MainWindow PACKAGE = Irssi::TextUI::MainWindow
PREFIX=mainwindow_
+#*******************************
+
+Irssi::TextUI::MainWindow
+mainwindow_up(mainwin, wrap)
+ Irssi::TextUI::MainWindow mainwin
+ int wrap
+
+Irssi::TextUI::MainWindow
+mainwindow_down(mainwin, wrap)
+ Irssi::TextUI::MainWindow mainwin
+ int wrap
+
+void
+statusbars(mainwin)
+ Irssi::TextUI::MainWindow mainwin;
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = mainwin->statusbars; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(plain_bless(tmp->data,
"Irssi::TextUI::Statusbar")));
+ }
+
+#*******************************
+MODULE = Irssi::TextUI::Statusbar PACKAGE = Irssi::TextUI::Statusbar
+#*******************************
+
+void
+items(bar)
+ Irssi::TextUI::Statusbar bar;
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(plain_bless(tmp->data,
"Irssi::TextUI::StatusbarItem")));
+ }
+
+Irssi::TextUI::MainWindow
+parent_window(bar)
+ Irssi::TextUI::Statusbar bar;
+CODE:
+ RETVAL = bar->parent_window;
+OUTPUT:
+ RETVAL
+
+#*******************************
+MODULE = Irssi::TextUI::StatusbarItem PACKAGE = Irssi::TextUI::StatusbarItem
+#*******************************
+
+Irssi::TextUI::Statusbar
+bar(item)
+ Irssi::TextUI::StatusbarItem item;
+CODE:
+ RETVAL = item->bar;
+OUTPUT:
+ RETVAL
+
+#*******************************
+MODULE = Irssi::TextUI PACKAGE = Irssi::TextUI
+#*******************************
Index: src/perl/textui/module.h
===================================================================
--- src/perl/textui/module.h (revision 4172)
+++ src/perl/textui/module.h (working copy)
@@ -7,10 +7,11 @@
#include "textbuffer.h"
#include "textbuffer-view.h"
-typedef MAIN_WINDOW_REC *Irssi__TextUI__MainWindow;
+/* 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 LINE_CACHE_REC *Irssi__TextUI__LineCache;
typedef LINE_INFO_REC *Irssi__TextUI__LineInfo;
+typedef STATUSBAR_REC *Irssi__TextUI__Statusbar;
typedef SBAR_ITEM_REC *Irssi__TextUI__StatusbarItem;
Index: src/perl/perl-common.c
===================================================================
--- src/perl/perl-common.c (revision 4172)
+++ src/perl/perl-common.c (working copy)
@@ -54,6 +54,9 @@
static GHashTable *iobject_stashes, *plain_stashes;
static GSList *use_protocols;
+#if xyzzy
+static GHashTable *plain_cache;
+#endif
/* returns the package who called us */
const char *perl_get_package(void)
@@ -148,13 +151,27 @@
PERL_OBJECT_FUNC fill_func;
HV *hv;
- fill_func = g_hash_table_lookup(plain_stashes, stash);
+#if xyzzy
+ hv = g_hash_table_lookup(plain_cache, object);
+ if (hv) {
+ /* increase reference count here */
+ SvREFCNT_inc(hv);
+ return hv;
+ } else {
+#endif
+ fill_func = g_hash_table_lookup(plain_stashes, stash);
- hv = newHV();
- hv_store(hv, "_irssi", 6, create_sv_ptr(object), 0);
- if (fill_func != NULL)
- fill_func(hv, object);
- return sv_bless(newRV_noinc((SV*)hv), gv_stashpv((char *)stash, 1));
+ hv = newHV();
+#if xyzzy
+ g_hash_table_insert(plain_cache, object, hv);
+#endif
+ hv_store(hv, "_irssi", 6, create_sv_ptr(object), 0);
+ if (fill_func != NULL)
+ fill_func(hv, object);
+ return sv_bless(newRV_noinc((SV*)hv), gv_stashpv((char *)stash,
1));
+#if xyzzy
+ }
+#endif
}
int irssi_is_ref_object(SV *o)
@@ -644,6 +661,22 @@
return FALSE;
}
+static void free_iobject_cache(void *key, HV *hv)
+{
+ /* decrement refcount on hv */
+ SvREFCNT_dec(hv);
+}
+
+#if xyzzy
+static void free_plain_cache(void *key, HV *hv)
+{
+ if (hv) {
+ /* decrement refcount on hv */
+ SvREFCNT_dec(hv);
+ }
+}
+#endif
+
static void perl_unregister_protocol(CHAT_PROTOCOL_REC *rec)
{
GSList *item;
@@ -678,6 +711,10 @@
(GCompareFunc) g_direct_equal);
plain_stashes = g_hash_table_new((GHashFunc) g_str_hash,
(GCompareFunc) g_str_equal);
+#if xyzzy
+ plain_cache = g_hash_table_new((GHashFunc) g_direct_hash,
+ (GCompareFunc) g_direct_equal);
+#endif
irssi_add_plains(core_plains);
use_protocols = NULL;
@@ -697,6 +734,12 @@
g_hash_table_destroy(plain_stashes);
plain_stashes = NULL;
+#if xyzzy
+ g_hash_table_foreach(plain_cache, (GHFunc) free_plain_cache, NULL);
+ g_hash_table_destroy(plain_cache);
+ plain_cache = NULL;
+#endif
+
g_slist_foreach(use_protocols, (GFunc) g_free, NULL);
g_slist_free(use_protocols);
use_protocols = NULL;
Index: src/perl/ui/typemap
===================================================================
--- src/perl/ui/typemap (revision 4172)
+++ src/perl/ui/typemap (working copy)
@@ -1,5 +1,6 @@
TYPEMAP
Irssi::UI::Theme T_PlainObj
+Irssi::TextUI::MainWindow T_PlainObj
Irssi::UI::Window T_PlainObj
Irssi::UI::Keyinfo T_PlainObj
Irssi::UI::TextDest T_PlainObj
Index: src/perl/ui/Window.xs
===================================================================
--- src/perl/ui/Window.xs (revision 4172)
+++ src/perl/ui/Window.xs (working copy)
@@ -242,6 +242,14 @@
OUTPUT:
RETVAL
+Irssi::TextUI::MainWindow
+parent_mainwindow(window)
+ Irssi::UI::Window window
+CODE:
+ RETVAL = WINDOW_MAIN(window);
+OUTPUT:
+ RETVAL
+
#*******************************
MODULE = Irssi::UI::Window PACKAGE = Irssi::Windowitem PREFIX = window_item_
#*******************************
Index: src/perl/ui/UI.xs
===================================================================
--- src/perl/ui/UI.xs (revision 4172)
+++ src/perl/ui/UI.xs (working copy)
@@ -1,4 +1,5 @@
#include "module.h"
+#include "fe-text/gui-windows.h"
void perl_themes_init(void);
void perl_themes_deinit(void);
@@ -35,6 +36,9 @@
hv_store(hv, "active", 6, iobject_bless(window->active), 0);
if (window->active_server)
hv_store(hv, "active_server", 13,
iobject_bless(window->active_server), 0);
+ /*
+ hv_store(hv, "parent", 6, plain_bless(WINDOW_MAIN(window),
"Irssi::TextUI::MainWindow"), 0);
+ */
hv_store(hv, "servertag", 9, new_pv(window->servertag), 0);
hv_store(hv, "level", 5, newSViv(window->level), 0);
Index: src/perl/ui/module.h
===================================================================
--- src/perl/ui/module.h (revision 4172)
+++ src/perl/ui/module.h (working copy)
@@ -1,6 +1,7 @@
#include "../common/module.h"
#include "fe-windows.h"
+#include "fe-text/gui-windows.h"
#include "fe-exec.h"
#include "formats.h"
#include "printtext.h"
@@ -8,6 +9,7 @@
#include "themes.h"
#include "keyboard.h"
+typedef MAIN_WINDOW_REC *Irssi__TextUI__MainWindow;
typedef WINDOW_REC *Irssi__UI__Window;
typedef TEXT_DEST_REC *Irssi__UI__TextDest;
typedef THEME_REC *Irssi__UI__Theme;
Index: src/fe-text/mainwindows.c
===================================================================
--- src/fe-text/mainwindows.c (revision 4172)
+++ src/fe-text/mainwindows.c (working copy)
@@ -837,26 +837,54 @@
window_set_active(window);
}
+MAIN_WINDOW_REC *mainwindow_up(MAIN_WINDOW_REC *mainwin, int wrap)
+{
+ MAIN_WINDOW_REC *rec;
+
+ rec = mainwindows_find_upper(mainwin->first_line);
+ if (rec == NULL && wrap)
+ rec = mainwindows_find_upper(term_height);
+ return rec;
+}
+
/* SYNTAX: WINDOW UP */
static void cmd_window_up(void)
{
MAIN_WINDOW_REC *rec;
+#if 1
+ rec = mainwindow_up(active_mainwin, TRUE);
+#else
rec = mainwindows_find_upper(active_mainwin->first_line);
if (rec == NULL)
rec = mainwindows_find_upper(term_height);
+#endif
if (rec != NULL)
window_set_active(rec->active);
}
+MAIN_WINDOW_REC *mainwindow_down(MAIN_WINDOW_REC *mainwin, int wrap)
+{
+ MAIN_WINDOW_REC *rec;
+
+ rec = mainwindows_find_lower(mainwin->last_line);
+ if (rec == NULL && wrap)
+ rec = mainwindows_find_lower(-1);
+ return rec;
+}
+
/* SYNTAX: WINDOW DOWN */
static void cmd_window_down(void)
{
MAIN_WINDOW_REC *rec;
+#if 1
+ rec = mainwindow_down(active_mainwin, TRUE);
+#else
rec = mainwindows_find_lower(active_mainwin->last_line);
if (rec == NULL)
rec = mainwindows_find_lower(-1);
+#endif
if (rec != NULL)
window_set_active(rec->active);
}
@@ -866,7 +894,7 @@
(WINDOW_GUI(window)->sticky && \
WINDOW_MAIN(window) == (sticky_parent)))
-static int window_refnum_left(int refnum, int wrap)
+int window_refnum_left(int refnum, int wrap)
{
MAIN_WINDOW_REC *find_sticky;
WINDOW_REC *window;
@@ -888,7 +916,7 @@
return refnum;
}
-static int window_refnum_right(int refnum, int wrap)
+int window_refnum_right(int refnum, int wrap)
{
MAIN_WINDOW_REC *find_sticky;
WINDOW_REC *window;
Index: src/fe-text/mainwindows.h
===================================================================
--- src/fe-text/mainwindows.h (revision 4172)
+++ src/fe-text/mainwindows.h (working copy)
@@ -57,4 +57,9 @@
GSList *mainwindows_get_sorted(int reverse);
+MAIN_WINDOW_REC *mainwindow_up(MAIN_WINDOW_REC *mainwin, int wrap);
+MAIN_WINDOW_REC *mainwindow_down(MAIN_WINDOW_REC *mainwin, int wrap);
+int window_refnum_left(int refnum, int wrap);
+int window_refnum_right(int refnum, int wrap);
+
#endif
Index: docs/perl.txt
===================================================================
--- docs/perl.txt (revision 4172)
+++ docs/perl.txt (working copy)
@@ -149,7 +149,13 @@
know where to run the script, or at least later figure out why it
didn't work :)
+ MainWindows
+ -----------
+Where the user documentation speaks of "split windows", the corresponding
+perl object is called Irssi::TextUI::MainWindow. The MainWindow may contain
+several Windows but only one is active (shown) at any one time.
+
Functions that you can use in Irssi's Perl scripts
--------------------------------------------------
@@ -177,8 +183,10 @@
Window active_win() - return active window
Server active_server() - return server in active window
+MainWindow active_mainwindow() - return active mainwindow
windows() - return list of all windows
+mainwindows() - return list of all split windows
servers() - return list of all servers
reconnects() - return list of all server reconnections
channels() - return list of all channels
@@ -465,6 +473,52 @@
Return active item's name, or if none is active, window's name
+TextUI::MainWindow->{}
+ active - the Irssi::UI::Window that is active inside
+ sticky_windows - number of sticky windows
+ first_line, last_line - first/last line used by this window (0..x) (includes
+ statusbars)
+ width, height - width/height of the window (includes statusbars)
+ statusbar_lines_top
+ statusbar_lines_bottom
+ statusbar_lines - top+bottom
+ dirty - This window needs a redraw
+ size_dirty - We'll need to resize the window, but haven't got around
+ doing it just yet.
+
+
+UI::Window
+MainWindow::parent_mainwindow()
+ To get from a Window to the MainWindow that shows it, use this function.
+ It is not a field because that would create a circular data structure,
+ and the Perl interface can't handle that.
+
+(TextUI::Statusbar)
+MainWindow::statusbars()
+ A list of the TextUI::StatusBar objects in the TextUI::MainWindow
+
+
+TextUI::StatusbarItem->{}
+ min_size
+ max_size
+ xpos
+ size
+ window
+
+TextUI::Statusbar
+StatusbarItem::bar()
+ Get the statusbar to which the statusbaritem belongs.
+
+(TextUI::StatusbarItem)
+StatusbarItem::items()
+ Get the TextUI::StatusbarItems in the Statusbar.
+
+TextUI::MainWindow
+Statusbar::parent_window()
+ Get the MainWindow that shows the Statusbar.
+
+
+
*** Server Connects
Connect->{}
-Olaf.
--
___ Olaf 'Rhialto' Seibert -- You author it, and I'll reader it.
\X/ rhialto/at/xs4all.nl -- Cetero censeo "authored" delendum esse.