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 *****************************************************************************/
33 #include <lua.h> /* Low level lua C API */
34 #include <lauxlib.h> /* Higher level C API */
35 #include <lualib.h> /* Lua libs */
46 static int vlclua_callback( vlc_object_t *p_this, char const *psz_var,
47 vlc_value_t oldval, vlc_value_t newval,
50 vlclua_callback_t *p_callback = (vlclua_callback_t*)p_data;
51 lua_State *L = p_callback->L;
54 lua_getglobal( L, "vlc" );
56 lua_getfield( L, -1, "callbacks" );
60 lua_pushinteger( L, p_callback->i_index );
62 lua_gettable( L, -2 );
63 /* callbacks callbacks[index] */
65 /* callbacks[index] */
66 lua_getfield( L, -1, "callback" );
67 /* callbacks[index] callback */
68 lua_pushstring( L, psz_var );
69 /* callbacks[index] callback var */
70 vlclua_pushvalue( L, p_callback->i_type, oldval );
71 /* callbacks[index] callback var oldval */
72 vlclua_pushvalue( L, p_callback->i_type, newval );
73 /* callbacks[index] callback var oldval newval */
74 lua_getfield( L, -5, "data" );
75 /* callbacks[index] callback var oldval newval data */
77 /* callback var oldval newval data */
79 if( lua_pcall( L, 4, 0, 0 ) )
82 const char *psz_err = lua_tostring( L, -1 );
83 msg_Err( p_this, "Error while runing lua interface callback: %s",
85 /* empty the stack (should only contain the error message) */
90 /* empty the stack (should already be empty) */
96 int vlclua_add_callback( lua_State *L )
98 vlclua_callback_t *p_callback;
99 static int i_index = 0;
100 vlc_object_t *p_obj = vlclua_checkobject( L, 1, 0 );
101 const char *psz_var = luaL_checkstring( L, 2 );
102 lua_settop( L, 4 ); /* makes sure that optional data arg is set */
103 if( !lua_isfunction( L, 3 ) )
104 return vlclua_error( L );
107 p_callback = (vlclua_callback_t*)malloc( sizeof( vlclua_callback_t ) );
109 return vlclua_error( L );
111 /* obj var func data */
112 lua_getglobal( L, "vlc" );
113 /* obj var func data vlc */
114 lua_getfield( L, -1, "callbacks" );
115 if( lua_isnil( L, -1 ) )
119 lua_setfield( L, -2, "callbacks" );
120 lua_getfield( L, -1, "callbacks" );
122 /* obj var func data vlc callbacks */
124 /* obj var func data callbacks */
125 lua_pushinteger( L, i_index );
126 /* obj var func data callbacks index */
128 /* obj var index func data callbacks */
130 /* obj var callbacks index func data */
131 lua_createtable( L, 0, 0 );
132 /* obj var callbacks index func data cbtable */
134 /* obj var callbacks index func cbtable data */
135 lua_setfield( L, -2, "data" );
136 /* obj var callbacks index func cbtable */
138 /* obj var callbacks index cbtable func */
139 lua_setfield( L, -2, "callback" );
140 /* obj var callbacks index cbtable */
141 lua_pushlightuserdata( L, p_obj ); /* will be needed in vlclua_del_callback */
142 /* obj var callbacks index cbtable p_obj */
143 lua_setfield( L, -2, "private1" );
144 /* obj var callbacks index cbtable */
145 lua_pushvalue( L, 2 ); /* will be needed in vlclua_del_callback */
146 /* obj var callbacks index cbtable var */
147 lua_setfield( L, -2, "private2" );
148 /* obj var callbacks index cbtable */
149 lua_pushlightuserdata( L, p_callback ); /* will be needed in vlclua_del_callback */
150 /* obj var callbacks index cbtable p_callback */
151 lua_setfield( L, -2, "private3" );
152 /* obj var callbacks index cbtable */
153 lua_settable( L, -3 );
154 /* obj var callbacks */
158 /* Do not move this before the lua specific code (it somehow changes
159 * the function in the stack to nil) */
160 p_callback->i_index = i_index;
161 p_callback->i_type = var_Type( p_obj, psz_var );
162 p_callback->L = lua_newthread( L );
164 var_AddCallback( p_obj, psz_var, vlclua_callback, p_callback );
168 int vlclua_del_callback( lua_State *L )
170 vlclua_callback_t *p_callback;
171 vlc_bool_t b_found = VLC_FALSE;
172 vlc_object_t *p_obj = vlclua_checkobject( L, 1, 0 );
173 const char *psz_var = luaL_checkstring( L, 2 );
174 lua_settop( L, 4 ); /* makes sure that optional data arg is set */
175 if( !lua_isfunction( L, 3 ) )
176 return vlclua_error( L );
178 /* obj var func data */
179 lua_getglobal( L, "vlc" );
180 /* obj var func data vlc */
181 lua_getfield( L, -1, "callbacks" );
182 if( lua_isnil( L, -1 ) )
183 return luaL_error( L, "Couldn't find matching callback." );
184 /* obj var func data vlc callbacks */
186 /* obj var func data callbacks */
188 /* obj var func data callbacks index */
189 while( lua_next( L, -2 ) )
191 /* obj var func data callbacks index value */
192 if( lua_isnumber( L, -2 ) )
194 lua_getfield( L, -1, "private2" );
195 /* obj var func data callbacks index value private2 */
196 if( lua_equal( L, 2, -1 ) ) /* var name is equal */
199 /* obj var func data callbacks index value */
200 lua_getfield( L, -1, "callback" );
201 /* obj var func data callbacks index value callback */
202 if( lua_equal( L, 3, -1 ) ) /* callback function is equal */
205 /* obj var func data callbacks index value */
206 lua_getfield( L, -1, "data" ); /* callback data is equal */
207 /* obj var func data callbacks index value data */
208 if( lua_equal( L, 4, -1 ) )
210 vlc_object_t *p_obj2;
212 /* obj var func data callbacks index value */
213 lua_getfield( L, -1, "private1" );
214 /* obj var func data callbacks index value private1 */
215 p_obj2 = (vlc_object_t*)luaL_checklightuserdata( L, -1 );
216 if( p_obj2 == p_obj ) /* object is equal */
219 /* obj var func data callbacks index value */
220 lua_getfield( L, -1, "private3" );
221 /* obj var func data callbacks index value private3 */
222 p_callback = (vlclua_callback_t*)luaL_checklightuserdata( L, -1 );
224 /* obj var func data callbacks index */
230 /* obj var func data callbacks index value private1 */
232 /* obj var func data callbacks index value */
237 /* obj var func data callbacks index value data */
239 /* obj var func data callbacks index value */
244 /* obj var func data callbacks index value callback */
246 /* obj var func data callbacks index value */
251 /* obj var func data callbacks index value private2 */
253 /* obj var func data callbacks index value */
256 /* obj var func data callbacks index value */
258 /* obj var func data callbacks index */
260 if( b_found == VLC_FALSE )
261 /* obj var func data callbacks */
262 return luaL_error( L, "Couldn't find matching callback." );
264 /* obj var func data callbacks index*/
266 var_DelCallback( p_obj, psz_var, vlclua_callback, p_callback );
269 /* obj var func data callbacks index */
271 /* obj var func data callbacks index nil */
272 lua_settable( L, -3 ); /* delete the callback table entry */
273 /* obj var func data callbacks */