diff options
Diffstat (limited to 'ClientHamr/GuiLua/GuiLua.c')
-rw-r--r-- | ClientHamr/GuiLua/GuiLua.c | 456 |
1 files changed, 0 insertions, 456 deletions
diff --git a/ClientHamr/GuiLua/GuiLua.c b/ClientHamr/GuiLua/GuiLua.c deleted file mode 100644 index c7a368c..0000000 --- a/ClientHamr/GuiLua/GuiLua.c +++ /dev/null | |||
@@ -1,456 +0,0 @@ | |||
1 | /* GuiLua - a GUI library that implements matrix-RAD style stuff. | ||
2 | |||
3 | Provides the skang and widget Lua packages. | ||
4 | |||
5 | In the initial intended use case, several applications will be using | ||
6 | this all at once, with one central app hosting all the GUIs. | ||
7 | |||
8 | Basically this should deal with "windows" and their contents. A | ||
9 | "window" in this case is hosted in the central app as some sort of | ||
10 | internal window, but the user can "tear off" those windows, then they | ||
11 | get their own OS hosted window. This could be done by the hosting app | ||
12 | sending the current window contents to the original app as a skang file. | ||
13 | |||
14 | Between the actual GUI and the app might be a socket, or a stdin/out | ||
15 | pipe. Just like matrix-RAD, this should be transparent to the app. | ||
16 | Also just like matrix-RAD, widgets can be connected to variable / | ||
17 | functions (C or Lua), and any twiddlings with those widgets runs the | ||
18 | function / changes the variable, again transparent to the app, except | ||
19 | for any registered get/set methods. | ||
20 | |||
21 | This interface between the GUI and the app is "skang" files, which are | ||
22 | basically Lua scripts. The GUI and the app can send skang files back | ||
23 | and forth, usually the app sends actual GUI stuff, and usually the GUI | ||
24 | sends variable twiddles or action calls. Usually. | ||
25 | |||
26 | To start with, this will be used to support multiple apps hosting their | ||
27 | windows in extantz, allowing the big viewer blob to be split up into | ||
28 | modules. At some point converting LL XML based UI shit into skang could | ||
29 | be done. Also, this should be an exntension to LuaSL, so in-world | ||
30 | scripts can have a poper GUI for a change. | ||
31 | |||
32 | |||
33 | NOTES and TODOs - | ||
34 | |||
35 | Lua scripts do - | ||
36 | require 'widget' -> loads widget.c | ||
37 | Widget.c is a library like test_c. | ||
38 | It starts up GuiLua.c app, with stdin/stdout pipe. | ||
39 | Widget.c then acts as a proxy for all the widget stuff. | ||
40 | So Lua modules via C libraries can work with Elm code that has a special main and has to be an app. | ||
41 | Seems simplest. | ||
42 | |||
43 | Also - | ||
44 | Some of this gets shared with LuaSL, since it came from there anyway. | ||
45 | |||
46 | Finally - | ||
47 | Add a --gui command line option, that runs foo.skang. | ||
48 | Than change the hash bang to use it. | ||
49 | And if there's a matching module, load the module first, call gimmeSkin() on it. | ||
50 | So that any with an internal default skin get that instead. | ||
51 | Same if there's a module, but no skang file. | ||
52 | |||
53 | Making these packages all a sub package of skang seems like a great | ||
54 | idea. On the other hand, looks like most things are just getting folded | ||
55 | into skang anyway. See | ||
56 | http://www.inf.puc-rio.br/~roberto/pil2/chapter15.pdf part 15.5 for | ||
57 | package details. | ||
58 | |||
59 | See if I can use LuaJIT FFI here. Since this will be a library, and | ||
60 | skang apps could be written in C or Lua, perhaps writing this library to | ||
61 | be FFI friendly instead of the usual Lua C binding might be the way to | ||
62 | go? LuaJIT is not ready yet, since it needs include files copied into | ||
63 | Lua files, and does not support macros, which EFL uses a lot of. | ||
64 | |||
65 | For the "GUI hosted in another app" case, we will need some sort of | ||
66 | internal window manager running in that other app. | ||
67 | |||
68 | This might end up running dozens of Lua scripts, and could use the LuaSL | ||
69 | Lua script running system. Moving that into this library might be a | ||
70 | sane idea I think? Or prehaps a separate library that both LuaSL and | ||
71 | GuiLua use? | ||
72 | |||
73 | Raster wants a method of sending Lua tables around as edje messages. | ||
74 | Between C, Edje, Edje Lua, and Lua. Sending between threads, and across | ||
75 | sockets. Using a new edje message type, or eet for sockets, was | ||
76 | suggested, but perhaps Lua skang is a better choice? | ||
77 | |||
78 | Somehow access to the edje_lua2.c bindings should be provided. And | ||
79 | bindings to the rest of EFL when they are done. Assuming the other EFL | ||
80 | developers do proper introspection stuff, or let me do it. | ||
81 | |||
82 | The generic Lua binding helper functions I wrote for edje_lua2.c could | ||
83 | be used here as well, and expanded as discussed on the E devs mailing | ||
84 | list. This would include the thread safe Lua function stuff copied | ||
85 | into the README. | ||
86 | |||
87 | There will eventually be a built in editor, like the zen editor from | ||
88 | matrix-RAD. It might be a separate app. | ||
89 | |||
90 | NAWS should probably live in here to. If I ever get around to writing | ||
91 | it. lol | ||
92 | |||
93 | The pre tokenized widget structure thingy I had planned in the | ||
94 | matrix-RAD TODO just wont work, as it uses symbols. On the other hand, | ||
95 | we will be using Lua tables anyway. B-) | ||
96 | |||
97 | The last half of http://passingcuriosity.com/2009/extending-lua-in-c/ | ||
98 | might be of use. | ||
99 | |||
100 | */ | ||
101 | |||
102 | |||
103 | /* thing package | ||
104 | |||
105 | Currently this is in skang.lua, but should bring this in here later. | ||
106 | |||
107 | */ | ||
108 | |||
109 | |||
110 | /* skang package | ||
111 | |||
112 | Currently this is in skang.lua, but should bring this in here later. | ||
113 | |||
114 | */ | ||
115 | |||
116 | |||
117 | /* stuff & squeal packages | ||
118 | |||
119 | Currently Stuff is in skang.lua, but should bring this in here later. | ||
120 | |||
121 | */ | ||
122 | |||
123 | |||
124 | /* widget package | ||
125 | |||
126 | Currently widget design is in skang.lua, but should bring this in here later. | ||
127 | |||
128 | */ | ||
129 | |||
130 | |||
131 | /* introspection | ||
132 | |||
133 | As detailed in README, EFL introspection doesn't seem to really be on | ||
134 | the radar, but I might get lucky, or I might have to write it myself. | ||
135 | For quick and dirty early testing, I'll probably write a widget package | ||
136 | that has hard coded mappings between some basic "label", "button", etc. | ||
137 | and ordinary elementary widgets. Proper introspection can come later. | ||
138 | |||
139 | */ | ||
140 | |||
141 | |||
142 | |||
143 | #include "GuiLua.h" | ||
144 | |||
145 | |||
146 | globals ourGlobals; | ||
147 | static const char *globName = "ourGlobals"; | ||
148 | |||
149 | |||
150 | // TODO - These functions should be able to deal with multiple windows. | ||
151 | // TODO - Should be able to open external and internal windows, and even switch between them on the fly. | ||
152 | static void _on_done(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) | ||
153 | { | ||
154 | // globals *ourGlobals = data; | ||
155 | |||
156 | // Tell the main loop to stop, which it will, eventually. | ||
157 | elm_exit(); | ||
158 | } | ||
159 | |||
160 | |||
161 | /* Sooo, how to do this - | ||
162 | widget has to be a light userdata | ||
163 | The rest can be Lua sub things? Each with a C function to update the widget. | ||
164 | |||
165 | win.quitter:colour(1,2,3,4) -> win.quitter.colour(win.quitter, 1,2,3,4) -> __call(win.quitter.colour, win.quitter, 1,2,3,4) -> skang.colour(win.quitter.colour, win.quitter, 1,2,3,4) | ||
166 | win.quitter.colour.r = 5 -> direct access to the table, well "direct" via Thing and Mum. We eventually want to call skang.colour() though. | ||
167 | */ | ||
168 | |||
169 | struct _Widget | ||
170 | { | ||
171 | char magic[8]; | ||
172 | Evas_Object *obj; | ||
173 | char *label, *look, *action, *help; | ||
174 | // foreground / background colour | ||
175 | // thing | ||
176 | // types {} | ||
177 | // skangCoord x, y, w, h | ||
178 | }; | ||
179 | |||
180 | static void _on_click(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) | ||
181 | { | ||
182 | globals *ourGlobals; | ||
183 | lua_State *L = data; | ||
184 | struct _Widget *wid; | ||
185 | |||
186 | lua_getfield(L, LUA_REGISTRYINDEX, globName); | ||
187 | ourGlobals = lua_touserdata(L, -1); | ||
188 | lua_pop(L, 1); | ||
189 | |||
190 | wid = evas_object_data_get(obj, "Widget"); | ||
191 | if (wid) | ||
192 | { | ||
193 | PD("Doing action %s", wid->action); | ||
194 | if (0 != luaL_dostring(L, wid->action)) | ||
195 | PE("Error running - %s", wid->action); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | static int widget(lua_State *L) | ||
200 | { | ||
201 | globals *ourGlobals; | ||
202 | char *type = "label"; | ||
203 | char *title = ":"; | ||
204 | int x = 1, y = 1, w = WIDTH/3, h = HEIGHT/3; | ||
205 | |||
206 | lua_getfield(L, LUA_REGISTRYINDEX, globName); | ||
207 | ourGlobals = lua_touserdata(L, -1); | ||
208 | lua_pop(L, 1); | ||
209 | |||
210 | pull_lua(L, 1, "$type $title %x %y %w %h", &type, &title, &x, &y, &w, &h); | ||
211 | |||
212 | // Poor mans introspection, until I write real introspection into EFL. | ||
213 | if (strcmp(type, "button") == 0) | ||
214 | { | ||
215 | struct _Widget *wid; | ||
216 | |||
217 | wid = calloc(1, sizeof(struct _Widget)); | ||
218 | strcpy(wid->magic, "Widget"); | ||
219 | wid->label = strdup(title); | ||
220 | wid->obj = elm_button_add(ourGlobals->win); | ||
221 | elm_object_text_set(wid->obj, title); | ||
222 | evas_object_smart_callback_add(wid->obj, "clicked", _on_click, L); | ||
223 | evas_object_resize(wid->obj, w, h); | ||
224 | evas_object_move(wid->obj, x, y); | ||
225 | evas_object_show(wid->obj); | ||
226 | evas_object_data_set(wid->obj, "Widget", wid); | ||
227 | /* Evas_Object *bt isn't a real pointer it seems. At least Lua bitches about it - | ||
228 | PANIC: unprotected error in call to Lua API (bad light userdata pointer) | ||
229 | So we wrap it. | ||
230 | */ | ||
231 | lua_pushlightuserdata(L, (void *) wid); | ||
232 | return 1; | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static int action(lua_State *L) | ||
239 | { | ||
240 | globals *ourGlobals; | ||
241 | struct _Widget *wid = lua_touserdata(L, 1); | ||
242 | char *action = "nada"; | ||
243 | |||
244 | lua_getfield(L, LUA_REGISTRYINDEX, globName); | ||
245 | ourGlobals = lua_touserdata(L, -1); | ||
246 | lua_pop(L, 1); | ||
247 | |||
248 | pull_lua(L, 2, "$", &action); | ||
249 | if (wid && strcmp(wid->magic, "Widget") == 0) | ||
250 | { | ||
251 | PD("Setting action %s", action); | ||
252 | wid->action = strdup(action); | ||
253 | } | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int colour(lua_State *L) | ||
258 | { | ||
259 | // TODO - This is just a stub for now. | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int window(lua_State *L) | ||
265 | { | ||
266 | globals *ourGlobals; | ||
267 | char *name = "GuiLua"; | ||
268 | char *title = "GuiLua test harness"; | ||
269 | int w = WIDTH, h = HEIGHT; | ||
270 | |||
271 | lua_getfield(L, LUA_REGISTRYINDEX, globName); | ||
272 | ourGlobals = lua_touserdata(L, -1); | ||
273 | lua_pop(L, 1); | ||
274 | |||
275 | pull_lua(L, 1, "%w %h $title $name", &w, &h, &title, &name); | ||
276 | PI("Setting window to %d %d %s", w, h, title); | ||
277 | |||
278 | if ((ourGlobals->win = elm_win_util_standard_add(name, title))) | ||
279 | { | ||
280 | evas_object_smart_callback_add(ourGlobals->win, "delete,request", _on_done, ourGlobals); | ||
281 | evas_object_resize(ourGlobals->win, w, h); | ||
282 | evas_object_move(ourGlobals->win, 0, 0); | ||
283 | evas_object_show(ourGlobals->win); | ||
284 | |||
285 | lua_pushlightuserdata(L, &ourGlobals->win); | ||
286 | return 1; | ||
287 | } | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int clear(lua_State *L) | ||
293 | { | ||
294 | // TODO - This is just a stub for now. | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int loopWindow(lua_State *L) | ||
300 | { | ||
301 | globals *ourGlobals; | ||
302 | |||
303 | lua_getfield(L, LUA_REGISTRYINDEX, globName); | ||
304 | ourGlobals = lua_touserdata(L, -1); | ||
305 | lua_pop(L, 1); | ||
306 | |||
307 | if (ourGlobals->win) | ||
308 | elm_run(); | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static int quit(lua_State *L) | ||
314 | { | ||
315 | globals *ourGlobals; | ||
316 | |||
317 | lua_getfield(L, LUA_REGISTRYINDEX, globName); | ||
318 | ourGlobals = lua_touserdata(L, -1); | ||
319 | lua_pop(L, 1); | ||
320 | |||
321 | _on_done(ourGlobals, NULL, NULL); | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static int closeWindow(lua_State *L) | ||
327 | { | ||
328 | globals *ourGlobals; | ||
329 | |||
330 | lua_getfield(L, LUA_REGISTRYINDEX, globName); | ||
331 | ourGlobals = lua_touserdata(L, -1); | ||
332 | lua_pop(L, 1); | ||
333 | |||
334 | // Elm will delete our buttons to, and EO will bitch four times for each. | ||
335 | if (ourGlobals->win) | ||
336 | evas_object_del(ourGlobals->win); | ||
337 | |||
338 | if (ourGlobals->logDom >= 0) | ||
339 | { | ||
340 | eina_log_domain_unregister(ourGlobals->logDom); | ||
341 | ourGlobals->logDom = -1; | ||
342 | } | ||
343 | |||
344 | // This shuts down Elementary, but keeps the main loop running until all ecore_evas are freed. | ||
345 | elm_shutdown(); | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | /* local widget = require 'libGuiLua' | ||
351 | |||
352 | Lua's require() function will strip any stuff from the front of the name | ||
353 | separated by a hyphen, so 'ClientHamr-GuiLua-libGuiLua' -> 'libGuiLua'. Then | ||
354 | it will search through a path, and eventually find this libGuiLua.so (or | ||
355 | libGuiLua.dll or whatever), then call luaopen_libGuiLua(), which should return | ||
356 | a table. The argument (only thing on the stack) for this function will | ||
357 | be 'libGuiLua'. | ||
358 | |||
359 | Normally luaL_register() creates a table of functions, that is the table | ||
360 | returned, but we want to do something different with skang. | ||
361 | */ | ||
362 | int luaopen_GuiLua(lua_State *L) | ||
363 | { | ||
364 | int skang; | ||
365 | |||
366 | // In theory this function only ever gets called once. | ||
367 | memset(&ourGlobals, 0, sizeof(globals)); | ||
368 | ourGlobals.logDom = loggingStartup("GuiLua", ourGlobals.logDom); | ||
369 | |||
370 | elm_policy_set(ELM_POLICY_EXIT, ELM_POLICY_EXIT_NONE); | ||
371 | elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_NONE); | ||
372 | elm_policy_set(ELM_POLICY_THROTTLE, ELM_POLICY_THROTTLE_HIDDEN_ALWAYS); | ||
373 | |||
374 | // These are set via the elementary_config tool, which is hard to find. | ||
375 | elm_config_finger_size_set(0); | ||
376 | elm_config_scale_set(1.0); | ||
377 | |||
378 | // pseudo-indices, special tables that can be accessed like the stack - | ||
379 | // LUA_GLOBALSINDEX - thread environment, where globals are | ||
380 | // LUA_ENVIRONINDEX - C function environment, in this case luaopen_widget() is the C function | ||
381 | // LUA_REGISTRYINDEX - C registry, global, for unique keys use the module name as a string, or a lightuserdata address to a C object in our module. | ||
382 | // lua_upvalueindex(n) - C function upvalues | ||
383 | |||
384 | // Shove ourGlobals into the registry. | ||
385 | lua_pushlightuserdata(L, &ourGlobals); | ||
386 | lua_setfield(L, LUA_REGISTRYINDEX, globName); | ||
387 | |||
388 | // The skang module should have been loaded by now, so we can just grab it out of package.loaded[]. | ||
389 | lua_getglobal(L, "package"); | ||
390 | lua_getfield(L, lua_gettop(L), "loaded"); | ||
391 | lua_remove(L, -2); // Removes "package" | ||
392 | lua_getfield(L, lua_gettop(L), SKANG); | ||
393 | lua_remove(L, -2); // Removes "loaded" | ||
394 | lua_setfield(L, LUA_REGISTRYINDEX, SKANG); | ||
395 | lua_getfield(L, LUA_REGISTRYINDEX, SKANG); // Puts the skang table back on the stack. | ||
396 | skang = lua_gettop(L); | ||
397 | |||
398 | // Define our functions. | ||
399 | //thingasm{'window', 'The size and title of the application Frame.', window, 'x,y,name', acl='GGG'} | ||
400 | push_lua(L, "@ ( { = $ $ & $ $acl } )", skang, THINGASM, skang, "Cwindow", "Opens our window.", window, "number,number,string", "GGG", 0); | ||
401 | push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "clear", "The current skin is cleared of all widgets.", clear, 0); | ||
402 | push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "widget", "Create a widget.", widget, 0); | ||
403 | push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "action", "Add an action to a widget.", action, 0); | ||
404 | push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "Colour", "Change widget colours.", colour, 0); | ||
405 | push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "loopWindow", "Run our windows main loop.", loopWindow, 0); | ||
406 | push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "quit", "Quit, exit, remove thyself.", quit, 0); | ||
407 | push_lua(L, "@ ( = $ $ & )", skang, THINGASM, skang, "closeWindow", "Closes our window.", closeWindow, 0); | ||
408 | |||
409 | // A test of the array building stuff. | ||
410 | push_lua(L, "@ ( { = $ $ % $widget !required } )", skang, THINGASM, skang, "wibble", "It's wibbly!", 1, "'edit', 'The wibblinator:', 1, 1, 10, 50", 1, 0); | ||
411 | |||
412 | // Makes no difference what we return, but it's expecting something. | ||
413 | return 1; | ||
414 | } | ||
415 | |||
416 | |||
417 | void GuiLuaDo(int argc, char **argv) | ||
418 | { | ||
419 | lua_State *L; | ||
420 | lua_Number i; | ||
421 | |||
422 | L = luaL_newstate(); | ||
423 | if (L) | ||
424 | { | ||
425 | luaL_openlibs(L); | ||
426 | |||
427 | // Pass all our command line arguments to Lua. | ||
428 | i = 1; | ||
429 | lua_newtable(L); | ||
430 | while (--argc > 0 && *++argv != '\0') | ||
431 | { | ||
432 | lua_pushnumber(L, i++); | ||
433 | lua_pushstring(L, *argv); | ||
434 | lua_settable(L, -3); | ||
435 | } | ||
436 | lua_setfield(L, LUA_GLOBALSINDEX, "arg"); | ||
437 | |||
438 | |||
439 | // When we do this, skang will process all the arguments passed to GuiLuaDo(). | ||
440 | // This likely includes a module load, which likely opens a window. | ||
441 | lua_getglobal(L, "require"); | ||
442 | lua_pushstring(L, SKANG); | ||
443 | lua_call(L, 1, 1); | ||
444 | lua_setfield(L, LUA_GLOBALSINDEX, SKANG); | ||
445 | |||
446 | |||
447 | // Run the main loop via a Lua call. | ||
448 | // This does nothing if no module opened a window. | ||
449 | if (0 != luaL_dostring(L, "skang.loopWindow()")) | ||
450 | PEm("Error running - skang.loopWindow()"); | ||
451 | lua_pop(L, closeWindow(L)); | ||
452 | lua_close(L); | ||
453 | } | ||
454 | else | ||
455 | fprintf(stderr, "Failed to start Lua!\n"); | ||
456 | } | ||