1 /*****************************************************************************
2 * callbacks.c: Generic lua<->vlc callbacks interface
3 *****************************************************************************
4 * Copyright (C) 2007 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea at videolan tod org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
37 #include <lua.h> /* Low level lua C API */
38 #include <lauxlib.h> /* Higher level C API */
39 #include <lualib.h> /* Lua libs */
50 static int vlclua_callback( vlc_object_t *p_this, char const *psz_var,
51 vlc_value_t oldval, vlc_value_t newval,
54 vlclua_callback_t *p_callback = (vlclua_callback_t*)p_data;
55 lua_State *L = p_callback->L;
58 lua_getglobal( L, "vlc" );
60 lua_getfield( L, -1, "callbacks" );
64 lua_pushinteger( L, p_callback->i_index );
66 lua_gettable( L, -2 );
67 /* callbacks callbacks[index] */
69 /* callbacks[index] */
70 lua_getfield( L, -1, "callback" );
71 /* callbacks[index] callback */
72 lua_pushstring( L, psz_var );
73 /* callbacks[index] callback var */
74 vlclua_pushvalue( L, p_callback->i_type, oldval );
75 /* callbacks[index] callback var oldval */
76 vlclua_pushvalue( L, p_callback->i_type, newval );
77 /* callbacks[index] callback var oldval newval */
78 lua_getfield( L, -5, "data" );
79 /* callbacks[index] callback var oldval newval data */
81 /* callback var oldval newval data */
83 if( lua_pcall( L, 4, 0, 0 ) )
86 const char *psz_err = lua_tostring( L, -1 );
87 msg_Err( p_this, "Error while runing lua interface callback: %s",
89 /* empty the stack (should only contain the error message) */
94 /* empty the stack (should already be empty) */
100 int vlclua_add_callback( lua_State *L )
102 vlclua_callback_t *p_callback;
103 static int i_index = 0;
104 vlc_object_t *p_obj = vlclua_checkobject( L, 1, 0 );
105 const char *psz_var = luaL_checkstring( L, 2 );
106 lua_settop( L, 4 ); /* makes sure that optional data arg is set */
107 if( !lua_isfunction( L, 3 ) )
108 return vlclua_error( L );
111 p_callback = (vlclua_callback_t*)malloc( sizeof( vlclua_callback_t ) );
113 return vlclua_error( L );
115 /* obj var func data */
116 lua_getglobal( L, "vlc" );
117 /* obj var func data vlc */
118 lua_getfield( L, -1, "callbacks" );
119 if( lua_isnil( L, -1 ) )
123 lua_setfield( L, -2, "callbacks" );
124 lua_getfield( L, -1, "callbacks" );
126 /* obj var func data vlc callbacks */
128 /* obj var func data callbacks */
129 lua_pushinteger( L, i_index );
130 /* obj var func data callbacks index */
132 /* obj var index func data callbacks */
134 /* obj var callbacks index func data */
135 lua_createtable( L, 0, 0 );
136 /* obj var callbacks index func data cbtable */
138 /* obj var callbacks index func cbtable data */
139 lua_setfield( L, -2, "data" );
140 /* obj var callbacks index func cbtable */
142 /* obj var callbacks index cbtable func */
143 lua_setfield( L, -2, "callback" );
144 /* obj var callbacks index cbtable */
145 lua_pushlightuserdata( L, p_obj ); /* will be needed in vlclua_del_callback */
146 /* obj var callbacks index cbtable p_obj */
147 lua_setfield( L, -2, "private1" );
148 /* obj var callbacks index cbtable */
149 lua_pushvalue( L, 2 ); /* will be needed in vlclua_del_callback */
150 /* obj var callbacks index cbtable var */
151 lua_setfield( L, -2, "private2" );
152 /* obj var callbacks index cbtable */
153 lua_pushlightuserdata( L, p_callback ); /* will be needed in vlclua_del_callback */
154 /* obj var callbacks index cbtable p_callback */
155 lua_setfield( L, -2, "private3" );
156 /* obj var callbacks index cbtable */
157 lua_settable( L, -3 );
158 /* obj var callbacks */
162 /* Do not move this before the lua specific code (it somehow changes
163 * the function in the stack to nil) */
164 p_callback->i_index = i_index;
165 p_callback->i_type = var_Type( p_obj, psz_var );
166 p_callback->L = lua_newthread( L ); /* Do we have to keep a reference to this thread somewhere to prevent garbage collection? */
168 var_AddCallback( p_obj, psz_var, vlclua_callback, p_callback );
172 int vlclua_del_callback( lua_State *L )
174 vlclua_callback_t *p_callback;
175 bool b_found = false;
176 vlc_object_t *p_obj = vlclua_checkobject( L, 1, 0 );
177 const char *psz_var = luaL_checkstring( L, 2 );
178 lua_settop( L, 4 ); /* makes sure that optional data arg is set */
179 if( !lua_isfunction( L, 3 ) )
180 return vlclua_error( L );
182 /* obj var func data */
183 lua_getglobal( L, "vlc" );
184 /* obj var func data vlc */
185 lua_getfield( L, -1, "callbacks" );
186 if( lua_isnil( L, -1 ) )
187 return luaL_error( L, "Couldn't find matching callback." );
188 /* obj var func data vlc callbacks */
190 /* obj var func data callbacks */
192 /* obj var func data callbacks index */
193 while( lua_next( L, -2 ) )
195 /* obj var func data callbacks index value */
196 if( lua_isnumber( L, -2 ) )
198 lua_getfield( L, -1, "private2" );
199 /* obj var func data callbacks index value private2 */
200 if( lua_equal( L, 2, -1 ) ) /* var name is equal */
203 /* obj var func data callbacks index value */
204 lua_getfield( L, -1, "callback" );
205 /* obj var func data callbacks index value callback */
206 if( lua_equal( L, 3, -1 ) ) /* callback function is equal */
209 /* obj var func data callbacks index value */
210 lua_getfield( L, -1, "data" ); /* callback data is equal */
211 /* obj var func data callbacks index value data */
212 if( lua_equal( L, 4, -1 ) )
214 vlc_object_t *p_obj2;
216 /* obj var func data callbacks index value */
217 lua_getfield( L, -1, "private1" );
218 /* obj var func data callbacks index value private1 */
219 p_obj2 = (vlc_object_t*)luaL_checklightuserdata( L, -1 );
220 if( p_obj2 == p_obj ) /* object is equal */
223 /* obj var func data callbacks index value */
224 lua_getfield( L, -1, "private3" );
225 /* obj var func data callbacks index value private3 */
226 p_callback = (vlclua_callback_t*)luaL_checklightuserdata( L, -1 );
228 /* obj var func data callbacks index */
234 /* obj var func data callbacks index value private1 */
236 /* obj var func data callbacks index value */
241 /* obj var func data callbacks index value data */
243 /* obj var func data callbacks index value */
248 /* obj var func data callbacks index value callback */
250 /* obj var func data callbacks index value */
255 /* obj var func data callbacks index value private2 */
257 /* obj var func data callbacks index value */
260 /* obj var func data callbacks index value */
262 /* obj var func data callbacks index */
264 if( b_found == false )
265 /* obj var func data callbacks */
266 return luaL_error( L, "Couldn't find matching callback." );
268 /* obj var func data callbacks index*/
270 var_DelCallback( p_obj, psz_var, vlclua_callback, p_callback );
273 /* obj var func data callbacks index */
275 /* obj var func data callbacks index nil */
276 lua_settable( L, -3 ); /* delete the callback table entry */
277 /* obj var func data callbacks */