[Spiderape-cvs] SF.net SVN: spiderape: [42] plugins/ncurses
Status: Beta
Brought to you by:
sgbeal
|
From: <sg...@us...> - 2007-09-28 03:44:51
|
Revision: 42
http://spiderape.svn.sourceforge.net/spiderape/?rev=42&view=rev
Author: sgbeal
Date: 2007-09-27 20:44:42 -0700 (Thu, 27 Sep 2007)
Log Message:
-----------
mostly works but has seriously broken endwin cleanup routines which need fixing
Modified Paths:
--------------
plugins/ncurses/Makefile
plugins/ncurses/NCursesPanel.cpp
plugins/ncurses/NCursesPanel.js
plugins/ncurses/NCursesWindow.cpp
plugins/ncurses/NCursesWindow.hpp
plugins/ncurses/binder.cpp
plugins/ncurses/binder.hpp
plugins/ncurses/ncwrapper.cpp
plugins/ncurses/ncwrapper.hpp
plugins/ncurses/panel.cpp
plugins/ncurses/plugin.make
plugins/ncurses/scripts/JCWindow.inc.js
plugins/ncurses/scripts/ncpad.js
plugins/ncurses/scripts/ncpanel.js
plugins/ncurses/scripts/ncurses.js
plugins/ncurses/scripts/ncws.inc.js
plugins/ncurses/scripts/ncws.js
plugins/ncurses/scripts/ripoffline.js
Modified: plugins/ncurses/Makefile
===================================================================
--- plugins/ncurses/Makefile 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/Makefile 2007-09-28 03:44:42 UTC (rev 42)
@@ -26,7 +26,9 @@
# APE.PLUGIN.TESTSCRIPT =
APE.PLUGIN.DIST_FILES = \
ChangeLog README \
- $(wildcard *.cpp *.hpp *.js) \
+ $(APE.PLUGIN.SOURCES) \
+ $(APE.PLUGIN.HEADERS) \
+ $(wildcard *.js) \
$(wildcard scripts/*.js)
CLEAN_FILES += $(wildcard *~ scripts/*~)
Modified: plugins/ncurses/NCursesPanel.cpp
===================================================================
--- plugins/ncurses/NCursesPanel.cpp 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/NCursesPanel.cpp 2007-09-28 03:44:42 UTC (rev 42)
@@ -9,6 +9,8 @@
#define JS_NATIVE_MEMBER(CL,FN) JSBool CL::FN( JSContext * cx, JSObject * obj, uint32 argc, jsval * argv, jsval * rval )
#define NCP_JS_NATIVE_MEMBER(FN) JS_NATIVE_MEMBER(NCursesPanel,FN)
+#define ENABLE_STATIC_INIT 0
+#if ENABLE_STATIC_INIT
namespace {
/**
This function will be called during static initialization phase
@@ -32,6 +34,7 @@
static bool inited_at_dlopen_time = ( spiderape_dll_init(),true );
}
+#endif // ENABLE_STATIC_INIT
namespace ape {
namespace nc {
@@ -67,7 +70,7 @@
static bool inited = false;
if( inited ) return;
inited = true;
- typedef ::ape::Class<NCursesPanel::strings::class_name,NCursesPanel> CT;
+ typedef NCursesPanel::ClassType CT;
CT::impl & ci = CT().Implement();
ci.Member<NCursesPanel::strings::bogo>( &NCursesPanel::bogo );
@@ -83,7 +86,7 @@
JSBool NCursesPanel::init_context( JSContext * cx, JSObject * obj )
{
NCursesPanel::init_js_class();
- typedef ::ape::Class<NCursesPanel::strings::class_name,NCursesPanel> CTP;
+ typedef NCursesPanel::ClassType CTP;
CTP::impl & cp = CTP().Implement();
cp.init_context(cx,obj);
typedef NCursesWindow::ClassType CTW;
Modified: plugins/ncurses/NCursesPanel.js
===================================================================
--- plugins/ncurses/NCursesPanel.js 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/NCursesPanel.js 2007-09-28 03:44:42 UTC (rev 42)
@@ -4,7 +4,10 @@
var root = new NCursesWindow(nc_new_panel(nc_newwin(0,0,0,0)));
root.background( ascii('~') | nc_color('black','yellow'));
nc_curs_set(0);
+nc_capture_cout(root.ncwindow());
var rootgeom = nc_wgeometry(root.ncwindow());
+root.moveCursor( rootgeom.h / 3 * 2, 0 );
+root.scrollOk();
var wins = [];
var pos = 'blue';
@@ -23,7 +26,6 @@
curpnl.background( nc_color('white',pos) );
curpnl.addString( "geom=="+curpnl.geometry().toSource() );
curpnl.refresh();
-nc_capture_cout(curpnl.ncwindow());
curpnl.moveCursor(3,0);
print("This is stdout.");
@@ -42,25 +44,26 @@
curpnl.addString( "geom=="+curpnl.geometry().toSource() );
curpnl.sub = new NCursesWindow(curpnl);
curpnl.sub.background( nc_color('black','white') );
-curpnl.sub.addString("Subwindow of panel '"+pos+"'.\n");
+curpnl.sub.print("Subwindow of panel '"+pos+"'.");
+//curpnl.sub.refresh();
-function ref() { nc_update_panels(); nc_doupdate(); }
-curpnl.refresh(); curpnl.getch();
-curpnl.sub.addString("bottom =="+wins['red'].bottom() );
-curpnl.refresh(); curpnl.getch();
-curpnl.sub.addString("top =="+wins['cyan'].top() );
-curpnl.refresh(); curpnl.getch();
+function ref() { nc_update_panels(); nc_doupdate(); root.getch(); }
+ref()
+print("bottom =="+wins['red'].bottom() );
+ref()
+print("top =="+wins['cyan'].top() );
+ref();
curpnl = wins['red'];
curpnl.top();
-curpnl.refresh();curpnl.getch();
+ref();
wins['green'].top();
-curpnl.refresh();curpnl.getch();
-print("move =="+wins['cyan'].moveWindow(4,4) );
-curpnl.refresh(); curpnl.getch();
+ref();
+print("move =="+wins['green'].moveWindow(4,4) );
+ref();
+print("move =="+wins['green'].moveWindow(6,16) );
-
curpnl = wins['cyan'];
//curpnl.moveWindow( rootgeom.h/3, 1 );
//curpnl.hide();
@@ -72,10 +75,8 @@
// nc_doupdate();
var attr = ncurses.A_BLINK | ncurses.A_UNDERLINE | ncurses.A_STANDOUT;
-var win = wins['red'];
-win.moveCursor(0,0);
-win.attrOn(attr);
+root.attrOn(attr);
print( "Tap any key to quit." );
-win.attrOff( attr );
+root.attrOff( attr );
root.getch();
nc_endwin();
Modified: plugins/ncurses/NCursesWindow.cpp
===================================================================
--- plugins/ncurses/NCursesWindow.cpp 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/NCursesWindow.cpp 2007-09-28 03:44:42 UTC (rev 42)
@@ -7,7 +7,6 @@
#define JS_NATIVE_MEMBER(CL,FN) JSBool CL::FN( JSContext * cx, JSObject * obj, uint32 argc, jsval * argv, jsval * rval )
#define NCW_JS_NATIVE_MEMBER(FN) JS_NATIVE_MEMBER(NCursesWindow,FN)
-#define NCP_JS_NATIVE_MEMBER(FN) JS_NATIVE_MEMBER(NCursesPanel,FN)
namespace {
/**
@@ -36,10 +35,6 @@
namespace ape {
namespace nc {
-
-
-
-
void NCursesWindow::shared_init( JSContext * cx )
{
if( stdscr ) return;
@@ -71,28 +66,26 @@
this->m_ncwinjv = WINDOW_to_jsval( cx, stdscr );
}
else if( 1 == argc )
- { // ctor(NCursesWindow) = parent window which we will wrap ourselves in
+ {
if( PANEL * p = JWBinder::get_panel(cx, argv[0] ) )
- {
+ { // ctor(PANEL)
this->m_ncwin = panel_window(p);
this->m_ncwinjv = WINDOW_to_jsval( cx, this->m_ncwin );
this->m_ncpanel = p;
-#if 0
- this->add_function( "bottom", "function(){return nc_bottom_panel(this.ncpanel());}");
- this->add_function( "hide", "function(){return nc_hide_panel(this.ncpanel());}");
- this->add_function( "moveWindow", "function(y,x) { return nc_move_panel( this.ncpanel(),y,x); }");
- this->add_function( "refresh", "function() { return nc_wrefresh(this.ncpanel()); }");
- this->add_function( "show", "function(){return nc_show_panel(this.ncpanel());}");
- this->add_function( "top", "function(){return nc_top_panel(this.ncpanel());}");
-#endif
}
+ else if( WINDOW * ncw = jsval_to_WINDOW(cx,argv[0]) )
+ { // ctor(WINDOW)
+ this->m_ncwinjv = argv[0];
+ this->m_ncwin = ncw;
+ }
else if( NCursesWindow * par = ape::jsval_to<NCursesWindow>( cx, argv[0] ) )
- { // ctor(NCursesWindow)
+ { // ctor(NCursesWindow) = parent window which we will wrap ourselves in
int w = par->width()-2;
int h = par->height()-2;
if( (w<=0) || (h<=0) )
{
- throw ape::exception( cx, "NCursesWindow 1-arg ctor: NCursesWindow parent is too small to contain a child.");
+ throw ape::exception( cx, "%s 1-arg ctor: NCursesWindow parent is too small to contain a child.",
+ NCursesWindow::strings::class_name);
}
jsval av[] = { par->window_handle_jsval(),
int_to_jsval(h), // lines
@@ -105,19 +98,17 @@
this->m_ncwin = jsval_to_WINDOW( cx, this->m_ncwinjv );
if( ! this->m_ncwin )
{
- throw new ape::exception( cx, "NCursesWindow 1-arg ctor: nc_derwin(NCursesWindow,%d,%d,%d,%d) failed!",
+ throw new ape::exception( cx, "%s 1-arg ctor: nc_derwin(NCursesWindow,%d,%d,%d,%d) failed!",
+ NCursesWindow::strings::class_name,
h,w,1,1);
}
this->set_parent( par );
}
- else if( WINDOW * ncw = jsval_to_WINDOW(cx,argv[0]) )
- { // ctor(WINDOW)
- this->m_ncwinjv = argv[0];
- this->m_ncwin = ncw;
- }
else
{
- throw new ape::exception( cx, "NCursesWindow 1-arg ctor: requires a WINDOW or NCursesWindow argument!" );
+ throw new ape::exception( cx, "%s 1-arg ctor: requires a PANEL or WINDOW or %s argument!",
+ NCursesWindow::strings::class_name,
+ NCursesWindow::strings::class_name );
}
}
else if( 4 == argc )
@@ -131,7 +122,8 @@
this->m_ncwin = jsval_to_WINDOW( cx, this->m_ncwinjv );
if( ! this->m_ncwin )
{
- throw new ape::exception( cx, "NCursesWindow 4-arg ctor: nc_newwin() failed!" );
+ throw new ape::exception( cx, "%s 4-arg ctor: nc_newwin() failed!",
+ NCursesWindow::strings::class_name);
}
}
else if( 5 == argc )
@@ -139,7 +131,9 @@
NCursesWindow * par = ape::jsval_to<NCursesWindow>( cx, argv[0] );
if( ! par )
{
- throw ape::exception( cx, "NCursesWindow 5-arg ctor requires (NCursesWindow,int,int,int,int) arguments.");
+ throw ape::exception( cx, "%s 5-arg ctor requires (%s,int,int,int,int) arguments.",
+ NCursesWindow::strings::class_name,
+ NCursesWindow::strings::class_name);
}
jsval av[] = { par->m_ncwinjv,
argv[1], argv[2],
@@ -147,37 +141,43 @@
nc_derwin( cx, JS_GetGlobalObject(cx), 5, av, &this->m_ncwinjv );
if( JSVAL_NULL == this->m_ncwinjv )
{
- throw new ape::exception( cx, "NCursesWindow 5-arg ctor: nc_derwin() failed!" );
+ throw new ape::exception( cx, "%s 5-arg ctor: nc_derwin() failed!",
+ NCursesWindow::strings::class_name);
}
this->m_ncwin = ape::jsval_to<WINDOW>( cx, this->m_ncwinjv );
this->set_parent( par );
}
else
{
- throw ape::exception( cx, "NCursesWindow ctor: did not get valid arguments." );
+ throw ape::exception( cx, "%s ctor: did not get valid arguments.",
+ NCursesWindow::strings::class_name);
}
if( ! this->m_ncwin )
{
- throw ape::exception( cx, "NCursesWindow ctor: did not get a WINDOW handle." );
+ throw ape::exception( cx, "%s ctor: this object has no valid WINDOW handle.",
+ NCursesWindow::strings::class_name );
}
- /**
- Note that Class<>'s ctor will bind this object to
- obj, but we cover the case of natively-created
- NCursesWindow by doing the binding ourselves here, and
- undoing it in the dtor.
- */
- ::ape::bind::bind_native<NCursesWindow>( this->js_context(),
+ ape::bind::bind_native<NCursesWindow>( this->js_context(),
this->js_value(),
this );
-// ::ape::bind::bind_native<WINDOW>( this->js_context(),
-// this->js_value(),
-// this->m_ncwin );
}
NCursesWindow::~NCursesWindow()
{
+ // We MUST unbind ourselves or the JS GC will end up causing a double-delete of this object:
+ ape::bind::unbind_native<NCursesWindow>( this->js_context(),
+ this->js_value(),
+ this );
+ if( ! stdscr )
+ {
+ return;
+ /**
+ This is to try to avoid a post-main() crash when GC finalizes
+ these objects.
+ */
+ }
if( this->m_par )
{
this->m_par->m_ch.remove( this );
@@ -201,14 +201,6 @@
}
catch(...) { /* ignore it! */ }
}
-
- /** See the notes in the ctor. */
- ::ape::bind::unbind_native<NCursesWindow>( this->js_context(),
- this->js_value(),
- this );
-// ::ape::bind::unbind_native<WINDOW>( this->js_context(),
-// this->js_value(),
-// this->m_ncwin );
}
void NCursesWindow::set_panel( PANEL * p )
@@ -335,7 +327,8 @@
av[4] = argv[3];
return nc_mvwaddnstr( cx, JS_GetGlobalObject(cx), 5, av, rval );
}
- return ape::set_pending_exception( cx, "NCursesWindow::%s() expects (string) or (y,x,string) arguments.",
+ return ape::set_pending_exception( cx, "%s::%s() expects (string) or (y,x,string) arguments.",
+ NCursesWindow::strings::class_name,
NCursesWindow::strings::wrap_addstr );
}
@@ -356,7 +349,8 @@
av[3] = argv[2];
return nc_mvwaddstr( cx, JS_GetGlobalObject(cx), 4, av, rval );
}
- return ape::set_pending_exception( cx, "NCursesWindow::%s() expects (int) or (y,x,int) arguments.",
+ return ape::set_pending_exception( cx, "%s::%s() expects (int) or (y,x,int) arguments.",
+ NCursesWindow::strings::class_name,
NCursesWindow::strings::wrap_addch );
}
@@ -399,7 +393,8 @@
return nc_mvwgetnstr(cx,glob,4,av,rval);
}
return ape::set_pending_exception( cx,
- "NCursesWindow::%s(): expects arguments matching one of: (), (N), (Y,X), or (Y,X,N)",
+ "%s::%s(): expects arguments matching one of: (), (N), (Y,X), or (Y,X,N)",
+ NCursesWindow::strings::class_name,
NCursesWindow::strings::wrap_getstring );
}
@@ -424,7 +419,8 @@
return nc_mvwhline(cx,glob,5,av,rval);
}
return ape::set_pending_exception( cx,
- "NCursesWindow::%s(): expects arguments matching one of: (int,N) (Y,X,int,N)",
+ "%s::%s(): expects arguments matching one of: (int,N) (Y,X,int,N)",
+ NCursesWindow::strings::class_name,
NCursesWindow::strings::wrap_hline );
}
@@ -448,7 +444,8 @@
return nc_mvwvline(cx,glob,5,av,rval);
}
return ape::set_pending_exception( cx,
- "NCursesWindow::%s(): expects arguments matching one of: (int,N) (Y,X,int,N)",
+ "%s::%s(): expects arguments matching one of: (int,N) (Y,X,int,N)",
+ NCursesWindow::strings::class_name,
NCursesWindow::strings::wrap_vline );
}
@@ -506,7 +503,6 @@
ci.Member<NCursesWindow::strings::wrap_getstring>( &NCursesWindow::wrap_getstring );
ci.Member<NCursesWindow::strings::wrap_hline>( &NCursesWindow::wrap_hline );
ci.Member<NCursesWindow::strings::wrap_vline>( &NCursesWindow::wrap_vline );
-
////////////////////////////////////////////////////
// If you want to automatically have a global instance
@@ -524,73 +520,7 @@
ci.Define();
}
- NCursesPanel::NCursesPanel( JSContext * cx, JSObject * obj, uint32 argc, jsval * argv, jsval * rval )
- : NCursesWindow( cx, obj, argc, argv, rval )
- {
- jsval pv = JSVAL_NULL;
- jsval av[1] = { this->window_handle_jsval() };
- nc_new_panel( cx, JS_GetGlobalObject(cx), 1, av, &pv );
- PANEL * p = jsval_to<PANEL>( cx, pv );
- if( ! p )
- {
- throw ape::exception( cx, "NCursesPanel::ctor couldn't get PANEL handle." );
- }
- this->set_panel( p );
- //ape::bind::bind_native<PANEL>( cx, pv, p );
-// this->add_function("tryit",
-// "function(){nc_hide_panel(");
- }
- NCursesPanel::~NCursesPanel()
- {
-
- }
-
- char const * NCursesPanel::strings::class_name = "NCursesPanel";
- char const * NCursesPanel::strings::bogo = "bogo";
-
- void NCursesPanel::init_js_class()
- {
- static bool inited = false;
- if( inited ) return;
- inited = true;
- typedef ::ape::Class<NCursesPanel::strings::class_name,NCursesPanel> CT;
- CT::impl & ci = CT().Implement();
-
- ci.Member<NCursesPanel::strings::bogo>( &NCursesPanel::bogo );
-
- ci.Define();
- }
-
- NCP_JS_NATIVE_MEMBER(bogo)
- {
- return JS_TRUE;
- }
-
- JSBool NCursesPanel::init_context( JSContext * cx, JSObject * obj )
- {
- NCursesPanel::init_js_class();
- typedef ::ape::Class<NCursesPanel::strings::class_name,NCursesPanel> CTP;
- CTP::impl & cp = CTP().Implement();
- cp.init_context(cx,obj);
- typedef NCursesWindow::ClassType CTW;
- CTW::impl & cw = CTW().Implement();
- JSBool ret = JS_SetPrototype( cx, cp.get_prototype(cx), cw.get_prototype(cx) );
- ape::scriptable proto( cx, cp.get_prototype(cx) );
- if( !(
- ret
- && proto.add_function( "bottom", "function(){return nc_bottom_panel(this.ncpanel());}")
- && proto.add_function( "hide", "function(){return nc_hide_panel(this.ncpanel());}")
- && proto.add_function( "moveWindow", "function(y,x) { return nc_move_panel( this.ncpanel(),y,x); }")
- && proto.add_function( "refresh", "function() { return nc_wrefresh(this.ncpanel()); }")
- && proto.add_function( "show", "function(){return nc_show_panel(this.ncpanel());}")
- && proto.add_function( "top", "function(){return nc_top_panel(this.ncpanel());}")
- )) {
- throw new ape::exception( cx, "NCursesPanel::init_context(): add_function() failed while setting up prototype functions." );
- }
- return ret;
- }
-
/**
Initialize NCursesWindow for the given context.
*/
@@ -609,10 +539,10 @@
// Add NCursesWindow to the context:
if( ! ci.init_context( cx, obj ) )
{
- throw ape::exception( cx, "NCursesWindow::init_context(): ClassType::impl::init_context() failed!" );
+ throw ape::exception( cx, "%s::init_context(): ClassType::impl::init_context() failed!",
+ NCursesWindow::strings::class_name );
}
//CERR << "NCursesWindow prototype == "<<std::hex<<ci.get_prototype(cx)<<'\n';
- ape::scriptable proto( cx, ci.get_prototype(cx) );
typedef std::map<std::string,std::string> StringMap;
StringMap funcmap;
@@ -634,7 +564,11 @@
funcmap["noutRefresh"] = "function() { return nc_wnoutrefresh(this.ncwindow()); }";
funcmap["overlay"] = "function(tgt) { return nc_overlay(this.ncwindow(),(tgt instanceof NCursesWindow) ? tgt.ncwindow() : tgt); }";
funcmap["overwrite"] = "function(tgt) { return nc_overwrite(this.ncwindow(),(tgt instanceof NCursesWindow) ? tgt.ncwindow() : tgt); }";
- // WTF? Causes an ape::exceptiion: && proto.add_function( "print", "function(str) { return this.addString(str+'\n'); }")
+ // WTF? Causes an ape::exception: && proto.add_function( "print", "function(str) { return this.addString(str+'\n'); }")
+ // WTF? funcmap["print"] = "function(str) { nc_wprint(this.ncwindow(),str); }";
+ // WTF? but THIS compiles: funcmap["print"] = "function(str) { }";
+ // WTF? And THIS works:
+ funcmap["print"] = "function() { var a=[]; a[0]=this.ncwindow(); for(var x=0;x<arguments.length;++x){a[1+x]=arguments[x]}; nc_wprint.apply(this,a);}";
funcmap["refresh"] = "function() { return nc_wrefresh(this.isPanel() ? this.ncpanel() : this.ncwindow()); }";
funcmap["scrollOk"] = "function(b) { return nc_scrollok(this.ncwindow(),(undefined===b)?true:b); }";
funcmap["touch"] = "function() { return nc_touchwin(this.ncwindow()); }";
@@ -643,22 +577,24 @@
// funcmap["redraw"] = "function() { return nc_wredrawwin(this.ncwindow()); }";
// funcmap["redrawLine"] = "function(start,count) { return nc_wredrawln(this.ncwindow(),start,count); }";
-
// PANEL-only functions:
- funcmap["bottom"] = "function() { return this.ncpanel() ? nc_bottom_panel(this.ncpanel()) : ncurses.ERR; }";
+ funcmap["bottom"] = "function() {return this.isPanel() ? nc_bottom_panel(this.ncpanel()) : ncurses.ERR;}";
funcmap["top"] = "function(){return this.isPanel() ? nc_top_panel(this.ncpanel()) : ncurses.ERR;}";
funcmap["show"] = "function(){return this.isPanel() ? nc_show_panel(this.ncpanel()) : ncurses.ERR;}";
funcmap["hide"] = "function(){return this.isPanel() ? nc_hide_panel(this.ncpanel()) : ncurses.ERR;}";
+ ape::scriptable proto( cx, ci.get_prototype(cx) );
for( StringMap::iterator it = funcmap.begin(); funcmap.end() != it; ++it )
{
if( ! proto.add_function( (*it).first, (*it).second ) )
{
- JS_ReportWarning( cx, "NCursesWindow: error adding prototype function '%s'.",
+ JS_ReportWarning( cx, "%s: error adding prototype function '%s'.",
+ NCursesWindow::strings::class_name,
(*it).first.c_str() );
}
}
- return NCursesPanel::init_context(cx,obj);
+ //return NCursesPanel::init_context(cx,obj);
+ return JS_TRUE;
}
@@ -666,5 +602,4 @@
} // namespace ape
#undef NCW_JS_NATIVE_MEMBER
-#undef NCP_JS_NATIVE_MEMBER
#undef JS_NATIVE_MEMBER
Modified: plugins/ncurses/NCursesWindow.hpp
===================================================================
--- plugins/ncurses/NCursesWindow.hpp 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/NCursesWindow.hpp 2007-09-28 03:44:42 UTC (rev 42)
@@ -18,8 +18,11 @@
NCursesWindow provides a JS-bound OO interface for
ncurses-based windows. Its is designed for use with the
ape::Class mechanism (thus its odd implementation). This
- class should not be used from C++ code - it may not behave
- as expected (then again, it might).
+ class should not be instantiated from C++ code - it will
+ not behave as expected. If you MUST instantiate it from
+ C++, then use
+ NCursesWindow::ClassType().Implement().create_object(...)
+ so that it gets correctly registered with the VM.
Reminder: some functions have odd names
(e.g. wrap_addstr()) to avoid naming conflicts with ncurses
@@ -211,6 +214,11 @@
static char const * bogo;
};
+ /**
+ Convience typedef for use with the Class<>-related code.
+ */
+ typedef ::ape::Class<NCursesPanel::strings::class_name,NCursesPanel> ClassType;
+
private:
NCursesPanel & operator=(NCursesPanel const &); // not implemented
NCursesPanel(NCursesPanel const &); // not implemented
Modified: plugins/ncurses/binder.cpp
===================================================================
--- plugins/ncurses/binder.cpp 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/binder.cpp 2007-09-28 03:44:42 UTC (rev 42)
@@ -3,6 +3,7 @@
#include <sf.net/ape/spiderape.hpp>
#include <sf.net/ape/binder.hpp> // a DIFFERENT binder.hpp, actually
#include <sf.net/ape/debuggering_macros.hpp> // CERR
+#include "NCursesWindow.hpp"
namespace ape {
namespace nc {
@@ -15,15 +16,6 @@
}
} // namespace Private
-
- int JWBinder::m_counter = 1000;
- // ^^^ we start with a "large" number because if we don't then
- // it is possible that integer arguments passed (incorrectly)
- // as WINDOW handles will be interpreted as a WINDOW (probably
- // a different one than intended). Yes, this did happen to
- // me. We choose an arbitrary integer which is expected to be
- // larger than screen coordinates.
-
void JWBinder::link_child( JWBinder * ch )
{
if( ! ch ) return;
@@ -32,7 +24,7 @@
void JWBinder::unlink_child( JWBinder * ch )
{
- this->m_ch.erase(std::find(this->m_ch.begin(),this->m_ch.end(),ch));
+ this->m_ch.remove(ch); //erase(std::find(this->m_ch.begin(),this->m_ch.end(),ch));
}
void JWBinder::init()
@@ -41,56 +33,41 @@
{
throw ::ape::exception( this->m_cx, "JWBinder(JSContext*[0x%x],WINDOW*[0x%x]) requires non-null pointers as arguments.", this->m_cx, this->m_win );
}
- // Avoid the possibility that our m_counter collides
- // with the global object's jsval, which is bound to stdscr:
- JWBinder * check = ::ape::bind::get_native<JWBinder>( this->m_cx, this->m_v );
- while( check )
- {
- this->m_v = int_to_jsval(++m_counter);
- check = ::ape::bind::get_native<JWBinder>( this->m_cx, this->m_v );
- }
+ this->m_v = ape::js_simple_object(this->m_cx).js_value();
keypad( this->m_win,true );
meta( this->m_win, true );
-// this->windowmap()[this->m_win] = this;
::ape::bind::bind_native<JWBinder>( this->m_cx, this->m_v, this );
::ape::bind::bind_native<WINDOW>( this->m_cx, this->m_v, this->m_win );
if( this->m_pnl )
{
::ape::bind::bind_native<PANEL>( this->m_cx, this->m_v, this->m_pnl );
}
+ //JWBinder::all_binders().push_back(this);
}
JWBinder::JWBinder(JSContext *cx, PANEL *p, jsval jv ) :
- m_cx(cx), m_win(panel_window(p)), m_pnl(p), m_v(jv ? jv : int_to_jsval(++m_counter)),
+ m_cx(cx), m_win(panel_window(p)), m_pnl(p), m_v(jv),
m_f(0), m_parent(0), m_ch()
{
this->init();
}
JWBinder::JWBinder(JSContext *cx, WINDOW * w, jsval jv ) :
- m_cx(cx), m_win(w), m_pnl(0), m_v(jv ? jv : int_to_jsval(++m_counter)),
+ m_cx(cx), m_win(w), m_pnl(0), m_v(jv),
m_f(0), m_parent(0), m_ch()
{
this->init();
}
-// JWBinder * JWBinder::binder_for( WINDOW * w )
+ jsval JWBinder::js_value() const { return this->m_v; }
+
+// unsigned long JWBinder::flags() const { return this->m_f; }
+// unsigned long JWBinder::flags( unsigned long f )
// {
-// WinMap::iterator it = windowmap().find(w);
-// return (windowmap().end() == it)
-// ? 0
-// : (*it).second;
+// unsigned long ret = f;
+// this->m_f = f;
+// return ret;
// }
- jsval JWBinder::js_value() const { return this->m_v; }
-
- unsigned long JWBinder::flags() const { return this->m_f; }
- unsigned long JWBinder::flags( unsigned long f )
- {
- unsigned long ret = f;
- this->m_f = f;
- return ret;
- }
-
JSContext * JWBinder::js_context() { return this->m_cx; }
WINDOW * JWBinder::window() { return this->m_win; }
@@ -128,69 +105,130 @@
JWBinder::~JWBinder()
{
- if(0) CERR << "Deleting WINDOW " << std::hex << this->window()
- << ", JSObject " << std::hex << jsval_to_cstring( this->js_context(), this->js_value() )
- << '\n';
+ //JWBinder::all_binders().remove(this);
+ this->parent( 0 );
+ ::ape::bind::unbind_native<JWBinder>( this->m_cx, this->m_v, this );
+ ::ape::bind::unbind_native<WINDOW>( this->m_cx, this->m_v, this->m_win );
+ if( 0 )
+ {
+ void * pt = this->m_pnl ? (void*)this->m_pnl : (void*)this->m_win;
+ CERR << "Deleting "<<
+ (this->m_pnl ? "PANEL " : "WINDOW ") << std::hex << pt
+ << " with"<<(this->m_parent?"out":" ")<<" parent"
+ << ", JSObject " << std::hex << jsval_to_cstring( this->js_context(), this->js_value() )
+ << '\n';
+ }
- // Kludge: remove stream-to-window redirects:
- using namespace Private;
- WindowStreamMap & str = captured_streams();
- typedef WindowStreamMap::iterator WIT;
- WIT stit = str.lower_bound(this->m_win);
- WIT head = stit;
- WIT stet = str.upper_bound(this->m_win);
- for( ; stet != stit; ++stit )
{
- delete (*stit).second;
- //str.erase(stit);
+ // Kludge: remove stream-to-window redirects:
+ using namespace Private;
+ WindowStreamMap & str = captured_streams();
+ typedef WindowStreamMap::iterator WIT;
+ WIT stit = str.lower_bound(this->m_win);
+ WIT head = stit;
+ WIT stet = str.upper_bound(this->m_win);
+ for( ; stet != stit; ++stit )
+ {
+ delete (*stit).second;
+ //str.erase(stit);
+ }
+ str.erase( head, stet );
+ // /KLUDGE
}
- str.erase( head, stet );
- // /KLUDGE
- // KLUDGE #2: remove data bound via nc_set_userdata()
- typedef ::ape::jsval_t JT;
- JT * j = ::ape::bind::get_native<JT>( this->js_context(), this->js_value() );
- if( j )
{
- ::ape::bind::unbind_native<JT>( this->js_context(), this->js_value(), j );
- delete j;
- j = 0;
+ // KLUDGE #2: remove data bound via nc_set_userdata()
+ typedef ::ape::jsval_t JT;
+ JT * j = ::ape::bind::get_native<JT>( this->js_context(), this->js_value() );
+ if( j )
+ {
+ ::ape::bind::unbind_native<JT>( this->js_context(), this->js_value(), j );
+ delete j;
+ j = 0;
+ }
+ // /KLUDGE #2
}
- // /KLUDGE #2
-
- this->parent( 0 );
BinderList lcp(this->m_ch); // need a copy to avoid modifying original while we're deleting.
BinderList::iterator it = lcp.begin();
- BinderList::iterator et = lcp.end();
- for( ; et != it; ++it )
+ for( ; lcp.end() != it; ++it )
{
- if(0) CERR << "Deleting child WINDOW " << std::hex << (*it)->window()
+ if(1) CERR << "Deleting child WINDOW " << std::hex << (*it)->window()
<< ", JSObject " << std::hex << jsval_to_cstring( this->js_context(), (*it)->js_value() )
<< '\n';
delete *it;
}
- ::ape::bind::unbind_native<JWBinder>( this->m_cx, this->m_v, this );
+ if( stdscr && this->m_win )
+ {
+ if( this->m_win != stdscr )
+ {
+ werase(this->m_win);
+ delwin( this->m_win );
+ }
+ }
this->free_panel();
- ::ape::bind::unbind_native<WINDOW>( this->m_cx, this->m_v, this->m_win );
- if( this->m_win )
+ }
+
+ void JWBinder::endwin_cleanup()
+ {
+ CERR << "JWBinder::endwin_cleanup()...\n";
+
{
- if( this->m_win == stdscr )
+ // Kludge: remove stream-to-window redirects:
+ using namespace Private;
+ WindowStreamMap str( captured_streams() );
+ captured_streams().clear();
+ typedef WindowStreamMap::iterator WIT;
+ WIT stit = str.begin();
+ WIT head = stit;
+ for( ; str.end() != stit; ++stit )
{
- endwin();
- stdscr = 0;
+ delete (*stit).second;
+ //str.erase(stit);
}
- else
+ // /KLUDGE
+ }
+#if 0
+ /**
+ We walk the list of all binders and make a deletion
+ queue for items WITHOUT parents (those with parents
+ will be deleted by their parents). We use
+ reverse_iterators because stdscr will be the first
+ binder and we need it to be alive the whole time to
+ avoid a segfault later on.
+ */
+ BinderList them;
+ BinderList & bl = JWBinder::all_binders();
+ BinderList::reverse_iterator rit = bl.rbegin();
+ JWBinder * cur = 0;
+ for( ; bl.rend() != rit; ++rit )
+ {
+ cur = *rit;
+ if( cur && (!cur->parent()) )
{
- werase(this->m_win);
- delwin( this->m_win );
+ them.push_back(cur);
+ // We only erase non-parented items
+ // because items with parents will be
+ // deleted by the parent.
}
}
+ BinderList::iterator it = them.begin();
+ for( ; them.end() != it; ++it )
+ {
+ delete *it;
+ }
+#endif
}
+ JWBinder::BinderList & JWBinder::all_binders()
+ {
+ static BinderList bob;
+ return bob;
+ }
+
int JWBinder::free_panel()
{
- if( ! this->m_pnl ) return ERR;
+ if( !stdscr || !this->m_pnl ) return ERR;
::ape::bind::unbind_native<PANEL>( this->m_cx, this->m_v, this->m_pnl );
int ret = del_panel( this->m_pnl );
this->m_pnl = 0;
@@ -207,8 +245,8 @@
JWBinder * b = get_binder(cx,jv);
if( ! b )
{
- throw ::ape::exception( cx, "JWBinder::assert_binder(0x%x,jsval) failed. msg=[%s]",
- cx, (msg ? msg : "none") );
+ throw ::ape::exception( cx, "JWBinder::assert_binder(0x%x,js=%s) failed. msg=[%s]",
+ cx, jsval_to_cstring(cx,jv), (msg ? msg : "none") );
}
return b;
}
@@ -219,12 +257,13 @@
return b ? b->window() : 0;
}
- WINDOW * JWBinder::assert_window( JSContext * cx, jsval jv )
+ WINDOW * JWBinder::assert_window( JSContext * cx, jsval jv, char const * msg )
{
WINDOW * w = get_window(cx,jv);
if( ! w )
{
- throw ::ape::exception( cx, "JWBinder::assert_window(cx=%x,jv=%s) failed", cx, jsval_to_cstring(cx,jv) );
+ throw ::ape::exception( cx, "JWBinder::assert_window(cx=%x,jv=%s) failed. msg=[%s]",
+ cx, jsval_to_cstring(cx,jv), (msg ? msg : "none") );
}
return w;
}
Modified: plugins/ncurses/binder.hpp
===================================================================
--- plugins/ncurses/binder.hpp 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/binder.hpp 2007-09-28 03:44:42 UTC (rev 42)
@@ -15,19 +15,17 @@
INTERNAL type for binding WINDOWs to JSObjects.
The internals of the ncurses/JS bindings use this,
but you should not.
+
+ This type is used extensively by the code in ncwrapper.cpp
+ and panels.cpp, but no other code should try to make use of
+ it.
*/
class JWBinder
{
public:
typedef std::list<JWBinder *> BinderList;
- enum Flags {
- NoFlags = 0x00000000,
- StdScreen = 0x1000000
- };
private:
- static int m_counter;
JSContext * m_cx;
- //JSObject * m_obj;
WINDOW * m_win;
PANEL * m_pnl;
jsval m_v;
@@ -35,13 +33,9 @@
JWBinder * m_parent;
BinderList m_ch;
void init();
- typedef std::map<WINDOW *,JWBinder *> WinMap;
- static WinMap & windowmap()
- {
- static WinMap m;
- return m;
- }
+ static BinderList & all_binders();
+
/** Adds ch to this object's children(). */
void link_child( JWBinder * ch );
@@ -55,16 +49,19 @@
this->js_value().
*/
JWBinder(JSContext *cx, WINDOW * w, jsval jv = 0 );
+ /**
+ Binds p to jv. If jv == 0 then an arbitrary jsval
+ is generated, which can be fetched via
+ this->js_value().
+ */
JWBinder(JSContext *cx, PANEL *p, jsval jv = 0 );
-// /** Returns the binder associated with w. */
-// static JWBinder * binder_for( WINDOW * w );
~JWBinder();
/** Returns the jsval bound to this->window(). */
jsval js_value() const;
- /** Returns internal flags. */
- unsigned long flags() const;
- /** Sets internal flags, returning old state. */
- unsigned long flags( unsigned long f );
+// /** Returns internal flags. */
+// unsigned long flags() const;
+// /** Sets internal flags, returning old state. */
+// unsigned long flags( unsigned long f );
/** Returns this object's JSContext. */
JSContext * js_context();
/** Returns this object's bound WINDOW. */
@@ -95,18 +92,27 @@
/** Returns binder associated with cx/jv. */
static JWBinder * get_binder( JSContext * cx, jsval jv );
+
/** Like get_binder(), but throws if no binding is found. */
static JWBinder * assert_binder( JSContext * cx, jsval jv, char const * msg = 0 );
+
/** Returns WINDOW associated with cx/jv. */
static WINDOW * get_window( JSContext * cx, jsval jv );
+
/** Like get_window(), but throws if no binding is found. */
- static WINDOW * assert_window( JSContext * cx, jsval jv );
+ static WINDOW * assert_window( JSContext * cx, jsval jv, char const * msg = 0 );
/** Returns PANEL associated with cx/jv. */
static PANEL * get_panel( JSContext * cx, jsval jv );
+
/** Like get_panel(), but throws if no binding is found. */
static PANEL * assert_panel( JSContext * cx, jsval jv );
+ /** Only to be called by nc_endwin()! Destroys all WINDOWs/PANELs/PADs
+ allocated by the framework.
+ */
+ static void endwin_cleanup();
+
};
Modified: plugins/ncurses/ncwrapper.cpp
===================================================================
--- plugins/ncurses/ncwrapper.cpp 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/ncwrapper.cpp 2007-09-28 03:44:42 UTC (rev 42)
@@ -77,6 +77,31 @@
} \
ASSERTNC(FUNCNAME,CX)
+// WINDOW_OR_NCERR() checks an arg to ensure it's a WINDOW, else it sets rval to NCJS_ERR and returns.
+#define WINDOW_OR_NCERR(JSARG,VARNAME) \
+ WINDOW * VARNAME = JWBinder::get_window(cx,JSARG); \
+ if( ! VARNAME ) { \
+ *rval = NCJS_ERR; \
+ return JS_TRUE; \
+ }
+
+// WINDOW_OR_NCERR() checks an arg to ensure it's a WINDOW, else it sets rval to JSVAL_NULL and returns.
+#define WINDOW_OR_JSNULL(JSARG,VARNAME) \
+ WINDOW * VARNAME = JWBinder::get_window(cx,JSARG); \
+ if( ! VARNAME ) { \
+ *rval = JSVAL_NULL; \
+ return JS_TRUE; \
+ }
+
+
+// WINDOW_OR_JSTHROW() checks an arg to ensure it's a WINDOW, else it sets a pending exception.
+#define WINDOW_OR_JSTHROW(FUNCNAME,JSARG,VARNAME) \
+ WINDOW * VARNAME = JWBinder::get_window(cx,JSARG); \
+ if( ! VARNAME ) { \
+ *rval = NCJS_ERR; \
+ return ape::set_pending_exception(cx,"%s() requires a WINDOW argument!",FUNCNAME); \
+ }
+
int screen_width()
{
return stdscr ? stdscr->_maxx+1 : 0;
@@ -86,10 +111,43 @@
return stdscr ? stdscr->_maxy+1 : 0;
}
- static const jsval NCJS_ERR = int_to_jsval(-1);
- static const jsval NCJS_OK = int_to_jsval(0);
+// typedef std::list<JWBinder *> BinderList;
+// BinderList & jwbinders()
+// {
+// static BinderList bob;
+// return bob;
+// }
+// /**
+// Internal use only. Only add top-level (non-parented)
+// binders here.
+// */
+// JWBinder * add_binder( JWBinder * b )
+// {
+// jwbinders().push_back(b);
+// return b;
+// }
+
+// void cleanup_binder( JWBinder * b )
+// {
+// if( ! b ) return;
+// jwbinders().remove(b);
+// delete b;
+// }
+
+// void cleanup_binders()
+// {
+// BinderList cp( jwbinders() );
+// BinderList::reverse_iterator rit = cp.begin();
+// for( ; rit != cp.rend(); ++rit )
+// {
+// cleanup_binder( *rit );
+// }
+// }
+
+
+
/**
Weird behaviour vis-a-vis ncurses' chtype
and to_jsval():
@@ -166,7 +224,7 @@
JSObject * obj = JS_GetGlobalObject( context );
binders()[rp] = new JWBinder( context, w );
jsval argv[] = {
- ::ape::to_jsval<WINDOW*>( context, w ),
+ WINDOW_to_jsval( context, w ),
int_to_jsval(l)
};
jsval rval;
@@ -242,7 +300,8 @@
scriptable nc( cx, jsval_to_object( jv ) );
std::ostringstream os;
- os
+ os << "this['ERR'] = " << ERR << ';'
+ << "this['OK'] = "<<OK<<';'
<< "this['TAB'] = 9;\n"
<< "this['\\t'] = 'TAB';\n"
<< "this[9] = 'TAB'; // key conflicts with ASCII 59/char '9'!\n"
@@ -559,6 +618,7 @@
{"nc_wmaxy", nc_wmaxy, 0},
{"nc_wmove", nc_wmove, 0},
{"nc_wnoutrefresh", nc_wnoutrefresh, 0},
+ {"nc_wprint", nc_wprint, 0},
{"nc_wredrawln", nc_wredrawln, 0},
{"nc_wrefresh", nc_wrefresh, 0},
{"nc_wresize", nc_wresize, 0},
@@ -679,17 +739,22 @@
return JS_TRUE;
}
-
JS_FUNC(nc_initscr)
{
JSObject * globobj = JS_GetGlobalObject(cx);
- jsval globv = OBJECT_TO_JSVAL(globobj);
- JWBinder * bin = JWBinder::get_binder( cx, globv ); //OBJECT_TO_JSVAL(obj) );
- if( bin )
- { // already initialized.
- *rval = bin->js_value();
+// jsval globv = OBJECT_TO_JSVAL(globobj);
+// JWBinder * bin = JWBinder::get_binder( cx, globv ); //OBJECT_TO_JSVAL(obj) );
+// if( bin )
+// { // already initialized.
+// *rval = bin->js_value();
+// return JS_TRUE;
+// }
+ jsval jvscr = ape::bind::get_jsval<WINDOW*>( cx, stdscr );
+ if( JSVAL_VOID != jvscr )
+ {
+ *rval = jvscr;
return JS_TRUE;
- }
+ }
WINDOW * std = initscr();
if( ! std )
{
@@ -714,7 +779,8 @@
::start_color();
install_full_palette();
}
- JWBinder * b = new JWBinder( cx, std, globv );
+ //JWBinder * b = new JWBinder( cx, std, globv );
+ JWBinder * b = new JWBinder( cx, std );
*rval = b->js_value();
JS_DefineProperty(cx, globobj, "stdscr", *rval, NULL, NULL, 0);
return JS_TRUE;
@@ -727,19 +793,17 @@
*rval = NCJS_ERR;
return JS_TRUE;
}
- JWBinder * b = JWBinder::get_binder(cx,OBJECT_TO_JSVAL(obj));
- if( ! b )
- {
- *rval = NCJS_ERR;
- return JS_TRUE; // assume endwin() already called.
- }
- ripoff::reset();
+ ripoff::reset(); // must come before JWBinder::endwin_cleanup()!!!
+ //CERR << "Freeing stdscr property...\n";
+ JS_DeleteProperty(cx, obj, "stdscr");
+ //CERR << "Freed stdscr property.\n";
+ CERR << "FIXME: nc_endwin cleanup: need to nuke all window resources!\n";
+ JWBinder::endwin_cleanup();
+ //CERR << "DONE: endwin_cleanup()!\n";
int rc = endwin();
- JS_DeleteProperty(cx, obj, "stdscr");
- if( ! rc )
+ if( 0 != rc )
{
stdscr = 0;
- delete b;
}
*rval = int_to_jsval( cx, rc );
return JS_TRUE;
@@ -882,24 +946,14 @@
JS_FUNC(nc_waddvstr)
{
ASSERTARGC("nc_waddvstr",cx,(2==argc));
- WINDOW * w = JWBinder::get_window( cx, argv[0] );
- if( ! w )
- {
- *rval = NCJS_ERR;
- return JS_TRUE;
- }
+ WINDOW_OR_NCERR(argv[0],w);
std::string s( jsval_to_std_string(cx, argv[1] ) );
return nc_addvstr_impl( w, getcury(w), getcurx(w), s, -1, rval );
}
JS_FUNC(nc_waddvnstr)
{
ASSERTARGC("nc_waddvnstr",cx,(3==argc));
- WINDOW * w = JWBinder::get_window( cx, *(argv++) );
- if( ! w )
- {
- *rval = NCJS_ERR;
- return JS_TRUE;
- }
+ WINDOW_OR_NCERR(*(argv++),w);
std::string s = jsval_to_std_string( cx, *(argv++) );
int n = jsval_to_int( *(argv++) );
return nc_addvstr_impl( w, getcury(w), getcurx(w), s, n, rval );
@@ -908,12 +962,7 @@
JS_FUNC(nc_mvwaddvstr)
{
ASSERTARGC("nc_mvwaddvstr",cx,(4==argc));
- WINDOW * w = JWBinder::get_window( cx, *(argv++) );
- if( ! w )
- {
- *rval = NCJS_ERR;
- return JS_TRUE;
- }
+ WINDOW_OR_NCERR(*(argv++),w);
int y = jsval_to_int( *(argv++) );
int x = jsval_to_int( *(argv++) );
std::string s( jsval_to_std_string(cx, *(argv++) ) );
@@ -923,12 +972,7 @@
JS_FUNC(nc_mvwaddvnstr)
{
ASSERTARGC("nc_mvwaddvnstr",cx,(5==argc));
- WINDOW * w = JWBinder::get_window( cx, *(argv++) );
- if( ! w )
- {
- *rval = NCJS_ERR;
- return JS_TRUE;
- }
+ WINDOW_OR_NCERR(*(argv++),w);
int y = jsval_to_int( *(argv++) );
int x = jsval_to_int( *(argv++) );
std::string s( jsval_to_std_string(cx, *(argv++) ) );
@@ -961,7 +1005,7 @@
JS_FUNC(nc_wbkgd)
{
ASSERTARGC("nc_wbkgd",cx,(2==argc));
- WINDOW * w = jsval_to<WINDOW>(cx,*(argv++));
+ WINDOW * w = jsval_to_WINDOW(cx,*(argv++));
if( ! w )
{
JS_ReportWarning(cx,"nc_wbkgd(WINDOW,int): first arg must be a WINDOW handle.");
@@ -973,6 +1017,33 @@
return JS_TRUE;
}
+ JS_FUNC(nc_wprint)
+ {
+ ASSERTARGC("nc_wbkgd",cx,(0<argc));
+ WINDOW * w = jsval_to_WINDOW(cx,argv[0]);
+ if( ! w )
+ {
+ JS_ReportWarning(cx,"nc_print(WINDOW,...): first arg must be a WINDOW handle.");
+ *rval = NCJS_ERR;
+ return JS_TRUE;
+ }
+ for( uint32 i = 1; i < argc; ++i )
+ {
+ char const * s = jsval_to_cstring(cx,argv[i]);
+ ::waddstr( w, s );
+ if( i < (argc-1) )
+ {
+ waddch(w,' ');
+ }
+ }
+ waddch(w,'\n');
+ // We do the following in case w is associated with a panel, because
+ // nc_wrefresh() handles that case:
+ jsval av[1] = { argv[0] };
+ nc_wrefresh(cx,obj,1,av,rval);
+ *rval = JSVAL_NULL;
+ return JS_TRUE;
+ }
JS_FUNC(nc_wrefresh)
@@ -988,7 +1059,8 @@
bin = JWBinder::get_binder(cx,argv[i]);
if( ! bin )
{
- JS_ReportWarning(cx,"nc_wrefresh(): failed to get binder for arg #%d: %s",i,jsval_to_cstring(cx,argv[i]));
+ //JS_ReportWarning(cx,"nc_wrefresh(): failed to get binder for arg #%d: %s",i,jsval_to_cstring(cx,argv[i]));
+ return ape::set_pending_exception(cx,"nc_wrefresh(): failed to get binder for arg #%d: %s",i,jsval_to_cstring(cx,argv[i]));
return JS_TRUE;
}
w = bin->window();
@@ -1000,8 +1072,10 @@
}
else if( bin->panel() )
{
- *rval = int_to_jsval( wnoutrefresh(w) );
+ //*rval = int_to_jsval( wnoutrefresh(w) );
+ touchwin(w);
update_panels();
+ *rval = int_to_jsval( doupdate() );
return JS_TRUE;
}
else if( ERR == wrefresh(w) )
@@ -1320,7 +1394,7 @@
JS_FUNC(nc_getpary)
{
ASSERTARGC("nc_getpary",cx,(1==argc));
- WINDOW * w = JWBinder::assert_window( cx, *(argv), "nc_getpary()" );
+ WINDOW_OR_JSNULL(*argv,w);
int y = -1;
int x = -1;
getparyx( w, y, x );
@@ -1331,7 +1405,7 @@
JS_FUNC(nc_getparx)
{
ASSERTARGC("nc_getparx",cx,(1==argc));
- WINDOW * w = JWBinder::assert_window( cx, *(argv), "nc_getparx()" );
+ WINDOW_OR_JSNULL(*argv,w);
int y = -1;
int x = -1;
getparyx( w, y, x );
@@ -1343,7 +1417,7 @@
JS_FUNC(nc_getparyx)
{
ASSERTARGC("nc_getparyx",cx,(1==argc));
- WINDOW * w = JWBinder::assert_window( cx, *(argv), "nc_getparyx()" );
+ WINDOW_OR_JSNULL(*argv,w);
int y = -1;
int x = -1;
getparyx( w, y, x );
@@ -1357,7 +1431,7 @@
JS_FUNC(nc_getcuryx)
{
ASSERTARGC("nc_getcuryx",cx,(1==argc));
- WINDOW * w = JWBinder::assert_window( cx, *(argv), "nc_getcuryx()" );
+ WINDOW_OR_JSNULL(*argv,w);
int y = getcury( w );
int x = getcurx( w );
::ape::js_simple_object quasi( cx );
@@ -1370,7 +1444,7 @@
JS_FUNC(nc_getbegyx)
{
ASSERTARGC("nc_getbegyx",cx,(1==argc));
- WINDOW * w = JWBinder::assert_window( cx, *(argv), "nc_getbegyx()" );
+ WINDOW_OR_JSNULL(*argv,w);
int y = -1;
int x = -1;
getbegyx( w, y, x );
@@ -1384,7 +1458,7 @@
JS_FUNC(nc_getmaxyx)
{
ASSERTARGC("nc_getmaxyx",cx,(1==argc));
- WINDOW * w = JWBinder::assert_window( cx, *(argv), "nc_getmaxyx()" );
+ WINDOW_OR_JSNULL(*argv,w);
int y = -1;
int x = -1;
getmaxyx( w, y, x );
@@ -1486,14 +1560,7 @@
{
ASSERTARGC("nc_is_pad",cx,(1==argc));
WINDOW * w = JWBinder::get_window( cx, *argv );
- if( ! w )
- {
- *rval = bool_to_jsval( false );
- }
- else
- {
- *rval = bool_to_jsval( WIN_IS_PAD(w) );
- }
+ *rval = bool_to_jsval( w ? (WIN_IS_PAD(w)) : false );
return JS_TRUE;
}
@@ -1522,7 +1589,7 @@
nc_capture_stream( std::ostream & os, JSContext *cx, JSObject *obj, uint32 argc, jsval * argv, jsval * rval )
{
ASSERTARGC("nc_capture_cout/cerr",cx,((argc>0) && (argc<3)));
- WINDOW * w = JWBinder::assert_window(cx,argv[0], "nc_capture_stream()" );
+ WINDOW_OR_JSTHROW("nc_capture_stream",argv[0],w);
long attr = (argc>1) ? jsval_to_int(argv[1]) : 0;
Private::captured_streams().insert( ::std::make_pair( w, new nc_window_streambuf(w,os,attr) ) );
*rval = JSVAL_VOID;
@@ -1541,8 +1608,8 @@
JS_FUNC(nc_capture_end)
{
- ASSERTARGC("nc_end_capture_cout/cerr",cx,(1==argc));
- WINDOW * w = JWBinder::assert_window(cx,argv[0], "nc_capture_end()");
+ ASSERTARGC("nc_capture_end",cx,(1==argc));
+ WINDOW_OR_JSTHROW("nc_capture_end",argv[0],w);
using namespace Private;
WindowStreamMap & str = captured_streams();
typedef WindowStreamMap::iterator WIT;
@@ -1638,7 +1705,7 @@
JS_FUNC(nc_box)
{
ASSERTARGC("nc_box",cx,((argc>=1) && (argc<=3)));
- WINDOW * w = JWBinder::assert_window(cx,*argv,"nc_box()");
+ WINDOW_OR_NCERR(*argv,w);
chtype vch = (argc>1) ? jsval_to_chtype(cx,argv[1]) : 0;
chtype hch = (argc>2) ? jsval_to_chtype(cx,argv[2]) : 0;
*rval = int_to_jsval( cx, box( w, vch, hch ) );
@@ -1924,7 +1991,7 @@
JS_FUNC(nc_getcury)
{
ASSERTARGC("nc_getcury",cx,(1==argc));
- WINDOW * w = JWBinder::get_window(cx,*argv);
+ WINDOW_OR_NCERR(argv[0],w);
*rval = int_to_jsval( w ? getcury(w) : -1 );
return JS_TRUE;
}
@@ -1932,7 +1999,7 @@
JS_FUNC(nc_getcurx)
{
ASSERTARGC("nc_getcurx",cx,(1==argc));
- WINDOW * w = JWBinder::get_window(cx,*argv);
+ WINDOW_OR_NCERR(argv[0],w);
*rval = int_to_jsval( w ? getcurx(w) : -1 );
return JS_TRUE;
}
@@ -1952,7 +2019,8 @@
JS_FUNC(nc_winch)
{
ASSERTARGC("nc_winch",cx,(1==argc));
- *rval = to_jsval<chtype>( cx, winch( JWBinder::assert_window(cx,*argv,"nc_winch()") ) );
+ WINDOW_OR_NCERR(*argv,w);
+ *rval = to_jsval<chtype>( cx, winch( w ) );
return JS_TRUE;
}
@@ -1973,7 +2041,7 @@
JS_FUNC(nc_mvwchgat)
{
ASSERTARGC("nc_mvwchgat",cx,(6==argc));
- WINDOW * w = JWBinder::assert_window( cx, *(argv++),"nc_mvwchgat()" );
+ WINDOW_OR_NCERR(*(argv++),w);
int y = jsval_to_int(*(argv++));
int x = jsval_to_int(*(argv++));
int n = jsval_to_int(*(argv++));
@@ -1993,6 +2061,11 @@
#else
::ape::argv_wrapper av(cx,argc,argv);
WINDOW * w = av++.to<WINDOW *>();
+ if( ! w )
+ {
+ *rval = NCJS_ERR;
+ return JS_TRUE;
+ }
int n = av++.to<int>();
int attr = av++.to<int>();
short color = av++.to<short>();
Modified: plugins/ncurses/ncwrapper.hpp
===================================================================
--- plugins/ncurses/ncwrapper.hpp 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/ncwrapper.hpp 2007-09-28 03:44:42 UTC (rev 42)
@@ -13,6 +13,7 @@
#include <sf.net/ape/conversion.hpp>
extern "C" {
# include <ncurses.h>
+# include <panel.h>
}
#include <map>
namespace ape {
@@ -66,15 +67,20 @@
*/
typedef long chtype; // from ncurses
+ static const jsval NCJS_ERR = ape::int_to_jsval(-1);
+ static const jsval NCJS_OK = ape::int_to_jsval(0);
+
+
static const ape::to_jsval_f<chtype> chtype_to_jsval = ape::to_jsval_f<chtype>();
static const ape::jsval_to_f<chtype> jsval_to_chtype = ape::jsval_to_f<chtype>();
+ static const ape::to_jsval_f<WINDOW*> WINDOW_to_jsval = ape::to_jsval_f<WINDOW*>();
+ static const ape::jsval_to_f<WINDOW*> jsval_to_WINDOW = ape::jsval_to_f<WINDOW*>();
+ static const ape::to_jsval_f<PANEL*> PANEL_to_jsval = ape::to_jsval_f<PANEL*>();
+ static const ape::jsval_to_f<PANEL*> jsval_to_PANEL = ape::jsval_to_f<PANEL*>();
- static const ape::to_jsval_f<WINDOW> WINDOW_to_jsval = ape::to_jsval_f<WINDOW>();
- static const ape::jsval_to_f<WINDOW> jsval_to_WINDOW = ape::jsval_to_f<WINDOW>();
-
// NC_WRAPPER_FUNC() is only to simplify browsing of the bound
// functions list, by (a) removing all of the syntactic noise
// brought on by the function signature and (b) making the
@@ -207,7 +213,12 @@
NC_WRAPPER_FUNC(wmove);
NC_WRAPPER_FUNC(redrawwin);
NC_WRAPPER_FUNC(wredrawln);
- /** Accepts 1 or more WINDOW arguments. */
+ /** Accepts 1 or more WINDOW or PANEL arguments. For PANELs
+ it does the update technique appropriate for PANELs (or at
+ least it does what *it thinks* is appropriate for PANELs).
+ If you pass it a PAD then it will silently fail without
+ crashing.
+ */
NC_WRAPPER_FUNC(wrefresh);
/** Read the native docs before using this. It's not
quite as useful as it sounds, due to curses' lack of
@@ -397,7 +408,8 @@
It might be interesting to know that nc_delwin() also works
on PANEL handles, whereas the native delwin() should not be
- used on panels.
+ used on panels. The difference with nc_delwin() is that it will
+ delete the PANEL *and* the associated WINDOW.
*/
NC_WRAPPER_FUNC(del_panel);
NC_WRAPPER_FUNC(hide_panel);
@@ -625,7 +637,21 @@
*/
NC_WRAPPER_FUNC(wgeometry);
+ /**
+ Works similarly to print(), but assumes that its first
+ argument is a WINDOW. The remaining args are
+ space-separated and added to the WINDOW using addstr() and
+ a trailing '\n' is then added. Unlike addstr(), this
+ function DOES call refresh() when it is done (this
+ simplifies its usage). If you are operating on PADs then
+ nc_addstr() is recommended, because refresh() is not legal
+ for PADs.
+ JS usage: nc_wprint(myWin,...);
+ */
+ NC_WRAPPER_FUNC(wprint);
+
+
#undef NC_WRAPPER_FUNC
} } // namespace ape::nc
Modified: plugins/ncurses/panel.cpp
===================================================================
--- plugins/ncurses/panel.cpp 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/panel.cpp 2007-09-28 03:44:42 UTC (rev 42)
@@ -4,8 +4,6 @@
#include <sf.net/ape/spiderape.hpp>
#include <sf.net/ape/debuggering_macros.hpp> // CERR
#include <sf.net/ape/fwd_to_func.hpp>
-#include <ncurses.h>
-#include <panel.h>
#include "binder.hpp"
#include "ncwrapper.hpp"
namespace ape {
@@ -30,6 +28,31 @@
} \
ASSERTNC(FUNCNAME,CX)
+// WINDOW_OR_JSTHROW() checks an arg to ensure it's a WINDOW, else it sets a pending exception.
+#define WINDOW_OR_JSTHROW(FUNCNAME,JSARG,VARNAME) \
+ WINDOW * VARNAME = JWBinder::get_window(cx,JSARG); \
+ if( ! VARNAME ) { \
+ *rval = NCJS_ERR; \
+ return ape::set_pending_exception(cx,"%s() requires a WINDOW argument!",FUNCNAME); \
+ }
+
+// PANEL_OR_NCERR() checks an arg to ensure it's a PANEL, else it sets rval to NCJS_ERR and returns.
+#define PANEL_OR_NCERR(JSARG,VARNAME) \
+ PANEL * VARNAME = JWBinder::get_panel(cx,JSARG); \
+ if( ! VARNAME ) { \
+ *rval = NCJS_ERR; \
+ return JS_TRUE; \
+ }
+
+// PANEL_OR_JSTHROW() checks an arg to ensure it's a PANEL, else it sets a pending exception.
+#define PANEL_OR_JSTHROW(FUNCNAME,JSARG,VARNAME) \
+ PANEL * VARNAME = JWBinder::get_panel(cx,JSARG); \
+ if( ! VARNAME ) { \
+ *rval = NCJS_ERR; \
+ return ape::set_pending_exception(cx,"%s() requires a PANEL argument!",FUNCNAME); \
+ }
+
+
JS_FUNC(nc_bottom_panel)
{
ASSERTARGC("nc_bottom_panel",cx,(1==argc));
@@ -40,10 +63,14 @@
JS_FUNC(nc_del_panel)
{
ASSERTARGC("nc_del_panel",cx,(1==argc));
- JWBinder * b = JWBinder::assert_binder( cx, *argv );
- *rval = bool_to_jsval( b->free_panel() );
- //return nc_delwin( cx, obj, argc, argv, rval );
- // ^^^ delwin() works identically to del_panel() here because
+ JWBinder * b = JWBinder::get_binder( cx, *argv );
+ if( ! b )
+ {
+ *rval = ape::int_to_jsval(-1);
+ return JSVAL_TRUE;
+ }
+ *rval = ape::int_to_jsval( b->free_panel() );
+ // ^^^ nc_delwin() works like del_panel() here because
// of the way our JWBinder cleanup works.
return JS_TRUE;
}
@@ -71,11 +98,11 @@
JS_FUNC(nc_new_panel)
{
ASSERTARGC("nc_new_panel",cx,(1==argc));
- WINDOW * w = JWBinder::assert_window( cx, *argv );
+ WINDOW_OR_JSTHROW("nc_new_panel",*argv,w);
PANEL * p = new_panel(w);
if( ! p )
{
- JS_ReportWarning(cx,"nc_new_panel(): new_panel() failed!");
+ //JS_ReportWarning(cx,"nc_new_panel(): new_panel() failed!");
*rval = JSVAL_NULL;
return JS_TRUE;
}
@@ -86,43 +113,41 @@
JS_FUNC(nc_panel_above)
{
ASSERTARGC("nc_panel_above",cx,(1==argc));
- *rval = to_jsval<PANEL*>( cx, ::ape::fwd_to_func1<PANEL*,const PANEL *>( panel_above, cx, obj, argc, argv ) );
+ *rval = PANEL_to_jsval( cx, ::ape::fwd_to_func1<PANEL*,const PANEL *>( panel_above, cx, obj, argc, argv ) );
return JS_TRUE;
}
JS_FUNC(nc_panel_below)
{
ASSERTARGC("nc_panel_below",cx,(1==argc));
- *rval = to_jsval<PANEL*>( cx, ::ape::fwd_to_func1<PANEL*,const PANEL *>( panel_below, cx, obj, argc, argv ) );
+ *rval = PANEL_to_jsval( cx, ::ape::fwd_to_func1<PANEL*,const PANEL *>( panel_below, cx, obj, argc, argv ) );
return JS_TRUE;
}
JS_FUNC(nc_panel_hidden)
{
ASSERTARGC("nc_panel_hidden",cx,(1==argc));
- PANEL * p = JWBinder::get_panel( cx, *argv );
- if( ! p )
- {
- JS_ReportWarning( cx, "nc_panel_hidden() expects a single PANEL argument." );
- *rval = int_to_jsval(-1);
- return JS_TRUE;
- }
+ PANEL_OR_NCERR(argv[0],p);
*rval = int_to_jsval( panel_hidden(p) );
- //::ape::int_to_jsval(::ape::fwd_to_func1<int,const PANEL *>( panel_hidden, cx, obj, argc, argv ) );
return JS_TRUE;
}
JS_FUNC(nc_panel_window)
{
ASSERTARGC("nc_panel_window",cx,(1==argc));
- *rval = to_jsval<WINDOW*>( cx, ::ape::fwd_to_func1<WINDOW*,const PANEL *>( panel_window, cx, obj, argc, argv ) );
+ *rval = WINDOW_to_jsval( cx, ::ape::fwd_to_func1<WINDOW*,const PANEL *>( panel_window, cx, obj, argc, argv ) );
return JS_TRUE;
}
JS_FUNC(nc_set_userdata)
{
ASSERTARGC("nc_set_userdata",cx,(2==argc));
- JWBinder::assert_binder( cx, *argv );
+ JWBinder * b = JWBinder::get_binder( cx, *argv );
// ^^^ we only really require this so we know we can clean up
// all entries via that JWBinder::~JWBinder().
+ if( ! b )
+ {
+ *rval = JSVAL_VOID;
+ return JS_TRUE;
+ }
typedef ::ape::jsval_t JT;
JT * j = ::ape::bind::get_native< JT >( cx, argv[0] );
if( j )
@@ -138,7 +163,7 @@
else
{
JT * j = new JT(argv[1]); // We must clean these up in ~JWBinder
- ::ape::bind::bind_native<JT>( cx, argv[0], j );
+ ::ape::bind::bind_native<JT>( cx, b->js_value(), j );
*rval = *j;
}
return JS_TRUE;
@@ -204,7 +229,7 @@
ASSERTARGC("nc_replace_panel",cx,(2==argc));
CHECKBINDER("nc_replace_panel",argv[0]);
PANEL * p = bin->panel();
- WINDOW * w = jsval_to<WINDOW>( cx, argv[1] );
+ WINDOW * w = jsval_to_WINDOW( cx, argv[1] );
if( (! p) || (!w) )
{
JS_ReportWarning(cx,"nc_replace_panel() requires arguments (PANEL,WINDOW).");
Modified: plugins/ncurses/plugin.make
===================================================================
--- plugins/ncurses/plugin.make 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/plugin.make 2007-09-28 03:44:42 UTC (rev 42)
@@ -40,7 +40,7 @@
PACKAGE_VERSION = $(APE.PLUGIN.VERSION)
prefix = $(APE.CONFIG.PREFIX)
# CPPFLAGS +=
-CXXFLAGS += -Wall -fPIC -pipe
+CXXFLAGS += -Wall -fPIC -pipe -g
LDFLAGS += -fPIC -pipe
#
########################################################################
Modified: plugins/ncurses/scripts/JCWindow.inc.js
===================================================================
--- plugins/ncurses/scripts/JCWindow.inc.js 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/scripts/JCWindow.inc.js 2007-09-28 03:44:42 UTC (rev 42)
@@ -4,7 +4,7 @@
if( ! is_defined( 'ncurses' ) )
{
- var dll = 'nc';
+ var dll = '../ncurses.so';
if( ! open_dll(dll) ) {
throw new Error("JSWindow could not load plugin '"+dll+"'.");
}
@@ -196,7 +196,8 @@
self.window = nc_newwin.apply(self,JCWindow.copyargs(arguments));
if( self.window )
{
- self.panel = nc_new_panel.apply(self.window);
+ self.panel = //nc_new_panel.apply(self.window);
+ nc_new_panel(self.window);
}
}
@@ -679,10 +680,10 @@
throw new Error("JCPad() unhandled ctor arguments. Read the docs." );
}
- this.vheight = function() { return nc_wheight( self.viewport ); };
- this.vwidth = function() { return nc_wwidth( self.viewport );};
- this.pheight = function() { return nc_wheight( self.pad ); };
- this.pwidth = function() { return nc_wwidth( self.pad ); };
+// this.vheight = function() { return nc_wheight( self.viewport ); };
+// this.vwidth = function() { return nc_wwidth( self.viewport );};
+// this.pheight = function() { return nc_wheight( self.pad ); };
+// this.pwidth = function() { return nc_wwidth( self.pad ); };
this.signals.scrollto = new Signal();
return self;
@@ -691,6 +692,11 @@
JCScroller.inherits( JCWindow );
+ JCScroller.prototype.vheight = function() { return nc_wheight( this.viewport ); };
+ JCScroller.prototype.vwidth = function() { return nc_wwidth( this.viewport );};
+ JCScroller.prototype.pheight = function() { return nc_wheight( this.pad ); };
+ JCScroller.prototype.pwidth = function() { return nc_wwidth( this.pad ); };
+
/**
Draws this.pad to the viewport window. If y and x are
passed, the top/left position of the viewport will be that
@@ -1173,12 +1179,12 @@
this.nc_wrender = function(win) {
// var old = nc_winch(win);
// var attr = this.selected
-// ? (ncurses.UNDERLINE | ncurses.BOLD | ncurses.REVERSE)
+// ? (ncurses.A_UNDERLINE | ncurses.A_BOLD | ncurses.A_REVERSE)
// : old;
// Weird: when i use nc_winch() and nc_wattrset(), all of the
// alpha chars in this.value get lowercased! curses!
var attr = this.selected
- ? (ncurses.UNDERLINE | ncurses.BOLD | ncurses.REVERSE)
+ ? (ncurses.A_UNDERLINE | ncurses.A_BOLD | ncurses.A_REVERSE)
: 0;
nc_wattron(win, attr);
nc_wrender(win,this.value);
Modified: plugins/ncurses/scripts/ncpad.js
===================================================================
--- plugins/ncurses/scripts/ncpad.js 2007-09-28 02:50:44 UTC (rev 41)
+++ plugins/ncurses/scripts/ncpad.js 2007-09-28 03:44:42 UTC (rev 42)
@@ -4,13 +4,13 @@
var sht = root.height();
var swt = root.width();
root.console = new JCWindow(root,sht/3*2,swt-2,1,1); //,sht/2,swt-2,1, 1);
-root.background(nc_color_pair("yellow","cyan") | ncurses.BOLD);
+root.background(nc_color_pair("yellow","cyan") | ncurses.A_BOLD);
root.border();
root.addstr(0,2,'ncpad test/demo');
root.refresh();
-root.console.background(nc_color_pair("white","black")|ncurses.BOLD);
+root.console.background(nc_color_pair("white","black")|ncurses.A_BOLD);
nc_capture_cout(root.console.window);
-//nc_capture_cerr(root.console.window,nc_color_pair("red","black")|ncurses.BOLD);
+//nc_capture_cerr(root.console.window,nc_color_pair("red","black")|ncurses.A_BOLD);
root.console.scrollok(true);
if( 0 ) {
@@ -22,7 +22,7 @@
root.console.scroller = new JCScroller( Pad, root.console );
root.signals.refresh.connect( root.console.scroller.refresh );
- //Pad.background(nc_color_pair('white','blue')|ncurses.BOLD);
+ //Pad.background(nc_color_pair('white','blue')|ncurses.A_BOLD);
for( var i = 0; i < Pad.height(); ++i )
{
print("Pad line #"+i);
@@ -52,7 +52,7 @@
nc_scrollok(Pad.pad,false);
var ht = ph/3;
var Win = root.SWindow = new JCWindow( root, ht, 30, ph+2, 1 );
- //Pad.background(nc_color_pair('white','blue')|ncurses.BOLD);
+ //Pad.background(nc_color_pair('white','blue')|ncurses.A_BOLD);
var SP = root.Scroller = new JCScroller( Pad, Win );
root.signals.refresh.connect( root.Scroller.refresh );
@@ -92,14 +92,14 @@
var km = new Object();
var thescroller = SP; //root.console.scroller;
var pageinc = thescroller.vheight();
- km[ncurses.UP] = function() { thescroller.scrollby(-1,0); };
- km[ncurses.DOWN] = function() { thescroller.scrollby(+1,0); };
- km[ncurses.RIGHT] = function() { thescroller.scrollby(0,+1); };
- km[ncurses.LEFT] = function() { thescroller.scrollby(0,-1); };
- km[ncurses.PGUP] = function() { thescroller.scrollby(-pageinc,0); };
- km[ncurses.PGDN] = function() { thescroller.scrollby(+pageinc,0); };
- km[ncurses.HOME] = function() { thescroller.scrollto(0,0); };
- km[ncurses.END] = function() { thescroller.scrollto(thescroller.pheight(),0); };
+ km[ncurses.KEY_UP] = function() { thescroller.scrollby(-1,0); };
+ km[ncurses.KEY_DOWN] = function() { thescroller.scrollby(+1,0); };
+ km[ncurses.KEY_RIGHT] = function() { thescroller.scrollby(0,+1); };
+ km[ncurses.KEY_LEFT] = function() { thescroller.scrollby(0,-1); };
+ km[ncurses.KEY_PPAGE] = function() { thescroller.scrollby(-pageinc,0); };
+ km[ncurses.KEY_NPAGE] = function() { thescroller.scrollby(+pageinc,0); };
+ km[ncurses.KEY_HOME] = function() { thescroller.scrollto(0,0); };
+ km[ncurses.KEY_END] = function() { thescroller.scrollto(thescroller.pheight(),0); };
km['q'] = function() { SP.keep_looping = false; };
Modified: plugins/ncurses/scripts/ncpanel.js
================================================================...
[truncated message content] |