1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        wxlstate.cpp
3 // Purpose:     wxLuaState, a wxWidgets interface to Lua
4 // Author:      Ray Gilbert, John Labenski, J Winwood (Reuben Thomas for bitlib at bottom)
5 // Created:     14/11/2001
6 // Copyright:   (c) 2012 John Labenski, 2001-2002 Lomtick Software. All rights reserved.
7 // Licence:     wxWidgets licence
8 /////////////////////////////////////////////////////////////////////////////
9 
10 // For compilers that support precompilation, includes "wx/wx.h"
11 #include <wx/wxprec.h>
12 
13 #ifdef __BORLANDC__
14     #pragma hdrstop
15 #endif
16 
17 // for all others, include the necessary headers
18 #ifndef WX_PRECOMP
19     #include <wx/wx.h>
20 #endif
21 
22 #include "wxlua/wxllua.h"
23 #include "wxlua/wxlstate.h"
24 #include "wxlua/wxlbind.h"
25 #include "wxlua/wxlcallb.h"
26 
27 //#include "wxluadebug/include/wxldebug.h" // for debugging only
28 
29 const char* wxlua_lreg_regtable_key            = "wxlua_lreg_regtable_key : wxLua LUA_REGISTRYINDEX tables";
30 
31 const char* wxlua_lreg_wxluastate_key          = "wxlua_lreg_wxluastate_key : wxLuaState";
32 const char* wxlua_lreg_wxluastatedata_key      = "wxlua_lreg_wxluastatedata_key : wxLuaStateData";
33 
34 const char* wxlua_lreg_wxluabindings_key       = "wxlua_lreg_wxluabindings_key : wxLuaBindings installed";
35 const char* wxlua_lreg_classes_key             = "wxlua_lreg_classes_key : wxLuaBindClass structs installed";
36 const char* wxlua_lreg_types_key               = "wxlua_lreg_types_key : wxLua metatable class types";
37 
38 const char* wxlua_lreg_weakobjects_key         = "wxlua_lreg_weakobjects_key : wxLua objects pushed";
39 const char* wxlua_lreg_gcobjects_key           = "wxlua_lreg_gcobjects_key : wxLua gc objects to delete";
40 const char* wxlua_lreg_derivedmethods_key      = "wxlua_lreg_derivedmethods_key : wxLua derived class methods";
41 const char* wxlua_lreg_evtcallbacks_key        = "wxlua_lreg_evtcallbacks_key : wxLuaEventCallbacks";
42 const char* wxlua_lreg_windestroycallbacks_key = "wxlua_lreg_windestroycallbacks_key : wxLuaWinDestoyCallbacks";
43 const char* wxlua_lreg_topwindows_key          = "wxlua_lreg_topwindows_key : wxLua top level wxWindows";
44 const char* wxlua_lreg_wxeventtype_key         = "wxlua_lreg_wxeventtype_key : wxLua wxEventType";
45 const char* wxlua_lreg_callbaseclassfunc_key   = "wxlua_lreg_callbaseclassfunc_key : wxLua CallBaseClassFunc";
46 
47 const char* wxlua_lreg_refs_key                = "wxlua_lreg_refs_key : wxLua Lua object refs";
48 const char* wxlua_lreg_debug_refs_key          = "wxlua_lreg_debug_refs_key : wxLuaDebugData refs";
49 
50 const char* wxlua_metatable_type_key           = "wxlua_metatable_type_key : wxLua metatable class type";
51 const char* wxlua_metatable_wxluabindclass_key = "wxlua_metatable_wxluabindclass_key : wxLua metatable wxLuaBindClass";
52 
53 // ----------------------------------------------------------------------------
54 
wxlua_lreg_createtable(lua_State * L,void * lightuserdata_reg_key,int narr,int nrec)55 void wxlua_lreg_createtable(lua_State* L, void* lightuserdata_reg_key, int narr, int nrec)
56 {
57     // clear the old ref to the table, even though it's weak kv
58     // it doesn't get cleared until the gc runs
59     lua_pushlightuserdata(L, &wxlua_lreg_regtable_key); // push key
60     lua_rawget(L, LUA_REGISTRYINDEX);                   // get table
61       lua_pushlightuserdata(L, lightuserdata_reg_key);  // push key
62       lua_rawget(L, LUA_REGISTRYINDEX);                 // get table or nil
63       if (lua_istable(L, -1))
64       {
65           lua_pushnil(L);                               // push value
66           lua_rawset(L, -3);                            // clear t[key] = nil
67           lua_pop(L, 1);                                // pop wxlua_lreg_regtable_key table
68       }
69       else
70         lua_pop(L, 2); // pop nil and wxlua_lreg_regtable_key table
71 
72     // Add new LUA_REGISTRYINDEX[&wxlua_lreg_regtable_key][lightuserdata_reg_key table] = lightuserdata_reg_key
73     lua_pushlightuserdata(L, lightuserdata_reg_key); // push key
74     lua_createtable(L, narr, nrec);                  // push value
75         lua_pushlightuserdata(L, &wxlua_lreg_regtable_key); // push key
76         lua_rawget(L, LUA_REGISTRYINDEX);                   // get wxlua_lreg_regtable_key table
77         lua_pushvalue(L, -2);    // push key (copy of the new table)
78         lua_pushvalue(L, -4);    // push value (copy of lightuserdata key)
79         lua_rawset(L, -3);       // set t[key] = value; pops key and value
80         lua_pop(L, 1);           // pop wxlua_lreg_regtable_key table
81     lua_rawset(L, LUA_REGISTRYINDEX); // set the value
82 }
83 
84 // ----------------------------------------------------------------------------
85 // Lua helper functions
86 // ----------------------------------------------------------------------------
87 
wxlua_LUA_ERR_msg(int LUA_ERRx)88 wxString wxlua_LUA_ERR_msg(int LUA_ERRx)
89 {
90     switch (LUA_ERRx)
91     {
92         case 0             : return wxEmptyString;
93         case LUA_YIELD     : return wxT("Lua: Thread is suspended");
94         case LUA_ERRRUN    : return wxT("Lua: Error while running chunk");
95         case LUA_ERRSYNTAX : return wxT("Lua: Syntax error during pre-compilation");
96         case LUA_ERRMEM    : return wxT("Lua: Memory allocation error");
97         case LUA_ERRERR    : return wxT("Lua: Generic error or an error occurred while running the error handler");
98         case LUA_ERRFILE   : return wxT("Lua: Error occurred while opening file");
99     }
100 
101     return wxT("Lua: Unknown LUA_ERRx error value");
102 }
103 
wxlua_errorinfo(lua_State * L,int status,int top,wxString * errorMsg_,int * line_num_)104 bool wxlua_errorinfo(lua_State* L, int status, int top, wxString* errorMsg_, int* line_num_)
105 {
106     if (status == 0)
107         return false;
108 
109     int newtop = lua_gettop(L);
110 
111     wxString errorMsg = wxlua_LUA_ERR_msg(status);
112 
113     switch(status)
114     {
115         case LUA_ERRMEM:
116         case LUA_ERRERR:
117         {
118             if (newtop > top)
119                 errorMsg += wxT("\n");
120             break;
121         }
122         case LUA_ERRRUN:
123         case LUA_ERRFILE:
124         case LUA_ERRSYNTAX:
125         default:
126         {
127             if (newtop > top)
128                 errorMsg += wxT("\n") + lua2wx(lua_tostring(L, -1));
129             break;
130         }
131     }
132 
133     errorMsg += wxT("\n");
134 
135     // Why can't I fill a lua_Debug here? Try to get the line number
136     // by parsing the error message that looks like this, 3 is linenumber
137     // [string "a = 1("]:3: unexpected symbol near `<eof>'
138     wxString lineStr = errorMsg;
139     long line_num = -1;
140     while(!lineStr.IsEmpty())
141     {
142         // search through the str to find ']:LONG:' pattern
143         lineStr = lineStr.AfterFirst(wxT(']'));
144         if ((lineStr.Length() > 0) && (lineStr.GetChar(0) == wxT(':')))
145         {
146             lineStr = lineStr.AfterFirst(wxT(':'));
147             if (lineStr.IsEmpty() || lineStr.BeforeFirst(wxT(':')).ToLong(&line_num))
148                 break;
149         }
150     }
151 
152     lua_settop(L, top); // pops the message if any
153 
154     if (errorMsg_) *errorMsg_ = errorMsg;
155     if (line_num_) *line_num_ = (int)line_num;
156 
157     return true;
158 }
159 
wxlua_error(lua_State * L,const char * errorMsg)160 void LUACALL wxlua_error(lua_State *L, const char *errorMsg)
161 {
162     // Use luaL_error(L, s) and not "lua_pushstring(L, s); lua_error(L)" since
163     // luaL_error() provides the file and line number too.
164     luaL_error(L, "%s", errorMsg);
165 }
166 
wxlua_argerror(lua_State * L,int stack_idx,const wxString & expectedType)167 void LUACALL wxlua_argerror(lua_State *L, int stack_idx, const wxString& expectedType)
168 {
169     wxString argType = wxlua_luaL_typename(L, stack_idx);
170 
171     wxString msg(wxString::Format(_("wxLua: Expected %s for parameter %d, but got a '%s'."),
172                                     expectedType.c_str(), stack_idx, argType.c_str()));
173 
174     wxlua_argerrormsg(L, msg);
175 }
176 
wxlua_argerrormsg(lua_State * L,const wxString & msg_)177 void LUACALL wxlua_argerrormsg(lua_State *L, const wxString& msg_)
178 {
179     wxString funcArgs(wxT("\n"));
180     wxString argMsg  = wxlua_getLuaArgsMsg(L, 1, lua_gettop(L));
181 
182     wxLuaBindMethod* wxlMethod = (wxLuaBindMethod *)lua_touserdata(L, lua_upvalueindex(1)); // lightuserdata
183     if (wxlMethod != NULL)
184     {
185         // Guarantee that this is a wxLuaBindMethod of ours so we don't crash.
186         // Since we're going to error out we don't have to be quick about it.
187 
188         // check if this method is part of a class
189         const wxLuaBindClass* wxlClass = wxLuaBinding::FindBindClass(wxlMethod);
190 
191         // if not, check if it's a global C style function
192         wxLuaBinding* binding = NULL;
193         if (wxlClass == NULL)
194             binding = wxLuaBinding::FindMethodBinding(wxlMethod);
195 
196         if ((wxlClass != NULL) || (binding != NULL))
197             funcArgs += wxlua_getBindMethodArgsMsg(L, wxlMethod);
198     }
199 
200     wxString msg;
201     msg.Printf(wxT("%s\nFunction called: '%s'%s"), msg_.c_str(), argMsg.c_str(), funcArgs.c_str());
202     wxlua_error(L, msg.c_str());
203 }
204 
wxlua_touserdata(lua_State * L,int stack_idx,bool null_ptr)205 void* LUACALL wxlua_touserdata(lua_State *L, int stack_idx, bool null_ptr /*= false*/)
206 {
207     if (lua_islightuserdata(L, stack_idx) != 0)
208     {
209         // can't NULL the ptr, just return the lightuserdata as is
210         return lua_touserdata(L, stack_idx);
211     }
212 
213     void *pdata = NULL;
214     void **ptr = (void **)lua_touserdata(L, stack_idx);
215 
216     if (ptr != NULL)
217     {
218         pdata = *ptr;       // get the pointer the userdata holds
219         if (null_ptr)       // NULL ptr so Lua won't try to gc it
220             *ptr = NULL;
221     }
222 
223     return pdata;
224 }
225 
226 // ----------------------------------------------------------------------------
227 // wxluaR_XXX - functions operate on tables in Lua's LUA_REGISTRYINDEX
228 // ----------------------------------------------------------------------------
229 
230 #define ABS_LUA_STKIDX(n, added_items) ((n) > 0 ? (n) : (n)-(added_items))
231 
232 // Note about luaL_ref() and luaL_unref().
233 // ref creates integer numbers from 1 to ...
234 // unref uses t[0] to hold the last unused reference and when you call unref
235 // again the next unused ref points back to the first and t[0] points to the
236 // last unrefed key.
237 // eg. create 5 refs, get refs 1,2,3,4,5, then call unref on 3 then 4 then
238 //     call ref 3 times and the new references will be 4, 3, 6
239 
wxluaR_ref(lua_State * L,int stack_idx,void * lightuserdata_reg_key)240 int wxluaR_ref(lua_State* L, int stack_idx, void* lightuserdata_reg_key)
241 {
242     // nothing on stack to insert and don't bother inserting nil
243     if (lua_isnoneornil(L, stack_idx))
244         return LUA_REFNIL;
245 
246     lua_pushlightuserdata(L, lightuserdata_reg_key);    // push key
247     lua_rawget(L, LUA_REGISTRYINDEX);                   // pop key, push value (table)
248 
249     lua_pushvalue(L, ABS_LUA_STKIDX(stack_idx,1));      // push value to store
250 
251     int ref_idx = luaL_ref(L, -2);                      // t[ref_idx] = value; pops value
252 
253     // We also store t[value] = table_idx for this table for faster lookup
254     if (lightuserdata_reg_key == &wxlua_lreg_debug_refs_key)
255     {
256         lua_pushvalue(L, ABS_LUA_STKIDX(stack_idx,1));  // push key
257         lua_pushnumber(L, ref_idx);                     // push value
258         lua_rawset(L, -3);                              // set t[key] = value; pops key and value
259     }
260 
261     lua_pop(L, 1);                                      // pop table
262 
263     return ref_idx;
264 }
265 
wxluaR_unref(lua_State * L,int ref_idx,void * lightuserdata_reg_key)266 bool wxluaR_unref(lua_State* L, int ref_idx, void* lightuserdata_reg_key)
267 {
268     if (ref_idx == LUA_REFNIL)                       // nothing to remove
269         return false;
270 
271     lua_pushlightuserdata(L, lightuserdata_reg_key); // push key
272     lua_rawget(L, LUA_REGISTRYINDEX);                // pop key, push value (table)
273 
274     // Also remove the t[value] = table_idx for this table
275     if (lightuserdata_reg_key == &wxlua_lreg_debug_refs_key)
276     {
277         lua_pushnumber(L, ref_idx);   // push key
278         lua_rawget(L, -2);            // get t[key] = value; pop key, push value;
279 
280         lua_pushnil(L);
281         lua_rawset(L, -3);            // t[value] = nil; pops key and value
282     }
283 
284     luaL_unref(L, -1, ref_idx);       // remove key and value in refs table
285                                       // note: this key will be used for the next wxluaR_ref()
286 
287     lua_pop(L, 1);                    // pop table
288 
289     return true;
290 }
291 
wxluaR_getref(lua_State * L,int ref_idx,void * lightuserdata_reg_key)292 bool LUACALL wxluaR_getref(lua_State *L, int ref_idx, void* lightuserdata_reg_key)
293 {
294     if (ref_idx == LUA_REFNIL)          // nothing to get
295         return false;
296 
297     lua_pushlightuserdata(L, lightuserdata_reg_key); // push key
298     lua_rawget(L, LUA_REGISTRYINDEX);                // pop key, push value (table)
299 
300     lua_rawgeti(L, -1, ref_idx);        // get t[ref_idx] = value; push value
301 
302     if (lua_isnil(L, -1))               // not a valid table key
303     {
304         lua_pop(L, 2);                  // pop nil and table
305         return false;
306     }
307 
308     lua_remove(L, -2);                  // remove table, leaving value on top
309 
310     return true; // return if table has a valid value and it's on the stack
311 }
312 
wxluaR_isrefed(lua_State * L,int stack_idx,void * lightuserdata_reg_key)313 int LUACALL wxluaR_isrefed(lua_State* L, int stack_idx, void* lightuserdata_reg_key)
314 {
315     int ref_idx = LUA_NOREF;
316 
317     lua_pushlightuserdata(L, lightuserdata_reg_key);    // push key
318     lua_rawget(L, LUA_REGISTRYINDEX);                   // pop key, push value (table)
319 
320     if (lightuserdata_reg_key == &wxlua_lreg_debug_refs_key)
321     {
322         // For this table we've pushed the value for a faster lookup
323         lua_pushvalue(L, ABS_LUA_STKIDX(stack_idx,1));  // push key (the value)
324         lua_rawget(L, -2);                              // get t[key] = value; pop key push value
325         ref_idx = (int)lua_tonumber(L, -1);
326 
327         if ((ref_idx == 0) && !lua_isnumber(L, -1))     // if !isnumber it returns 0 (faster)
328             ref_idx = LUA_NOREF;
329 
330         lua_pop(L, 2); // pop object we pushed and the ref table
331     }
332     else
333     {
334         // otherwise search through all the values
335         lua_pushnil(L);
336         while (lua_next(L, -2) != 0)
337         {
338             // value = -1, key = -2, table = -3, object = stack_idx before 3 added items
339             if (lua_equal(L, -1, ABS_LUA_STKIDX(stack_idx,3)))
340             {
341                 ref_idx = (int)lua_tonumber(L, -2);
342                 lua_pop(L, 2);               // pop key, value
343                 break;
344             }
345             else
346                 lua_pop(L, 1);               // pop value, lua_next will pop key at end
347         }
348 
349         lua_pop(L, 1); // pop ref table
350     }
351 
352     return ref_idx;
353 }
354 
355 // ----------------------------------------------------------------------------
356 // wxluaO_XXX - functions operate on the "Objects"
357 // ----------------------------------------------------------------------------
358 
wxluaO_addgcobject(lua_State * L,void * obj_ptr,int wxl_type)359 bool LUACALL wxluaO_addgcobject(lua_State *L, void *obj_ptr, int wxl_type)
360 {
361     lua_pushlightuserdata(L, &wxlua_lreg_gcobjects_key); // push key
362     lua_rawget(L, LUA_REGISTRYINDEX);                    // pop key, push value (table)
363 
364     // Check if it's already tracked since that means the weak udata table isn't working right
365     lua_pushlightuserdata(L, obj_ptr); // push key
366     lua_rawget(L, -2);                 // get t[key] = value, pops key
367 
368     if (!lua_isnil(L, -1))
369     {
370         lua_pop(L, 2); // pop table and value
371         wxCHECK_MSG(false, false, wxT("Tracking an object twice in wxluaO_addgcobject: ") + wxluaT_typename(L, wxl_type));
372         return false;
373     }
374 
375     lua_pop(L, 1); // pop nil
376 
377     // Then add it
378     lua_pushlightuserdata(L, obj_ptr);  // push key
379     lua_pushnumber(L, wxl_type);        // push value
380     lua_rawset(L, -3);                  // set t[key] = value, pops key and value
381 
382     lua_pop(L, 1); // pop table
383 
384     return true;
385 }
386 
wxluaO_deletegcobject(lua_State * L,int stack_idx,int flags)387 bool LUACALL wxluaO_deletegcobject(lua_State *L, int stack_idx, int flags)
388 {
389     void* udata   = lua_touserdata(L, stack_idx);
390     void* obj_ptr = wxlua_touserdata(L, stack_idx, true); // clear lua userdata's ptr
391 
392     if (obj_ptr == NULL) return false; // can happen
393 
394     bool delete_all = WXLUA_HASBIT(flags, WXLUA_DELETE_OBJECT_ALL);
395 
396     wxLuaBindClass *wxlClass = NULL;
397 
398     if (lua_getmetatable(L, stack_idx))
399     {
400         lua_pushlightuserdata(L, &wxlua_metatable_wxluabindclass_key); // push key
401         lua_rawget(L, -2);                                   // get t[key] = value; pop key push value
402         wxlClass = (wxLuaBindClass *)lua_touserdata(L, -1);
403         lua_pop(L, 2); // pop metatable and lightuserdata value
404     }
405 
406     // Remove the weak ref to it, will optionally clear all the metatables
407     // for an userdata created for this object to make them unusable.
408     int udata_count = wxluaO_untrackweakobject(L, delete_all ? NULL : udata, obj_ptr);
409 
410     if (delete_all || (udata_count < 1))
411     {
412         // remove any derived methods attached to this object
413         wxlua_removederivedmethods(L, obj_ptr);
414 
415         // check if we are really supposed to delete it
416         lua_pushlightuserdata(L, &wxlua_lreg_gcobjects_key); // push key
417         lua_rawget(L, LUA_REGISTRYINDEX);                    // pop key, push value (table)
418 
419         lua_pushlightuserdata(L, obj_ptr); // push key
420         lua_rawget(L, -2);                 // get t[key] = value, pops key
421 
422         if (wxlClass && lua_isnumber(L, -1)) // the wxLua type for it
423         {
424             lua_pop(L, 1); // pop number value
425 
426             lua_pushlightuserdata(L, obj_ptr); // push key
427             lua_pushnil(L);                    // push value
428             lua_rawset(L, -3);                 // set t[key] = value, pops key and value
429 
430             lua_pop(L, 1); // pop delobj table
431 
432             // delete the object using the function stored in the wxLuaBindClass
433             if (obj_ptr)
434                 wxlClass->delete_fn(&obj_ptr);
435             else
436                 return false;
437 
438             return true;
439         }
440         else
441         {
442             // no error message since we're called from wxlua_wxLuaBindClass__gc
443             // automatically for all our objects and this table stores which ones to delete
444             // so we don't want to have to check first and then call this.
445             lua_pop(L, 2); // pop nil and delobj
446         }
447     }
448 
449     return false;
450 }
451 
wxluaO_undeletegcobject(lua_State * L,void * obj_ptr)452 bool LUACALL wxluaO_undeletegcobject(lua_State *L, void *obj_ptr)
453 {
454     if (obj_ptr == NULL) return false;
455 
456     lua_pushlightuserdata(L, &wxlua_lreg_gcobjects_key); // push key
457     lua_rawget(L, LUA_REGISTRYINDEX);                    // pop key, push value (table)
458 
459     lua_pushlightuserdata(L, obj_ptr); // push key
460     lua_rawget(L, -2);                 // get t[key] = value, pops key
461 
462     if (lua_isnumber(L, -1)) // is the wxLua type of the object
463     {
464         lua_pop(L, 1); // pop number
465 
466         lua_pushlightuserdata(L, obj_ptr); // push key
467         lua_pushnil(L);                    // push value
468         lua_rawset(L, -3);                 // set t[key] = value, pops key and value
469 
470         lua_pop(L, 1); // pop delobj table
471         return true;
472     }
473     else
474         lua_pop(L, 2); // pop nil and gcobject table
475 
476     return false;
477 }
478 
wxluaO_isgcobject(lua_State * L,void * obj_ptr)479 bool LUACALL wxluaO_isgcobject(lua_State *L, void *obj_ptr)
480 {
481     lua_pushlightuserdata(L, &wxlua_lreg_gcobjects_key); // push key
482     lua_rawget(L, LUA_REGISTRYINDEX);                    // pop key, push value (table)
483 
484     lua_pushlightuserdata(L, obj_ptr); // push key
485     lua_rawget(L, -2);                 // get t[key] = value, pops key
486 
487     bool found = (0 != lua_isnumber(L, -1));
488     lua_pop(L, 2); // pop udata and table
489 
490     return found;
491 }
492 
wxluaO_getgcobjectinfo(lua_State * L)493 wxArrayString LUACALL wxluaO_getgcobjectinfo(lua_State *L)
494 {
495     wxArrayString arrStr;
496 
497     lua_pushlightuserdata(L, &wxlua_lreg_gcobjects_key); // push key
498     lua_rawget(L, LUA_REGISTRYINDEX);                    // pop key, push value (table)
499 
500     lua_pushnil(L);
501     while (lua_next(L, -2) != 0)
502     {
503         // value = -1, key = -2, table = -3
504         wxString name(wxT("wxObject?"));
505 
506         int wxl_type = (int)lua_tonumber(L, -1);
507         name = wxluaT_typename(L, wxl_type);
508 
509         arrStr.Add(wxString::Format(wxT("%s(%p)"), name.c_str(), lua_touserdata(L, -2)));
510 
511         lua_pop(L, 1); // pop value, lua_next will pop key at end
512     }
513 
514     lua_pop(L, 1); // pop table
515 
516     arrStr.Sort();
517     return arrStr;
518 }
519 
wxluaO_trackweakobject(lua_State * L,int udata_stack_idx,void * obj_ptr,int wxl_type)520 void LUACALL wxluaO_trackweakobject(lua_State *L, int udata_stack_idx, void *obj_ptr, int wxl_type)
521 {
522     lua_pushlightuserdata(L, &wxlua_lreg_weakobjects_key); // push key
523     lua_rawget(L, LUA_REGISTRYINDEX);                      // pop key, push value (the obj table)
524 
525     lua_pushlightuserdata(L, obj_ptr); // push key
526     lua_rawget(L, -2);
527 
528     if (lua_isnil(L, -1)) // not tracked yet, create new table to store items
529     {
530         lua_pop(L, 1); // pop nil
531 
532         lua_pushlightuserdata(L, obj_ptr);
533         lua_newtable(L);
534           lua_newtable(L);                    // metatable
535             lua_pushlstring(L, "__mode", 6);
536             lua_pushlstring(L, "v", 1);
537             lua_rawset(L, -3);                // set mode of main table
538           lua_setmetatable(L, -2);            // via the metatable
539         lua_rawset(L, -3);
540 
541         lua_pushlightuserdata(L, obj_ptr); // get the table back
542         lua_rawget(L, -2);
543     }
544     else
545     {
546         // check for dupes since that's what we're trying to avoid
547         lua_pushnumber(L, wxl_type);
548         lua_rawget(L, -2);
549         // this must never happen
550         if (!lua_isnil(L, -1))
551         {
552             wxFAIL_MSG(wxT("Trying to push userdata for object with same wxLua type twice"));
553         }
554         lua_pop(L, 1); // pop nil
555     }
556 
557     lua_pushnumber(L, wxl_type);
558     lua_pushvalue(L, ABS_LUA_STKIDX(udata_stack_idx, 3)); // push the Lua userdata as the value (note: weak valued table)
559     lua_rawset(L, -3);    // t[key] = value; pops key and value
560     lua_pop(L, 2);        // pop weakobj table and obj_ptr table
561 }
562 
wxluaO_untrackweakobject(lua_State * L,void * udata,void * obj_ptr)563 int LUACALL wxluaO_untrackweakobject(lua_State *L, void* udata, void *obj_ptr)
564 {
565     lua_pushlightuserdata(L, &wxlua_lreg_weakobjects_key); // push key
566     lua_rawget(L, LUA_REGISTRYINDEX);                      // pop key, push value (the object table)
567 
568     lua_pushlightuserdata(L, (void*)obj_ptr); // push key
569     lua_rawget(L, -2);                        // get t[key] = value; pop key push value
570 
571     int count = 0;
572 
573     if (lua_istable(L, -1))
574     {
575         // clear the metatables for the userdata
576         lua_pushnil(L);
577         while (lua_next(L, -2) != 0)
578         {
579             // value = -1, key = -2, table = -3
580             void *u = lua_touserdata(L, -1);
581 
582             if ((udata == NULL) || (udata == u))
583             {
584                 lua_pushnil(L);
585                 lua_setmetatable(L, -2); // remove value's metatable
586             }
587 
588             if (udata == u)
589             {
590                 lua_pop(L, 1);        // pop value
591 
592                 lua_pushvalue(L, -1); // copy key for next iteration
593                 lua_pushnil(L);
594                 lua_rawset(L, -4);    // set t[key] = nil to remove it
595             }
596             else
597             {
598                 ++count;       // only count ones that still exist
599                 lua_pop(L, 1); // pop value, leave key for next iteration
600             }
601         }
602 
603         lua_pop(L, 1); // pop obj_ptr table
604 
605         // If we've cleared everything then remove the table
606         if ((udata == NULL) || (count == 0))
607         {
608             count = 0;                                // removed them all
609             lua_pushlightuserdata(L, (void*)obj_ptr); // push key
610             lua_pushnil(L);                           // push value
611             lua_rawset(L, -3);                        // set t[key] = nil; pops key and value
612         }
613 
614         lua_pop(L, 1);                            // pop objects table
615     }
616     else
617         lua_pop(L, 2); // pop nil and weakobj table
618 
619     return count;
620 }
621 
wxluaO_istrackedweakobject(lua_State * L,void * obj_ptr,int wxl_type,bool push_on_stack)622 bool LUACALL wxluaO_istrackedweakobject(lua_State *L, void *obj_ptr, int wxl_type, bool push_on_stack)
623 {
624     lua_pushlightuserdata(L, &wxlua_lreg_weakobjects_key); // push key
625     lua_rawget(L, LUA_REGISTRYINDEX);   // pop key, push value (the obj table)
626 
627     lua_pushlightuserdata(L, obj_ptr); // push key
628     lua_rawget(L, -2);                 // get t[key] value; pop key push value
629 
630     if (lua_istable(L, -1))
631     {
632         lua_pushnumber(L, wxl_type); // push key
633         lua_rawget(L, -2);           // get t[key] = value; pops key
634 
635         // check if they've dynamic casted the object or if it was casted in C++
636         if (wxl_type == wxluaT_type(L, -1))
637         {
638             if (push_on_stack)
639             {
640                 lua_remove(L, -3); // remove the obj table, leave value on the stack
641                 lua_remove(L, -2); // remove table of userdata, leave value on the stack
642             }
643             else
644                 lua_pop(L, 3);
645 
646             return true;
647         }
648         else
649             lua_pop(L, 1); // pop the userdata that is not the right type
650     }
651 
652     lua_pop(L, 2); // pop the weakobj table and the nil.
653     return false;
654 }
655 
wxluaO_gettrackedweakobjectinfo(lua_State * L)656 wxArrayString LUACALL wxluaO_gettrackedweakobjectinfo(lua_State *L)
657 {
658     wxArrayString arrStr;
659 
660     lua_pushlightuserdata(L, &wxlua_lreg_weakobjects_key); // push key
661     lua_rawget(L, LUA_REGISTRYINDEX);                      // pop key, push value (table)
662 
663     lua_pushnil(L);
664     while (lua_next(L, -2) != 0)
665     {
666         // value = -1, key = -2, table = -3
667         void* obj_ptr = lua_touserdata(L, -2); // actually lightuserdata
668 
669         wxString name;
670 
671         // iterate the table of userdata
672         lua_pushnil(L);
673         while (lua_next(L, -2) != 0)
674         {
675             // value = -1, key = -2, table = -3
676             int wxl_type = (int)lua_tonumber(L, -2);
677             if (!name.IsEmpty()) name += wxT(", ");
678             name += wxString::Format(wxT("%s(%p, type=%d)"), wxluaT_typename(L, wxl_type).c_str(), lua_touserdata(L, -1), wxl_type);
679             lua_pop(L, 1); // pop value, lua_next will pop key at end
680         }
681 
682         arrStr.Add(wxString::Format(wxT("%p = %s"), obj_ptr, name.c_str()));
683 
684         lua_pop(L, 1); // pop value, lua_next will pop key at end
685     }
686 
687     lua_pop(L, 1); // pop table
688 
689     arrStr.Sort();
690     return arrStr;
691 }
692 
693 // ----------------------------------------------------------------------------
694 // wxluaW_XXX - functions operate on tracked wxWindows
695 // ----------------------------------------------------------------------------
696 
wxluaW_addtrackedwindow(lua_State * L,wxObject * wxobj)697 void LUACALL wxluaW_addtrackedwindow(lua_State *L, wxObject* wxobj)
698 {
699     if (!wxobj) return; // allow NULL w/o error
700 
701     // don't track these "windows" since they're supposed to be attached
702     // and their parents are not properly set so we can't tell if
703     // their parents are tracked.
704     if (wxDynamicCast(wxobj, wxMenuBar) != NULL) return;
705     if (wxDynamicCast(wxobj, wxToolBar) != NULL) return;
706 
707     wxWindow* win = wxDynamicCast(wxobj, wxWindow);
708 
709     // only need to track parent window, it deletes children for us
710     if (win && !wxluaW_istrackedwindow(L, win, true))
711     {
712         lua_pushlightuserdata(L, &wxlua_lreg_topwindows_key); // push key
713         lua_rawget(L, LUA_REGISTRYINDEX);                     // pop key, push value (table)
714 
715         lua_pushlightuserdata(L, win); // push key
716         lua_pushnumber(L, 1);          // push value
717         lua_rawset(L, -3);             // set t[key] = value, pops key and value
718 
719         lua_pop(L, 1); // pop topwindows table
720     }
721 }
722 
wxluaW_removetrackedwindow(lua_State * L,wxWindow * win)723 void LUACALL wxluaW_removetrackedwindow(lua_State *L, wxWindow* win)
724 {
725     lua_pushlightuserdata(L, &wxlua_lreg_topwindows_key); // push key
726     lua_rawget(L, LUA_REGISTRYINDEX);                     // pop key, push value (table)
727 
728     lua_pushlightuserdata(L, win); // push key
729     lua_pushnil(L);                // push value
730     lua_rawset(L, -3);             // set t[key] = value, pops key and value
731 
732     lua_pop(L, 1); // pop topwindows table
733 }
734 
wxluaW_istrackedwindow(lua_State * L,wxWindow * win,bool check_parents)735 bool LUACALL wxluaW_istrackedwindow(lua_State *L, wxWindow* win, bool check_parents)
736 {
737     lua_pushlightuserdata(L, &wxlua_lreg_topwindows_key); // push key
738     lua_rawget(L, LUA_REGISTRYINDEX);                     // pop key, push value (table)
739 
740     wxWindow* parent = win;
741 
742     while (parent)
743     {
744         lua_pushlightuserdata(L, parent); // push key
745         lua_rawget(L, -2);                // pop key, push value
746 
747         if (lua_isnumber(L, -1))
748         {
749             lua_pop(L, 2); // pop topwindows table and value
750             return true;
751         }
752 
753         parent = check_parents ? parent->GetParent() : NULL;
754         lua_pop(L, 1); // pop value (nil)
755     }
756 
757     lua_pop(L, 1); // pop topwindows table
758 
759     return false;
760 }
761 
wxluaW_gettrackedwindowinfo(lua_State * L)762 wxArrayString LUACALL wxluaW_gettrackedwindowinfo(lua_State *L)
763 {
764     wxArrayString arrStr;
765 
766     lua_pushlightuserdata(L, &wxlua_lreg_topwindows_key); // push key
767     lua_rawget(L, LUA_REGISTRYINDEX);                     // pop key, push value (table)
768 
769     lua_pushnil(L);
770     while (lua_next(L, -2) != 0)
771     {
772         // value = -1, key = -2, table = -3
773         wxWindow* win = (wxWindow*)lua_touserdata(L, -2);
774         wxCHECK_MSG(win, arrStr, wxT("Invalid wxWindow"));
775 
776         wxString name(win->GetClassInfo()->GetClassName());
777         arrStr.Add(wxString::Format(wxT("%s(%p id=%d)"), name.c_str(), win, win->GetId()));
778 
779         lua_pop(L, 1); // pop value, lua_next will pop key at end
780     }
781 
782     lua_pop(L, 1); // pop table
783 
784     arrStr.Sort();
785     return arrStr;
786 }
787 
788 // ----------------------------------------------------------------------------
789 // wxluaT_XXX - functions operate on the wxLua types
790 // ----------------------------------------------------------------------------
791 
wxluaT_newmetatable(lua_State * L,int wxl_type)792 int wxluaT_newmetatable(lua_State* L, int wxl_type)
793 {
794     lua_newtable(L);                                     // create a table for our new type
795     lua_pushlightuserdata(L, &wxlua_metatable_type_key); // push key
796     lua_pushnumber(L, wxl_type);                         // push value
797     lua_rawset(L, -3);                                   // set t[key] = value; pop key and value
798 
799     lua_pushlightuserdata(L, &wxlua_lreg_types_key);     // push key
800     lua_rawget(L, LUA_REGISTRYINDEX);                    // pop key, push value (table)
801 
802     // make sure that the Lua table array is contiguous
803     int len = (int)lua_objlen(L, -1);                    // get the length of the table
804     while (++len < wxl_type)
805     {
806         lua_pushnumber(L, 0);
807         lua_rawseti(L, -2, len);
808     }
809 
810     // It is not allowed to reregister this type
811     lua_rawgeti(L, -1, wxl_type);
812     int t = lua_type(L, -1);
813     wxCHECK_MSG((t == LUA_TNUMBER) || (t == LUA_TNIL), WXLUA_TUNKNOWN, wxT("Attempting to reregister wxLua type"));
814     lua_pop(L, 1);
815 
816     // Add the metatable to the wxlua_lreg_types_key table
817     lua_pushvalue(L, -2);                                // copy the metatable
818     lua_rawseti(L, -2, wxl_type);                        // add it, pops table
819     lua_pop(L, 1);                                       // pop wxlua_lreg_types_key table
820 
821     return wxl_type; // leave the table on the stack
822 }
823 
wxluaT_getmetatable(lua_State * L,int wxl_type)824 bool LUACALL wxluaT_getmetatable(lua_State* L, int wxl_type)
825 {
826     if (wxluaR_getref(L, wxl_type, &wxlua_lreg_types_key)) // get the metatable
827     {
828         if (lua_type(L, -1) == LUA_TTABLE)
829             return true;
830 
831         lua_pop(L, 1); // pop nil or 0 placeholder
832     }
833 
834     return false;
835 }
836 
wxluaT_setmetatable(lua_State * L,int wxl_type)837 bool LUACALL wxluaT_setmetatable(lua_State *L, int wxl_type)
838 {
839     if (wxluaT_getmetatable(L, wxl_type)) // get the metatable
840     {
841         // set it as the metatable of the object at the top of the stack
842         if (lua_setmetatable(L, -2)) // pops table
843             return true;
844         else
845         {
846             lua_pop(L, 1); // pop table
847             wxlua_error(L, "wxLua: Unable to set metatable in wxluaT_setmetatable.");
848         }
849     }
850     else
851         wxlua_error(L, "wxLua: Unable to get metatable in wxluaT_setmetatable.");
852 
853     return false;
854 }
855 
wxluaT_type(lua_State * L,int stack_idx)856 int LUACALL wxluaT_type(lua_State *L, int stack_idx)
857 {
858     int wxl_type = WXLUA_TUNKNOWN;
859     int ltype = lua_type(L, stack_idx);
860 
861     if ((ltype == LUA_TUSERDATA) && lua_getmetatable(L, stack_idx)) // see wxluaT_newmetatable()
862     {
863         lua_pushlightuserdata(L, &wxlua_metatable_type_key); // push key
864         lua_rawget(L, -2);                                   // get t[key] = value; pop key push value
865         wxl_type = (int)lua_tonumber(L, -1); // if !isnumber it returns 0 (check below is faster)
866 
867         // if it's not a number (it's probably nil) then it's someone else's userdata
868         if ((wxl_type == 0) && !lua_isnumber(L, -1))
869             wxl_type = WXLUA_TUSERDATA;
870 
871         lua_pop(L, 2); // pop metatable and wxl_type number
872     }
873     else
874         wxl_type = wxlua_luatowxluatype(ltype);
875 
876     return wxl_type;
877 }
878 
wxluaT_typename(lua_State * L,int wxl_type)879 wxString LUACALL wxluaT_typename(lua_State* L, int wxl_type)
880 {
881     // try to use wxString's ref counting and return this existing copy
882     static wxString s[14] = {
883         wxT("unknown"),
884         wxT("none"),
885         wxT("nil"),
886         wxT("boolean"),
887         wxT("lightuserdata"),
888         wxT("number"),
889         wxT("string"),
890         wxT("table"),
891         wxT("function"),
892         wxT("userdata"),
893         wxT("thread"),
894         wxT("integer"),
895         wxT("cfunction"),
896         wxT("pointer")
897     };
898 
899     // Check for real type or this is a predefined WXLUA_TXXX type
900     if ((L == NULL) || (WXLUAT_IS_LUAT(wxl_type)))
901     {
902         switch (wxl_type)
903         {
904             case WXLUA_TUNKNOWN :       return s[0];
905             case WXLUA_TNONE :          return s[1];
906             case WXLUA_TNIL :           return s[2];
907             case WXLUA_TBOOLEAN :       return s[3];
908             case WXLUA_TLIGHTUSERDATA : return s[4];
909             case WXLUA_TNUMBER :        return s[5];
910             case WXLUA_TSTRING :        return s[6];
911             case WXLUA_TTABLE :         return s[7];
912             case WXLUA_TFUNCTION :      return s[8];
913             case WXLUA_TUSERDATA :      return s[9];
914             case WXLUA_TTHREAD :        return s[10];
915 
916             case WXLUA_TINTEGER :       return s[11];
917             case WXLUA_TCFUNCTION :     return s[12];
918             case WXLUA_TPOINTER :       return s[13];
919         }
920     }
921     else
922     {
923         const wxLuaBindClass* wxlClass = wxluaT_getclass(L, wxl_type);
924         if (wxlClass)
925             return lua2wx(wxlClass->name);
926     }
927 
928     return wxT("Unknown wxLua Type?");
929 }
930 
wxluaT_gettypename(lua_State * L,int stack_idx)931 wxString LUACALL wxluaT_gettypename(lua_State* L, int stack_idx)
932 {
933     return wxluaT_typename(L, wxluaT_type(L, stack_idx));
934 }
935 
wxlua_luaL_typename(lua_State * L,int stack_idx)936 wxString LUACALL wxlua_luaL_typename(lua_State* L, int stack_idx)
937 {
938     // lua_typename(L, lua_type(L, stack_idx))
939     return lua2wx(luaL_typename(L, stack_idx));
940 }
941 
wxluaT_gettype(lua_State * L,const char * class_name)942 int LUACALL wxluaT_gettype(lua_State* L, const char* class_name)
943 {
944     const wxLuaBindClass* wxlClass = wxluaT_getclass(L, class_name);
945     if (wxlClass)
946         return *wxlClass->wxluatype;
947 
948     return WXLUA_TUNKNOWN;
949 }
950 
wxluaT_getclass(lua_State * L,int wxl_type)951 const wxLuaBindClass* LUACALL wxluaT_getclass(lua_State* L, int wxl_type)
952 {
953     // note: wxluaT_getmetatable() doesn't leave anything on the stack on failure
954     if (wxluaT_getmetatable(L, wxl_type))
955     {
956         // t[wxluatype] = { [bindclass_key] = lightuserdata wxLuaBindClass... (or nil if not a wxLua class type)
957         lua_pushlightuserdata(L, &wxlua_metatable_wxluabindclass_key);
958         lua_rawget(L, -2);
959         const wxLuaBindClass* wxlClass = (wxLuaBindClass *)lua_touserdata(L, -1); // actually lightuserdata
960 
961         lua_pop(L, 2); // pop type table and lightuserdata (or nil if none)
962 
963         return wxlClass;
964     }
965 
966     return NULL;
967 }
968 
wxluaT_getclass(lua_State * L,const char * class_name)969 const wxLuaBindClass* LUACALL wxluaT_getclass(lua_State* L, const char* class_name)
970 {
971     lua_pushlightuserdata(L, &wxlua_lreg_classes_key); // push key
972     lua_rawget(L, LUA_REGISTRYINDEX);                  // pop key, push value (table)
973 
974     lua_pushstring(L, class_name); // push key
975     lua_rawget(L, -2);             // get t["class_name"] = &wxLuaBindClass; pop key push value
976     const wxLuaBindClass* wxlClass = (wxLuaBindClass *)lua_touserdata(L, -1); // actually lightuserdata
977 
978     lua_pop(L, 2); // pop table and lightuserdata (or nil if none)
979 
980     return wxlClass; // may be NULL
981 }
982 
wxluaT_isuserdatatype(lua_State * L,int stack_idx,int wxl_type)983 bool wxluaT_isuserdatatype(lua_State* L, int stack_idx, int wxl_type)
984 {
985     int stack_type = wxluaT_type(L, stack_idx);
986 
987     if (wxlua_iswxuserdatatype(stack_type) &&
988         ((wxluatype_NULL == stack_type) || // FIXME, how to check when NULL is valid or not?
989         ((wxl_type == WXLUA_TSTRING) &&
990          ((wxluaT_isderivedtype(L, stack_type, *p_wxluatype_wxString) >= 0) ||
991           (wxluaT_isderivedtype(L, stack_type, *p_wxluatype_wxMemoryBuffer) >= 0))) ||
992         (wxluaT_isderivedtype(L, stack_type, wxl_type) >= 0)))
993         return true;
994 
995     return false;
996 }
997 
998 // Note about multiple inheritance in wxLua :
999 // See wxLuaBindClass::baseclass_vtable_offsets
1000 //
1001 // class A { int x; }; class B { int y; }; class AB : public A, public B { int z; };
1002 // AB ab; void *v_ab_a = (A*)&ab; void *v_ab_b = (B*)&ab;
1003 // long int dummy = 0;
1004 // long int AB_diff = ((long int)(B*)(AB*)&dummy) - ((long int)(A*)(AB*)&dummy);
1005 // wxPrintf(wxT("AB*=%p, A*=%p, B*=%p, B*-A*=%d\n"), &ab, v_ab_a, v_ab_b, AB_diff);
1006 // prints: "AB*=0x614dfc, A*=0x614dfc, B*=0x614e00, B*-A*=4"
1007 //
1008 // In order to call B's functions from a void* pointer to an AB object :
1009 // 1) Ideally, we cast to an AB object and the compiler will appropriately lookup
1010 //    and handle calls to B's functions.
1011 // 2) Cast to an AB object then to a B object where the compiler has already
1012 //    shifted the pointer and calls to B's functions are made directly.
1013 // 3) Explicitly shift the void* pointer to the AB object to where the vtable for
1014 //    B is. We now have an object that only knows about B and what B was derived from.
1015 //    I'm sure this is frowned upon by C++ enthusiasts.
1016 //
1017 // Ways of doing 1 and 2 in wxLua with C++ constraints, wxLua does #3 above.
1018 //
1019 // 1) wxLua would duplicate all the the binding functions for second
1020 //    and higher base classes and therefore each binding function will cast the
1021 //    void* we get from Lua to exactly the object type that it is. This is best,
1022 //    but it adds bloat.
1023 // 2) Come up with a clever way using overloaded functions, templates,
1024 //    or some sort of variant class to convert the void* pointer from Lua to
1025 //    type of object that it really is (we know by the wxLuaType integer)
1026 //    and then the binding function will cast it whatever base class it may be.
1027 //    The problem is that we really need to overload this casting function by
1028 //    return type, the function takes void* and returns ClassXYZ*, but this
1029 //    is not allowed in C++.
1030 // 3) Store an array of the offsets in each classes' wxLuaBindClass struct
1031 //    to the second or higher base classes and automatically add this offset in
1032 //    wxluaT_getuserdatatype(). The offsets are calculated at compile time
1033 //    using the AB_diff method above.
1034 //
1035 // Various ways to cast a void* pointer to the second base class :
1036 // void* v_ab = &ab;   // compilier doesn't know what v_ab is anymore
1037 // AB* ab = (AB*)v_ab; // ok since we cast right back to original type
1038 // A*  a  = (A*)v_ab;  // ok in GCC & MSVC since we are casting to 1st base class
1039 // B*  b  = (B*)v_ab;  // segfault! since B*'s vtable is +4 bytes as shown above
1040 // B*  b1 = (B*)(AB*)v_ab; // ok since compiler converts to AB* and knows that B* is shifted
1041 // B*  b2 = (B*)((long int)v_ab + AB_diff); // ok since we've shifted to B
1042 
1043 
1044 // forward declaration
1045 static int wxluaT_isderivedtype_recurser(const wxLuaBindClass *wxlClass, int base_wxl_type, int levels, int* baseclass_n);
1046 
wxluaT_getuserdatatype(lua_State * L,int stack_idx,int wxl_type)1047 void* LUACALL wxluaT_getuserdatatype(lua_State* L, int stack_idx, int wxl_type)
1048 {
1049     int stack_type = wxluaT_type(L, stack_idx);
1050 
1051     if (wxluatype_NULL == stack_type)
1052         return NULL;
1053 
1054     // Note: we directly use the recurser function since we may need the wxLuaBindClass
1055     //int level = wxluaT_isderivedtype(L, stack_type, wxl_type);
1056 
1057     int baseclass_n = 0;
1058     const wxLuaBindClass* wxlClass = wxluaT_getclass(L, stack_type);
1059     int level = wxluaT_isderivedtype_recurser(wxlClass, wxl_type, 0, &baseclass_n);
1060 
1061     if ((level >= 0) && (baseclass_n == 0))
1062     {
1063         // We can directly cast the void* pointer to the baseclass if baseclass_n == 0
1064         return wxlua_touserdata(L, stack_idx, false);
1065     }
1066     else if (level > 0)
1067     {
1068         // The class on the stack is derived from a second or higher base class
1069         // and therefore the pointer to the base class is not the same as the
1070         // pointer to the class object on the stack. We need to shift the
1071         // pointer by the number of bytes in wxLuaBindClass::baseclass_vtable_offsets
1072         // so that when it is casted to the base class we don't segfault.
1073         // Using 'long long' for 32 and 64 bit and compatibility with older compilers that don't have uintptr_t.
1074         unsigned long long o = (unsigned long long)wxlua_touserdata(L, stack_idx, false);
1075 
1076         if (wxlClass->baseclass_wxluatypes)
1077         {
1078             int i = 0;
1079             while (wxlClass->baseclass_wxluatypes[i]) // NULL terminated, the baseclass_vtable_offsets is not
1080             {
1081                 if (*(wxlClass->baseclass_wxluatypes[i]) == wxl_type)
1082                 {
1083                     o += wxlClass->baseclass_vtable_offsets[i];
1084                     break;
1085                 }
1086                 i++;
1087             }
1088         }
1089 
1090         return (void*)o;
1091     }
1092 
1093 
1094 
1095     wxlua_argerror(L, stack_idx, wxT("a '") + wxluaT_typename(L, wxl_type) + wxT("'"));
1096 
1097     return NULL;
1098 }
1099 
wxluaT_pushuserdatatype(lua_State * L,const void * obj_ptr,int wxl_type,bool track,bool allow_NULL)1100 bool LUACALL wxluaT_pushuserdatatype(lua_State* L, const void *obj_ptr, int wxl_type, bool track, bool allow_NULL)
1101 {
1102     // FIXME allow_NULL is a hack for the NULL userdata type.
1103 
1104     if (allow_NULL || (obj_ptr != NULL))
1105     {
1106         // First check to see if we've already pushed this object into Lua.
1107         // This avoids the problem of the gc deleting a returned pointer to a permanent object.
1108         // Test code is this:
1109         // il = wx.wxImageList(16,16); ... noteBook:SetImageList(il); ... local il2 = noteBook:GetImageList()
1110         // When il2 gets gc it will delete il even though il may still be valid and used by the notebook.
1111 
1112         if (wxluaO_istrackedweakobject(L, (void*)obj_ptr, wxl_type, true))
1113             return true;
1114 
1115         // if the object we are referencing is derived from wxWindow
1116         if (obj_ptr && (wxluaT_isderivedtype(L, wxl_type, *p_wxluatype_wxWindow) >= 0))
1117         {
1118             wxWindow* win = wxDynamicCast(obj_ptr, wxWindow); // double check that it's a wxWindow
1119             if (win != NULL)
1120             {
1121                 // check to make sure that we're not trying to attach another destroy callback
1122                 lua_pushlightuserdata(L, &wxlua_lreg_windestroycallbacks_key); // push key
1123                 lua_rawget(L, LUA_REGISTRYINDEX);                              // pop key, push value (table)
1124 
1125                 lua_pushlightuserdata(L, win); // push key
1126                 lua_rawget(L, -2);             // get t[key] = value; pops key
1127 
1128                 if (!lua_islightuserdata(L, -1))
1129                 {
1130                     // Connect the wxWindow to wxEVT_DESTROY callback so if Lua has
1131                     // a copy(s) of it we can clear the metatable when we get the
1132                     // event so we don't segfault if we try to access it by accident.
1133                     wxLuaState wxlState(L);
1134                     wxCHECK_MSG(wxlState.Ok(), false, wxT("Invalid wxLuaState"));
1135                     wxLuaWinDestroyCallback *pCallback =
1136                             new wxLuaWinDestroyCallback(wxlState, win);
1137 
1138                     if (pCallback == NULL)
1139                         wxlua_error(L, "wxLua: Out of memory creating wxLuaWinDestroyCallback.");
1140                     // assert should have been given in constructor so delete it
1141                     // since it's not attached as a callback user data
1142                     if (!pCallback->Ok())
1143                         delete pCallback;
1144                 }
1145 
1146                 lua_pop(L, 2); // pop windestroy table and value
1147             }
1148         }
1149 
1150         // Wrap the void* pointer in a newuserdata
1151         const void **ptr = (const void **)lua_newuserdata(L, sizeof(void *));
1152         if (ptr != NULL)
1153         {
1154             *ptr = obj_ptr;
1155             // try to get the object's references table and set the metatable to the object
1156             if (wxluaT_getmetatable(L, wxl_type))
1157             {
1158                 // pop the table and set it as the metatable for the newuserdata
1159                 lua_setmetatable(L, -2);
1160 
1161                 if (track)
1162                     wxluaO_trackweakobject(L, -1, (void*)obj_ptr, wxl_type);
1163 
1164                 return true; // leave value on the stack
1165             }
1166             else
1167                 wxlua_error(L, "wxLua: Unable to get metatable in wxluaT_pushuserdatatype.");
1168         }
1169         else
1170             wxlua_error(L, "wxLua: Out of memory");
1171     }
1172     else
1173     {
1174         lua_pushnil(L);
1175         return true;
1176     }
1177 
1178     return false;
1179 }
1180 
1181 // ----------------------------------------------------------------------------
1182 // Functions to get info about the wxLua types
1183 // ----------------------------------------------------------------------------
1184 
wxluaT_isderivedtype_recurser(const wxLuaBindClass * wxlClass,int base_wxl_type,int levels,int * baseclass_n)1185 static int wxluaT_isderivedtype_recurser(const wxLuaBindClass *wxlClass, int base_wxl_type, int levels, int* baseclass_n)
1186 {
1187     if (wxlClass != NULL)
1188     {
1189         // check that input isn't what we want first since this func is used in a couple places
1190         if (*wxlClass->wxluatype == base_wxl_type)
1191             return levels;
1192         else if (wxlClass->baseclassNames != NULL) // check baseclass by baseclass
1193         {
1194             for (size_t i = 0; wxlClass->baseclassNames[i]; ++i)
1195             {
1196                 // Note: base class may be NULL if lib/module containing it is not loaded
1197                 wxLuaBindClass* baseClass = wxlClass->baseBindClasses[i];
1198 
1199                 if (baseClass != NULL)
1200                 {
1201                     if (*baseClass->wxluatype == base_wxl_type)
1202                     {
1203                         if (baseclass_n) *baseclass_n = wxMax(*baseclass_n, (int)i);
1204                         return levels+1;
1205                     }
1206                     else
1207                     {
1208                         // create a new baseclass_n since we may be going down the wrong path
1209                         // and we do not want to change the original.
1210                         int baseclass_n_tmp = wxMax(baseclass_n ? *baseclass_n : 0, (int)i);
1211                         int ret = wxluaT_isderivedtype_recurser(baseClass, base_wxl_type, levels+1, &baseclass_n_tmp);
1212                         if (ret > -1)
1213                         {
1214                             // now set the baseclass_n var to the tmp one
1215                             if (baseclass_n) *baseclass_n = wxMax(baseclass_n_tmp, (int)i);
1216                             return ret;
1217                         }
1218                     }
1219                 }
1220             }
1221         }
1222     }
1223 
1224     return -1; // wxluatype is not derived from base_wxluatype
1225 }
1226 
wxluaT_isderivedtype(lua_State * L,int wxl_type,int base_wxl_type,int * baseclass_n)1227 int LUACALL wxluaT_isderivedtype(lua_State* L, int wxl_type, int base_wxl_type, int* baseclass_n)
1228 {
1229     // couldn't possibly be derived from each other
1230     if (!wxlua_iswxuserdatatype(wxl_type) || !wxlua_iswxuserdatatype(base_wxl_type))
1231         return -1;
1232 
1233     // These two types are the same, yes recurser also checks, but this is faster
1234     if (wxl_type == base_wxl_type)
1235         return 0;
1236 
1237     const wxLuaBindClass *wxlClass = wxluaT_getclass(L, wxl_type);
1238 
1239     if (baseclass_n != NULL) *baseclass_n = 0;
1240 
1241     return wxluaT_isderivedtype_recurser(wxlClass, base_wxl_type, 0, baseclass_n);
1242 }
1243 
wxluaT_isderivedclass(const wxLuaBindClass * wxlClass,const wxLuaBindClass * base_wxlClass,int * baseclass_n)1244 int LUACALL wxluaT_isderivedclass(const wxLuaBindClass* wxlClass, const wxLuaBindClass* base_wxlClass, int* baseclass_n)
1245 {
1246     // Ok if either is NULL to allow blindly calling this
1247     if ((wxlClass == NULL) || (base_wxlClass == NULL))
1248         return -1;
1249 
1250     // These two types are the same
1251     if (wxlClass->wxluatype == base_wxlClass->wxluatype) // comparing pointers
1252         return 0;
1253 
1254     if (baseclass_n != NULL) *baseclass_n = 0;
1255 
1256     return wxluaT_isderivedtype_recurser(wxlClass, *base_wxlClass->wxluatype, 1, baseclass_n);
1257 }
1258 
wxlua_iswxluatype(int luatype,int wxl_type,lua_State * L)1259 int LUACALL wxlua_iswxluatype(int luatype, int wxl_type, lua_State* L /* = NULL */)
1260 {
1261     int ret = -1; // unknown wxlua arg type
1262 
1263     switch (wxl_type)
1264     {
1265         case WXLUA_TNONE :
1266             ret = (luatype == LUA_TNONE) ? 1 : 0;
1267             break;
1268         case WXLUA_TNIL :
1269             ret = (luatype == LUA_TNIL) ? 1 : 0;
1270             break;
1271         case WXLUA_TBOOLEAN :
1272             // LUA_TNIL:    nil == false
1273             // LUA_TNUMBER: 0 == false as in C
1274             ret = ((luatype == LUA_TBOOLEAN) || (luatype == LUA_TNUMBER) || (luatype == LUA_TNIL)) ? 1 : 0;
1275             break;
1276         case WXLUA_TLIGHTUSERDATA:
1277             ret = (luatype == LUA_TLIGHTUSERDATA) ? 1 : 0;
1278             break;
1279         case WXLUA_TNUMBER :
1280             // LUA_TNIL:     evaluates to 0, too easy to have a typo
1281             // LUA_TSTRING:  will be 0 unless really a number "2"
1282             // LUA_TBOOLEAN: can't do (bool_val or 1)
1283             ret = ((luatype == LUA_TNUMBER) || (luatype == LUA_TBOOLEAN)) ? 1 : 0;
1284             break;
1285         case WXLUA_TSTRING :
1286             // LUA_TNIL:    too easy to have a variable typo, use (str or "")
1287             // LUA_TNUMBER: can convert easily, always works, but breaks overload bindings
1288             ret = (luatype == LUA_TSTRING) ? 1 : 0;
1289             break;
1290         case WXLUA_TTABLE :
1291             ret = (luatype == LUA_TTABLE) ? 1 : 0;
1292             break;
1293         case WXLUA_TFUNCTION :
1294             ret = (luatype == LUA_TFUNCTION) ? 1 : 0;
1295             break;
1296         case WXLUA_TUSERDATA :
1297             ret = (luatype == LUA_TUSERDATA) ? 1 : 0;
1298             break;
1299         case WXLUA_TTHREAD :
1300             ret = (luatype == LUA_TTHREAD) ? 1 : 0;
1301             break;
1302         case WXLUA_TINTEGER :
1303             // LUA_TNIL: evaluates to 0 so wx.ENUM_typo = 0
1304             ret = (luatype == LUA_TNUMBER) ? 1 : 0;
1305             break;
1306         case WXLUA_TCFUNCTION :
1307             ret = (luatype == LUA_TFUNCTION) ? 1 : 0;
1308             break;
1309         case WXLUA_TPOINTER :
1310             ret = (luatype == LUA_TLIGHTUSERDATA) || (luatype == LUA_TUSERDATA) ||
1311                   (luatype == LUA_TFUNCTION) || (luatype == LUA_TTABLE) ||
1312                   (luatype == LUA_TTHREAD) ? 1 : 0;
1313             break;
1314         case WXLUA_TANY :
1315             ret = 1; // any type is acceptable
1316             break;
1317     }
1318 
1319     // if we don't know the type (it's not predefined)
1320     if ((ret < 0) && L &&(luatype == LUA_TTABLE))
1321     {
1322         const wxLuaBindClass* wxlClass = wxluaT_getclass(L, wxl_type);
1323 
1324         if (wxluaT_isderivedclass(wxlClass, wxluaT_getclass(L, "wxArrayString")) >= 0)
1325             ret = 1;
1326         else if (wxluaT_isderivedclass(wxlClass, wxluaT_getclass(L, "wxSortedArrayString")) >= 0)
1327             ret = 1;
1328         else if (wxluaT_isderivedclass(wxlClass, wxluaT_getclass(L, "wxArrayInt")) >= 0)
1329             ret = 1;
1330         else if (wxluaT_isderivedclass(wxlClass, wxluaT_getclass(L, "wxArrayDouble")) >= 0)
1331             ret = 1;
1332     }
1333 
1334     return ret;
1335 }
1336 
wxlua_luatowxluatype(int luatype)1337 int wxlua_luatowxluatype(int luatype)
1338 {
1339     //int wxltype = LUAT_TO_WXLUAT(luatype);
1340     //if (!WXLUAT_IS_LUAT(wxltype))
1341     //    return WXLUA_TUNKNOWN;
1342     //return wxltype;
1343 
1344     switch (luatype)
1345     {
1346         case LUA_TNONE          : return WXLUA_TNONE;
1347         case LUA_TNIL           : return WXLUA_TNIL;
1348         case LUA_TBOOLEAN       : return WXLUA_TBOOLEAN;
1349         case LUA_TLIGHTUSERDATA : return WXLUA_TLIGHTUSERDATA;
1350         case LUA_TNUMBER        : return WXLUA_TNUMBER;
1351         case LUA_TSTRING        : return WXLUA_TSTRING;
1352         case LUA_TTABLE         : return WXLUA_TTABLE;
1353         case LUA_TFUNCTION      : return WXLUA_TFUNCTION;
1354         case LUA_TUSERDATA      : return WXLUA_TUSERDATA;
1355         case LUA_TTHREAD        : return WXLUA_TTHREAD;
1356         //case LUA_T???         : return WXLUA_TINTEGER;
1357         //case LUA_T???         : return WXLUA_TCFUNCTION;
1358         //case LUA_T???         : return WXLUA_TPOINTER;
1359     }
1360 
1361     return WXLUA_TUNKNOWN;
1362 }
1363 
wxlua_wxluatoluatype(int wxlarg)1364 int wxlua_wxluatoluatype(int wxlarg)
1365 {
1366     switch (wxlarg)
1367     {
1368         case WXLUA_TNONE :          return LUA_TNONE;
1369         case WXLUA_TNIL :           return LUA_TNIL;
1370         case WXLUA_TBOOLEAN :       return LUA_TBOOLEAN;
1371         case WXLUA_TLIGHTUSERDATA : return LUA_TLIGHTUSERDATA;
1372         case WXLUA_TNUMBER :        return LUA_TNUMBER;
1373         case WXLUA_TSTRING :        return LUA_TSTRING;
1374         case WXLUA_TTABLE :         return LUA_TTABLE;
1375         case WXLUA_TFUNCTION :      return LUA_TFUNCTION;
1376         case WXLUA_TUSERDATA :      return LUA_TUSERDATA;
1377         case WXLUA_TTHREAD :        return LUA_TTHREAD;
1378         case WXLUA_TINTEGER :       return LUA_TNUMBER;
1379         case WXLUA_TCFUNCTION :     return LUA_TFUNCTION;
1380         //case WXLUA_TPOINTER :       return LUA_T???; multiple types
1381     }
1382 
1383     return -1;
1384 }
1385 
wxlua_iswxstringtype(lua_State * L,int stack_idx)1386 bool wxlua_iswxstringtype(lua_State* L, int stack_idx)
1387 {
1388     // NOTE: If we ever allow numbers to be coerced to strings we must
1389     // change how we handle lua_tostring() calls since it will change a number
1390     // to a string on the stack. This could break people's code.
1391     if (wxlua_iswxluatype(lua_type(L, stack_idx), WXLUA_TSTRING) == 1)
1392         return true;
1393     else if (wxlua_iswxuserdata(L, stack_idx))
1394     {
1395         int wxl_type = wxluaT_type(L, stack_idx);
1396         return (wxluaT_isderivedtype(L, wxl_type, *p_wxluatype_wxString) >= 0);
1397     }
1398 
1399     return false;
1400 }
1401 
wxlua_getstringtypelen(lua_State * L,int stack_idx,size_t * len)1402 const char* LUACALL wxlua_getstringtypelen(lua_State *L, int stack_idx, size_t *len)
1403 {
1404     if (wxlua_isstringtype(L, stack_idx))
1405         return lua_tolstring(L, stack_idx, len);
1406     else if (wxlua_iswxuserdata(L, stack_idx))
1407     {
1408         int stack_type = wxluaT_type(L, stack_idx);
1409 
1410         if (wxluaT_isderivedtype(L, stack_type, *p_wxluatype_wxString) >= 0)
1411         {
1412             wxString* wxstr = (wxString*)wxlua_touserdata(L, stack_idx, false);
1413             wxCHECK_MSG(wxstr, NULL, wxT("Invalid userdata wxString"));
1414             const char *retp = (const char *)wx2lua(*wxstr);
1415             if (len != NULL)
1416                 *len = strlen(retp);
1417             return retp;
1418         }
1419         else if (wxluaT_isderivedtype(L, stack_type, *p_wxluatype_wxMemoryBuffer) >= 0)
1420         {
1421             wxMemoryBuffer * wxmem = (wxMemoryBuffer *)wxluaT_getuserdatatype(L, stack_idx, *p_wxluatype_wxMemoryBuffer);
1422             const char *datap = (const char *)wxmem->GetData();
1423             if (len != NULL)
1424                 *len = wxmem->GetDataLen();
1425             return datap;
1426         }
1427     }
1428 
1429     wxlua_argerror(L, stack_idx, wxT("a 'string' or 'wxString'"));
1430 
1431     return NULL;
1432 }
1433 
wxlua_getstringtype(lua_State * L,int stack_idx)1434 const char* LUACALL wxlua_getstringtype(lua_State *L, int stack_idx)
1435 {
1436     return wxlua_getstringtypelen(L, stack_idx, NULL);
1437 }
1438 
wxlua_getwxStringtype(lua_State * L,int stack_idx)1439 wxString LUACALL wxlua_getwxStringtype(lua_State *L, int stack_idx)
1440 {
1441     if (wxlua_isstringtype(L, stack_idx))
1442         return lua2wx(lua_tostring(L, stack_idx));
1443     else if (wxlua_iswxuserdata(L, stack_idx))
1444     {
1445         int stack_type = wxluaT_type(L, stack_idx);
1446 
1447         if (wxluaT_isderivedtype(L, stack_type, *p_wxluatype_wxString) >= 0)
1448         {
1449             wxString* wxstr = (wxString*)wxlua_touserdata(L, stack_idx, false);
1450             wxCHECK_MSG(wxstr, wxEmptyString, wxT("Invalid userdata wxString"));
1451             return *wxstr;
1452         }
1453     }
1454 
1455     wxlua_argerror(L, stack_idx, wxT("a 'string' or 'wxString'"));
1456 
1457     return wxEmptyString;
1458 }
1459 
wxlua_getbooleantype(lua_State * L,int stack_idx)1460 bool LUACALL wxlua_getbooleantype(lua_State *L, int stack_idx)
1461 {
1462     int l_type = lua_type(L, stack_idx);
1463 
1464     if (!wxlua_iswxluatype(l_type, WXLUA_TBOOLEAN))
1465         wxlua_argerror(L, stack_idx, wxT("a 'boolean'"));
1466 
1467     int num = 0;
1468     // we also allow 0 = false and !0 = true (Lua thinks 0 == true, i.e. !nil)
1469     if (l_type == LUA_TNUMBER)
1470         num = (int)lua_tonumber(L, stack_idx);
1471     else
1472         num = (int)lua_toboolean(L, stack_idx);
1473 
1474     return (num != 0);
1475 }
wxlua_getenumtype(lua_State * L,int stack_idx)1476 long LUACALL wxlua_getenumtype(lua_State *L, int stack_idx)
1477 {
1478     int l_type = lua_type(L, stack_idx);
1479 
1480     if (!wxlua_iswxluatype(l_type, WXLUA_TINTEGER))
1481         wxlua_argerror(L, stack_idx, wxT("an 'integer enum'"));
1482 
1483     // we don't allow bool or round, enums must strictly be integers
1484     double value = lua_tonumber(L, stack_idx);
1485     long long_value = (long)value;
1486 
1487     if (value != long_value)
1488         wxlua_argerror(L, stack_idx, wxT("an 'integer enum'"));
1489 
1490     return long_value;
1491 }
wxlua_getintegertype(lua_State * L,int stack_idx)1492 long LUACALL wxlua_getintegertype(lua_State *L, int stack_idx)
1493 {
1494     int l_type = lua_type(L, stack_idx);
1495 
1496     if (!wxlua_iswxluatype(l_type, WXLUA_TINTEGER))
1497         wxlua_argerror(L, stack_idx, wxT("an 'integer'"));
1498 
1499     double value = 0;
1500     // we also allow bool = 1/0 which Lua evaluates to nil in lua_tonumber
1501     if (l_type == LUA_TBOOLEAN)
1502         value = lua_toboolean(L, stack_idx) ? 1 : 0;
1503     else
1504         value = lua_tonumber(L, stack_idx);
1505 
1506     long long_value = (long)value;
1507 
1508     if (value != long_value)
1509         wxlua_argerror(L, stack_idx, wxT("an 'integer'"));
1510 
1511     return long_value;
1512 }
wxlua_getuintegertype(lua_State * L,int stack_idx)1513 unsigned long LUACALL wxlua_getuintegertype(lua_State *L, int stack_idx)
1514 {
1515     int l_type = lua_type(L, stack_idx);
1516 
1517     if (!wxlua_iswxluatype(l_type, WXLUA_TINTEGER))
1518         wxlua_argerror(L, stack_idx, wxT("an 'unsigned integer'"));
1519 
1520     double value = 0;
1521     // we also allow bool = 1/0 which Lua evaluates to nil in lua_tonumber
1522     if (l_type == LUA_TBOOLEAN)
1523         value = lua_toboolean(L, stack_idx) ? 1 : 0;
1524     else
1525         value = lua_tonumber(L, stack_idx);
1526 
1527     unsigned long ulong_value = (unsigned long)value;
1528 
1529     if ((value != ulong_value) || (value < 0))
1530         wxlua_argerror(L, stack_idx, wxT("an 'unsigned integer'"));
1531 
1532     return ulong_value;
1533 }
wxlua_getnumbertype(lua_State * L,int stack_idx)1534 double LUACALL wxlua_getnumbertype(lua_State *L, int stack_idx)
1535 {
1536     int l_type = lua_type(L, stack_idx);
1537 
1538     if (!wxlua_iswxluatype(l_type, WXLUA_TNUMBER))
1539         wxlua_argerror(L, stack_idx, wxT("a 'number'"));
1540 
1541     double value = 0;
1542     // we also allow bool = 1/0 which Lua evaluates to nil in lua_tonumber
1543     if (l_type == LUA_TBOOLEAN)
1544         value = lua_toboolean(L, stack_idx) ? 1 : 0;
1545     else
1546         value = lua_tonumber(L, stack_idx);
1547 
1548     return value;
1549 }
1550 
wxlua_getpointertype(lua_State * L,int stack_idx)1551 void* LUACALL wxlua_getpointertype(lua_State* L, int stack_idx)
1552 {
1553     int l_type = lua_type(L, stack_idx);
1554 
1555     if (!wxlua_iswxluatype(l_type, WXLUA_TPOINTER))
1556         wxlua_argerror(L, stack_idx, wxT("a 'pointer'"));
1557 
1558     void* value = (void *)lua_topointer(L, stack_idx);
1559 
1560     return value;
1561 }
1562 
wxlua_getchararray(lua_State * L,int stack_idx,int & count)1563 const char** LUACALL wxlua_getchararray(lua_State *L, int stack_idx, int &count)
1564 {
1565     const char **arrChar = NULL;
1566     count = 0;
1567 
1568     if (lua_istable(L, stack_idx))
1569     {
1570         int table_len = lua_objlen(L, stack_idx);
1571         if (table_len > 0)
1572             arrChar = new const char *[table_len];
1573 
1574         if (arrChar != NULL)
1575         {
1576             for (int n = 0; n < table_len; ++n)
1577             {
1578                 lua_rawgeti(L, stack_idx, n+1); // Lua array starts at 1
1579                 const char *s = wxlua_getstringtype(L, -1);
1580                 arrChar[n] = s; // share Lua string
1581                 lua_pop(L, 1);
1582             }
1583         }
1584 
1585         count = table_len;
1586     }
1587     else
1588         wxlua_argerror(L, stack_idx, wxT("a 'table' array of strings"));
1589 
1590     return arrChar;
1591 }
1592 
wxlua_getwxStringarray(lua_State * L,int stack_idx,int & count)1593 wxString* LUACALL wxlua_getwxStringarray(lua_State* L, int stack_idx, int& count)
1594 {
1595     wxString *strArray = NULL;
1596     count = 0; // zero it in case we do a long jmp
1597     wxLuaSmartwxArrayString arr(wxlua_getwxArrayString(L, stack_idx));
1598 
1599     count = (int)((wxArrayString&)arr).GetCount();
1600     strArray = new wxString[count];
1601     for (int n = 0; n < count; ++n)
1602         strArray[n] = ((wxArrayString&)arr)[n];
1603 
1604     return strArray;
1605 }
1606 
wxlua_getintarray(lua_State * L,int stack_idx,int & count)1607 int* LUACALL wxlua_getintarray(lua_State* L, int stack_idx, int& count)
1608 {
1609     int *intArray = NULL;
1610     count = 0; // zero it in case we do a long jmp
1611     wxLuaSmartwxArrayInt arr(wxlua_getwxArrayInt(L, stack_idx));
1612 
1613     count = (int)((wxArrayInt&)arr).GetCount();
1614     intArray = new int[count];
1615     for (int n = 0; n < count; ++n)
1616         intArray[n] = ((wxArrayInt&)arr)[n];
1617 
1618     return intArray;
1619 }
1620 
wxlua_getwxArrayString(lua_State * L,int stack_idx)1621 wxLuaSmartwxArrayString LUACALL wxlua_getwxArrayString(lua_State* L, int stack_idx)
1622 {
1623     wxLuaSmartwxArrayString arr(NULL, true); // will added to or replaced
1624     int count = -1;                          // used to check for failure
1625 
1626     if (lua_istable(L, stack_idx))
1627     {
1628         count = 0;
1629 
1630         while (1)
1631         {
1632             lua_rawgeti(L, stack_idx, count+1);
1633 
1634             if (wxlua_iswxstringtype(L, -1))
1635             {
1636                 ((wxArrayString&)arr).Add(wxlua_getwxStringtype(L, -1));
1637                 ++count;
1638 
1639                 lua_pop(L, 1);
1640             }
1641             else if (lua_isnil(L, -1))
1642             {
1643                 lua_pop(L, 1);
1644                 break;
1645             }
1646             else
1647             {
1648                 wxlua_argerror(L, stack_idx, wxT("a 'wxArrayString' or table array of strings"));
1649                 return arr;
1650             }
1651         }
1652     }
1653     else if (wxlua_iswxuserdata(L, stack_idx))
1654     {
1655         int arrstr_wxltype = wxluaT_gettype(L, "wxArrayString");
1656 
1657         if (wxluaT_isuserdatatype(L, stack_idx, arrstr_wxltype))
1658         {
1659             wxArrayString *arrStr = (wxArrayString *)wxluaT_getuserdatatype(L, stack_idx, arrstr_wxltype);
1660             if (arrStr)
1661             {
1662                 arr = wxLuaSmartwxArrayString(arrStr, false); // replace
1663                 count = arrStr->GetCount();
1664             }
1665         }
1666     }
1667 
1668     if (count < 0)
1669         wxlua_argerror(L, stack_idx, wxT("a 'wxArrayString' or table array of strings"));
1670 
1671     return arr;
1672 }
1673 
wxlua_getwxSortedArrayString(lua_State * L,int stack_idx)1674 wxLuaSmartwxSortedArrayString LUACALL wxlua_getwxSortedArrayString(lua_State* L, int stack_idx)
1675 {
1676     wxLuaSmartwxSortedArrayString arr(NULL, true); // will be replaced
1677     int count = -1;                                // used to check for failure
1678 
1679     if (lua_istable(L, stack_idx))
1680     {
1681         wxLuaSmartwxArrayString a = wxlua_getwxArrayString(L, stack_idx);
1682         arr = wxLuaSmartwxSortedArrayString(new wxSortedArrayString(a), true);
1683         count = 0;
1684     }
1685     else if (wxlua_iswxuserdata(L, stack_idx))
1686     {
1687         int arrstr_wxltype = wxluaT_gettype(L, "wxArrayString");
1688 
1689         if (wxluaT_isuserdatatype(L, stack_idx, arrstr_wxltype))
1690         {
1691             wxSortedArrayString *arrStr = (wxSortedArrayString *)wxluaT_getuserdatatype(L, stack_idx, arrstr_wxltype);
1692             if (arrStr)
1693             {
1694                 arr = wxLuaSmartwxSortedArrayString(arrStr, false); // replace
1695                 count = arrStr->GetCount();
1696             }
1697         }
1698     }
1699 
1700     if (count < 0)
1701         wxlua_argerror(L, stack_idx, wxT("a 'wxArrayString' or table array of strings"));
1702 
1703     return arr;
1704 }
1705 
wxlua_getwxArrayInt(lua_State * L,int stack_idx)1706 wxLuaSmartwxArrayInt LUACALL wxlua_getwxArrayInt(lua_State* L, int stack_idx)
1707 {
1708     wxLuaSmartwxArrayInt arr(NULL, true); // will be replaced
1709     int count = -1;                       // used to check for failure
1710 
1711     if (lua_istable(L, stack_idx))
1712     {
1713         count = 0;
1714 
1715         while(1)
1716         {
1717             lua_rawgeti(L, stack_idx, count+1);
1718 
1719             if (wxlua_isnumbertype(L, -1))
1720             {
1721                 ((wxArrayInt&)arr).Add((int)lua_tonumber(L, -1));
1722                 ++count;
1723 
1724                 lua_pop(L, 1);
1725             }
1726             else if (lua_isnil(L, -1))
1727             {
1728                 lua_pop(L, 1);
1729                 break;
1730             }
1731             else
1732             {
1733                 wxlua_argerror(L, stack_idx, wxT("a 'wxArrayInt' or a table array of integers"));
1734                 return arr;
1735             }
1736         }
1737     }
1738     else if (wxlua_iswxuserdata(L, stack_idx))
1739     {
1740         int arrint_wxltype = wxluaT_gettype(L, "wxArrayInt");
1741 
1742         if (wxluaT_isuserdatatype(L, stack_idx, arrint_wxltype))
1743         {
1744             wxArrayInt *arrInt = (wxArrayInt *)wxluaT_getuserdatatype(L, stack_idx, arrint_wxltype);
1745             if (arrInt)
1746             {
1747                 arr = wxLuaSmartwxArrayInt(arrInt, false); // replace
1748                 count = arrInt->GetCount();
1749             }
1750         }
1751     }
1752 
1753     if (count < 0)
1754         wxlua_argerror(L, stack_idx, wxT("a 'wxArrayInt' or a table array of integers"));
1755 
1756     return arr;
1757 }
1758 
wxlua_getwxArrayDouble(lua_State * L,int stack_idx)1759 wxLuaSmartwxArrayDouble LUACALL wxlua_getwxArrayDouble(lua_State* L, int stack_idx)
1760 {
1761     wxLuaSmartwxArrayDouble arr(NULL, true); // will be replaced
1762     int count = -1;                       // used to check for failure
1763 
1764     if (lua_istable(L, stack_idx))
1765     {
1766         count = 0;
1767 
1768         while(1)
1769         {
1770             lua_rawgeti(L, stack_idx, count+1);
1771 
1772             if (wxlua_isnumbertype(L, -1))
1773             {
1774                 ((wxArrayDouble&)arr).Add(lua_tonumber(L, -1));
1775                 ++count;
1776 
1777                 lua_pop(L, 1);
1778             }
1779             else if (lua_isnil(L, -1))
1780             {
1781                 lua_pop(L, 1);
1782                 break;
1783             }
1784             else
1785             {
1786                 wxlua_argerror(L, stack_idx, wxT("a 'wxArrayDouble' or a table array of integers"));
1787                 return arr;
1788             }
1789         }
1790     }
1791     else if (wxlua_iswxuserdata(L, stack_idx))
1792     {
1793         int arrdouble_wxltype = wxluaT_gettype(L, "wxArrayDouble");
1794 
1795         if (wxluaT_isuserdatatype(L, stack_idx, arrdouble_wxltype))
1796         {
1797             wxArrayDouble *arrDouble = (wxArrayDouble *)wxluaT_getuserdatatype(L, stack_idx, arrdouble_wxltype);
1798             if (arrDouble)
1799             {
1800                 arr = wxLuaSmartwxArrayDouble(arrDouble, false); // replace
1801                 count = arrDouble->GetCount();
1802             }
1803         }
1804     }
1805 
1806     if (count < 0)
1807         wxlua_argerror(L, stack_idx, wxT("a 'wxArrayDouble' or a table array of numbers"));
1808 
1809     return arr;
1810 }
1811 
wxlua_getwxPointArray(lua_State * L,int stack_idx)1812 wxLuaSharedPtr<std::vector<wxPoint> > LUACALL wxlua_getwxPointArray(lua_State* L, int stack_idx)
1813 {
1814     wxLuaSharedPtr<std::vector<wxPoint> > pointArray(new std::vector<wxPoint>);
1815     int count = -1;       // used to check for failure
1816     int is_xy_table = -1; // is it a table with x,y fields or a number array {1,2}
1817 
1818     if (lua_istable(L, stack_idx))
1819     {
1820         count = lua_objlen(L, stack_idx); /* get size of table */
1821 
1822         double x, y;
1823         for (int i = 1; i <= count; ++i)
1824         {
1825             lua_rawgeti(L, stack_idx, i); /* get next point as {x,y} */
1826             int t = wxluaT_type(L, -1);
1827             if (t == WXLUA_TTABLE)
1828             {
1829                 // First time, check how it was formatted
1830                 if (is_xy_table == -1)
1831                 {
1832                     lua_rawgeti(L, -1, 1);
1833                     is_xy_table = (lua_isnumber(L, -1) == 0) ? 1 : 0;
1834                     lua_pop(L, 1);
1835                 }
1836 
1837                 if (is_xy_table == 1)
1838                 {
1839                     lua_pushstring(L, "x");
1840                     lua_rawget(L, -2);
1841                     if (!lua_isnumber(L, -1))
1842                         wxlua_argerror(L, stack_idx, wxT("a 'number' for x-coordinate of a wxPoint array, valid tables are {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint(1,2),,...}."));
1843                     x = lua_tonumber(L, -1);
1844                     lua_pop(L, 1);
1845 
1846                     lua_pushstring(L, "y");
1847                     lua_rawget(L, -2);
1848                     if (!lua_isnumber(L, -1))
1849                         wxlua_argerror(L, stack_idx, wxT("a 'number' for y-coordinate of a wxPoint array, valid tables are {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint(1,2),,...}."));
1850                     y = lua_tonumber(L, -1);
1851                     lua_pop(L, 1);
1852                 }
1853                 else
1854                 {
1855                     lua_rawgeti(L, -1, 1);
1856                     if (!lua_isnumber(L, -1))
1857                         wxlua_argerror(L, stack_idx, wxT("a 'number' for [1] index (x-coordinate) of a wxPoint array, valid tables {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint(1,2),,...}."));
1858                     x = lua_tonumber(L, -1);
1859                     lua_pop(L, 1);
1860 
1861                     lua_rawgeti(L, -1, 2);
1862                     if (!lua_isnumber(L, -1))
1863                         wxlua_argerror(L, stack_idx, wxT("a 'number' for [2] index (y-coordinate) of a wxPoint array, valid tables {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint(1,2),,...}."));
1864                     y = lua_tonumber(L,-1);
1865                     lua_pop(L, 1);
1866                 }
1867 
1868                 pointArray->push_back(wxPoint((int)x, (int)y));
1869             }
1870             else if (t == *p_wxluatype_wxPoint)
1871             {
1872                 const wxPoint* point = (const wxPoint *)wxluaT_getuserdatatype(L, -1, *p_wxluatype_wxPoint);
1873                 pointArray->push_back(*point);
1874             }
1875             else
1876             {
1877                 wxlua_argerror(L, stack_idx, wxT("a Lua table of 'wxPoints', valid tables {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint(1,2),,...}."));
1878                 return pointArray;
1879             }
1880 
1881             lua_pop(L, 1);
1882         }
1883     }
1884 /*
1885 
1886     // Binding the wxPointList is a problem since we have to worry about
1887     // wxList::DeleteContents() and who calls it, it'll be accident waiting to happen.
1888 
1889     else if (wxlua_iswxuserdata(L, stack_idx))
1890     {
1891         int pointlist_wxltype = wxluaT_gettype(L, "wxPointList");
1892 
1893         if (wxluaT_isuserdatatype(L, stack_idx, pointlist_wxltype))
1894         {
1895             wxPointList *ptList = (wxPointList *)wxluaT_getuserdatatype(L, stack_idx, pointlist_wxltype);
1896             if (ptList)
1897             {
1898                 //pointArray.reset(ptList);
1899                 //pointArray.SetDelete(false);
1900                 count = ptList->GetCount();
1901             }
1902         }
1903     }
1904 */
1905 
1906     if (count < 0)
1907         wxlua_argerror(L, stack_idx, wxT("a Lua table of 'wxPoints', valid tables {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint(1,2),,...}."));
1908 
1909     return pointArray;
1910 }
1911 
wxlua_getwxPoint2DDoubleArray(lua_State * L,int stack_idx)1912 wxLuaSharedPtr<std::vector<wxPoint2DDouble> > LUACALL wxlua_getwxPoint2DDoubleArray(lua_State* L, int stack_idx)
1913 {
1914     wxLuaSharedPtr<std::vector<wxPoint2DDouble> > pointArray(new std::vector<wxPoint2DDouble>);
1915     int count = -1;       // used to check for failure
1916     int is_xy_table = -1; // is it a table with x,y fields or a number array {1,2}
1917 
1918     if (lua_istable(L, stack_idx))
1919     {
1920         count = lua_objlen(L, stack_idx); /* get size of table */
1921 
1922         double x, y;
1923         for (int i = 1; i <= count; ++i)
1924         {
1925             lua_rawgeti(L, stack_idx, i); /* get next point as {x,y} */
1926             int t = wxluaT_type(L, -1);
1927             if (t == WXLUA_TTABLE)
1928             {
1929                 // First time, check how it was formatted
1930                 if (is_xy_table == -1)
1931                 {
1932                     lua_rawgeti(L, -1, 1);
1933                     is_xy_table = (lua_isnumber(L, -1) == 0) ? 1 : 0;
1934                     lua_pop(L, 1);
1935                 }
1936 
1937                 if (is_xy_table == 1)
1938                 {
1939                     lua_pushstring(L, "x");
1940                     lua_rawget(L, -2);
1941                     if (!lua_isnumber(L, -1))
1942                         wxlua_argerror(L, stack_idx, wxT("a 'number' for x-coordinate of a wxPoint2DDouble array, valid tables are {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint2DDouble(1,2),,...}."));
1943                     x = lua_tonumber(L, -1);
1944                     lua_pop(L, 1);
1945 
1946                     lua_pushstring(L, "y");
1947                     lua_rawget(L, -2);
1948                     if (!lua_isnumber(L, -1))
1949                         wxlua_argerror(L, stack_idx, wxT("a 'number' for y-coordinate of a wxPoint2DDouble array, valid tables are {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint2DDouble(1,2),,...}."));
1950                     y = lua_tonumber(L, -1);
1951                     lua_pop(L, 1);
1952                 }
1953                 else
1954                 {
1955                     lua_rawgeti(L, -1, 1);
1956                     if (!lua_isnumber(L, -1))
1957                         wxlua_argerror(L, stack_idx, wxT("a 'number' for [1] index (x-coordinate) of a wxPoint2DDouble array, valid tables {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint2DDouble(1,2),,...}."));
1958                     x = lua_tonumber(L, -1);
1959                     lua_pop(L, 1);
1960 
1961                     lua_rawgeti(L, -1, 2);
1962                     if (!lua_isnumber(L, -1))
1963                         wxlua_argerror(L, stack_idx, wxT("a 'number' for [2] index (y-coordinate) of a wxPoint2DDouble array, valid tables {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint2DDouble(1,2),,...}."));
1964                     y = lua_tonumber(L,-1);
1965                     lua_pop(L, 1);
1966                 }
1967 
1968                 pointArray->push_back(wxPoint2DDouble(x, y));
1969             }
1970             else if (t == *p_wxluatype_wxPoint2DDouble)
1971             {
1972                 const wxPoint* point = (const wxPoint *)wxluaT_getuserdatatype(L, -1, *p_wxluatype_wxPoint);
1973                 pointArray->push_back(*point);
1974             }
1975             else
1976             {
1977                 wxlua_argerror(L, stack_idx, wxT("a Lua table of 'wxPoint2DDoubles', valid tables {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint2DDouble(1,2),,...}."));
1978                 return pointArray;
1979             }
1980 
1981             lua_pop(L, 1);
1982         }
1983     }
1984     if (count < 0)
1985         wxlua_argerror(L, stack_idx, wxT("a Lua table of 'wxPoint2DDoubles', valid tables {{1,2},...}, {{x=1,y=2},...}, or {wx.wxPoint2DDouble(1,2),,...}."));
1986 
1987     return pointArray;
1988 }
1989 
wxlua_pushwxArrayStringtable(lua_State * L,const wxArrayString & strArray)1990 int LUACALL wxlua_pushwxArrayStringtable(lua_State *L, const wxArrayString &strArray)
1991 {
1992     size_t idx, count = strArray.GetCount();
1993     lua_createtable(L, count, 0);
1994 
1995     for (idx = 0; idx < count; ++idx)
1996     {
1997         wxlua_pushwxString(L, strArray[idx]);
1998         lua_rawseti(L, -2, idx + 1);
1999     }
2000     return idx;
2001 }
2002 
wxlua_pushwxArrayInttable(lua_State * L,const wxArrayInt & intArray)2003 int LUACALL wxlua_pushwxArrayInttable(lua_State *L, const wxArrayInt &intArray)
2004 {
2005     size_t idx, count = intArray.GetCount();
2006     lua_createtable(L, count, 0);
2007 
2008     for (idx = 0; idx < count; ++idx)
2009     {
2010 #if LUA_VERSION_NUM >= 503
2011         lua_pushinteger(L, intArray[idx]);
2012 #else
2013         lua_pushnumber(L, intArray[idx]);
2014 #endif
2015         lua_rawseti(L, -2, idx + 1);
2016     }
2017     return idx;
2018 }
2019 
wxlua_pushwxArrayDoubletable(lua_State * L,const wxArrayDouble & doubleArray)2020 int LUACALL wxlua_pushwxArrayDoubletable(lua_State *L, const wxArrayDouble &doubleArray)
2021 {
2022     size_t idx, count = doubleArray.GetCount();
2023     lua_createtable(L, count, 0);
2024 
2025     for (idx = 0; idx < count; ++idx)
2026     {
2027         lua_pushnumber(L, doubleArray[idx]);
2028         lua_rawseti(L, -2, idx + 1);
2029     }
2030     return idx;
2031 }
2032 
wxlua_pushwxString(lua_State * L,const wxString & str)2033 void LUACALL wxlua_pushwxString(lua_State* L, const wxString& str)
2034 {
2035     lua_pushstring(L, wx2lua(str));
2036 }
2037 
wxlua_concatwxArrayString(const wxArrayString & arr,const wxString & sep)2038 wxString wxlua_concatwxArrayString(const wxArrayString& arr, const wxString& sep)
2039 {
2040     wxString s;
2041     size_t n, count = arr.GetCount();
2042     for (n = 0; n < count; ++n)
2043     {
2044         s += arr[n];
2045         if (n < count - 1) s += sep;
2046     }
2047 
2048     return s;
2049 }
2050 
wxlua_pushargs(lua_State * L,wxChar ** argv,int argc,int start_n)2051 int wxlua_pushargs(lua_State* L, wxChar **argv, int argc, int start_n)
2052 {
2053     if (argc == 0) return 0;
2054 
2055     int i = 0;
2056     int narg = argc - (start_n + 1);  // number of arguments to the script
2057     luaL_checkstack(L, narg + 3, "too many arguments to script");
2058     for (i = start_n+1; i < argc; i++)
2059         lua_pushstring(L, wx2lua(argv[i]));
2060 
2061     lua_createtable(L, narg, start_n + 1);
2062 
2063     for (i = 0; i < argc; i++)
2064     {
2065         lua_pushstring(L, wx2lua(argv[i]));
2066         lua_rawseti(L, -2, i - start_n);
2067     }
2068 
2069     lua_setglobal(L, "arg");
2070 
2071     return narg;
2072 }
2073 
2074 //----------------------------------------------------------------------------
2075 // Derived class member functions for classes in wxLua
2076 //----------------------------------------------------------------------------
2077 
wxlua_setderivedmethod(lua_State * L,void * obj_ptr,const char * method_name,wxLuaObject * wxlObj)2078 bool LUACALL wxlua_setderivedmethod(lua_State* L, void *obj_ptr, const char *method_name, wxLuaObject* wxlObj)
2079 {
2080     lua_pushlightuserdata(L, &wxlua_lreg_derivedmethods_key); // push key
2081     lua_rawget( L, LUA_REGISTRYINDEX );                       // pop key, push value (table)
2082 
2083     lua_pushlightuserdata(L, (void *)obj_ptr); // push key
2084     lua_rawget(L, -2);                         // get t[key] = value, pop key push value
2085 
2086     if (!lua_istable(L, -1))
2087     {
2088         lua_pop(L, 1); // pop nil value
2089 
2090         // add new table for this object
2091         lua_pushlightuserdata(L, (void *)obj_ptr); // push key
2092         lua_newtable(L);                           // push value
2093         lua_rawset(L, -3);                         // set t[key] = value; pops key and value
2094 
2095         // put the new table back on the top of the stack
2096         lua_pushlightuserdata(L, (void *)obj_ptr);
2097         lua_rawget(L, -2);
2098     }
2099     else
2100     {
2101         // see if there already is a method
2102         lua_pushstring( L, method_name );
2103         lua_rawget(L, -2);
2104 
2105         if (lua_islightuserdata(L, -1))
2106         {
2107             // already have a method, delete it before replacing it
2108             wxLuaObject* o = (wxLuaObject*)lua_touserdata( L, -1 );
2109             o->RemoveReference(L);
2110             delete o;
2111         }
2112 
2113         lua_pop(L, 1); // pop the deleted old object, or nil
2114     }
2115 
2116     lua_pushstring( L, method_name );        // push key
2117     lua_pushlightuserdata(L, (void*)wxlObj); // push value
2118     lua_rawset(L, -3);                       // set t[key] = value; pops key and value
2119 
2120     lua_pop(L, 2); // pop the object and overridden function table
2121 
2122     return true;
2123 }
wxlua_hasderivedmethod(lua_State * L,const void * obj_ptr,const char * method_name,bool push_method)2124 bool LUACALL wxlua_hasderivedmethod(lua_State* L, const void *obj_ptr, const char *method_name, bool push_method)
2125 {
2126     bool found = false;
2127     wxLuaObject* wxlObj = NULL;
2128 
2129     lua_pushlightuserdata(L, &wxlua_lreg_derivedmethods_key);
2130     lua_rawget( L, LUA_REGISTRYINDEX ); // pop key, push table
2131 
2132     lua_pushlightuserdata(L, (void *)obj_ptr);
2133     lua_rawget(L, -2); // pop key, push table or nil
2134 
2135     if (lua_istable(L, -1))
2136     {
2137         // see if there is a method with the same name
2138         lua_pushstring( L, method_name );
2139         lua_rawget(L, -2);
2140 
2141         if (lua_islightuserdata(L, -1))
2142             wxlObj = (wxLuaObject*)lua_touserdata( L, -1 );
2143 
2144         lua_pop(L, 1); // pop the method object or nil
2145     }
2146 
2147     lua_pop(L, 2); // pop registry table and object table or nil
2148 
2149     if (wxlObj != NULL)
2150     {
2151         // if we've got the object, put it on top of the stack
2152         if (push_method && wxlObj->GetObject(L))
2153             found = true;
2154         else if (!push_method)
2155             found = true;
2156     }
2157 
2158     return found;
2159 }
wxlua_removederivedmethods(lua_State * L,void * obj_ptr)2160 bool LUACALL wxlua_removederivedmethods(lua_State* L, void *obj_ptr)
2161 {
2162     bool found = false;
2163 
2164     lua_pushlightuserdata(L, &wxlua_lreg_derivedmethods_key);
2165     lua_rawget( L, LUA_REGISTRYINDEX ); // pop key, push table
2166 
2167     lua_pushlightuserdata(L, (void *)obj_ptr);
2168     lua_rawget(L, -2); // pop key, push table or nil
2169 
2170     if (lua_istable(L, -1))
2171     {
2172         found = true;
2173 
2174         // delete all of the derived methods we've pushed
2175         lua_pushnil(L);
2176         while (lua_next(L, -2) != 0)
2177         {
2178             // value at -1, key at -2, table at -3
2179             if (lua_islightuserdata(L, -1))
2180             {
2181                 wxLuaObject* o = (wxLuaObject*)lua_touserdata(L, -1);
2182                 o->RemoveReference(L);
2183                 delete o;
2184             }
2185 
2186             lua_pop(L, 1); // remove value; keep key for next iteration
2187         }
2188 
2189         lua_pop(L, 1);     // pop the obj table
2190 
2191         lua_pushlightuserdata(L, (void *)obj_ptr); // push key
2192         lua_pushnil(L);                            // push value, to remove it
2193         lua_rawset(L, -3);                         // set t[key] = value; pop key and value
2194 
2195         lua_pop(L, 1); // pop the derived table
2196     }
2197     else
2198         lua_pop(L, 2); // pop the derived table and nil for the obj table
2199 
2200     return found;
2201 }
2202 
2203 //----------------------------------------------------------------------------
2204 // Other functions for wxLua's keys in the
2205 //----------------------------------------------------------------------------
2206 
wxlua_getcallbaseclassfunction(lua_State * L)2207 bool LUACALL wxlua_getcallbaseclassfunction(lua_State* L)
2208 {
2209     lua_pushlightuserdata(L, &wxlua_lreg_callbaseclassfunc_key);
2210     lua_rawget( L, LUA_REGISTRYINDEX ); // pop key, push bool
2211 
2212     bool call_base = (0 != lua_toboolean(L, -1)); // nil == 0 too
2213     lua_pop(L, 1);                               // pop bool
2214 
2215     return call_base;
2216 }
2217 
wxlua_setcallbaseclassfunction(lua_State * L,bool call_base)2218 void LUACALL wxlua_setcallbaseclassfunction(lua_State* L, bool call_base)
2219 {
2220     lua_pushlightuserdata(L, &wxlua_lreg_callbaseclassfunc_key);
2221     lua_pushboolean(L, call_base);
2222     lua_rawset( L, LUA_REGISTRYINDEX ); // pop key and bool
2223 }
2224 
wxlua_getwxeventtype(lua_State * L)2225 wxEventType LUACALL wxlua_getwxeventtype(lua_State* L)
2226 {
2227     lua_pushlightuserdata(L, &wxlua_lreg_wxeventtype_key);
2228     lua_rawget( L, LUA_REGISTRYINDEX ); // pop key, push bool
2229 
2230     wxEventType evt_type = (wxEventType)lua_tonumber(L, -1);
2231     lua_pop(L, 1); // pop number
2232 
2233     return evt_type;
2234 }
2235 
wxlua_setwxeventtype(lua_State * L,wxEventType evt_type)2236 void LUACALL wxlua_setwxeventtype(lua_State* L, wxEventType evt_type)
2237 {
2238     lua_pushlightuserdata(L, &wxlua_lreg_wxeventtype_key);
2239     lua_pushnumber(L, evt_type);
2240     lua_rawset( L, LUA_REGISTRYINDEX ); // pop key and number
2241 }
2242 
wxlua_getwxluastatedata(lua_State * L)2243 wxLuaStateData* LUACALL wxlua_getwxluastatedata(lua_State* L)
2244 {
2245     lua_pushlightuserdata(L, &wxlua_lreg_wxluastatedata_key);
2246     lua_rawget( L, LUA_REGISTRYINDEX ); // pop key, push bool
2247 
2248     wxLuaStateData* data = (wxLuaStateData*)lua_touserdata(L, -1);
2249     lua_pop(L, 1); // pop udata
2250 
2251     return data;
2252 }
2253