Commit 0e17e9a2e2c28c81f03cf0303240e6ab7c2f6640

Authored by DarkGod
1 parent 85909b73

Added a generic web rendered (not available on OSX yet): a module or addon can r…

…ender UI, or parts of UI in html5/css3/javascript now.
1   -<script type="text/javascript" src='asset://te4/data/html/jquery-1.10.2.min.js'></script>
  1 +<script type="text/javascript" src='asset://te4/html/jquery-1.10.2.min.js'></script>
2 2
3 3 <p><strong>lol</strong> lolll</p>
4 4
5   -<script type="text/javascript" src='asset://te4/data/html/test.js'></script>
  5 +<script type="text/javascript" src='asset://te4/html/test.js'></script>
  6 +
  7 +<script type="text/javascript">
  8 +
  9 +te4.lua("print('plop')");
  10 +console.log("=====ret: " + te4.lolzor(1, "plop"));
  11 +
  12 +$('strong').css("color", "red");
  13 +
  14 +</script>
6 15
... ...
1 1 $('strong').click(function() {
2 2 $(this).html("CLICKED");
3   - te4core.testclick("theclick", 7);
4 3 });
\ No newline at end of file
... ...
... ... @@ -139,6 +139,9 @@ core.display.setGamma(config.settings.gamma_correction / 100)
139 139 if not config.settings.fbo_active then core.display.disableFBO() print("Disabling FBO") end
140 140 if not config.settings.shaders_active then core.shader.disable() print("Disabling Shaders") end
141 141
  142 +-- Webcore local request resolver
  143 +dofile("/engine/webcore.lua")
  144 +
142 145 -- Load profile configs
143 146 core.profile.createThread()
144 147 profile = engine.PlayerProfile.new()
... ...
... ... @@ -34,6 +34,7 @@ function _M:init(t)
34 34 self.never_clean = t.never_clean
35 35 self.allow_popup = t.allow_popup
36 36 self.allow_login = t.allow_login
  37 + self.custom_calls = t.custom_calls or {}
37 38 if self.allow_login == nil then self.allow_login = true end
38 39
39 40 if self.allow_login and self.url:find("^http://te4%.org/") and profile.auth then
... ... @@ -60,18 +61,28 @@ function _M:generate()
60 61 self.key:reset()
61 62
62 63 local handlers = {
63   - on_title = function(view, title) if self.on_title then self.on_title(title) end end,
64   - on_popup = function(view, url, w, h) if self.allow_popup then
  64 + on_title = function(title) if self.on_title then self.on_title(title) end end,
  65 + on_popup = function(url, w, h) if self.allow_popup then
65 66 local Dialog = require "engine.ui.Dialog"
66 67 Dialog:webPopup(url, w, h)
67 68 end end,
68   - on_loading = function(view, url, status)
69   - print("===loading", url, status)
  69 + on_loading = function(url, status)
70 70 self.loading = status
71 71 end,
72 72 }
73 73 if self.allow_downloads then self:onDownload(handlers) end
74   - self.view = core.webview.new(self.w, self.h, self.url, handlers)
  74 + self.view = core.webview.new(self.w, self.h, handlers)
  75 +
  76 + self.custom_calls.lolzor = function(nb, str)
  77 + print("call from js got: ", nb, str)
  78 + return "PLAP"
  79 + end
  80 +
  81 + for name, fct in pairs(self.custom_calls) do
  82 + handlers[name] = fct
  83 + self.view:setMethod(name)
  84 + end
  85 + self.view:loadURL(self.url)
75 86 self.loading = 0
76 87 self.loading_rotation = 0
77 88 self.scroll_inertia = 0
... ... @@ -155,7 +166,7 @@ end
155 166 function _M:onDownload(handlers)
156 167 local Dialog = require "engine.ui.Dialog"
157 168
158   - handlers.on_download_request = function(view, downid, url, file, mime)
  169 + handlers.on_download_request = function(downid, url, file, mime)
159 170 if mime == "application/t-engine-addon" and self.allow_downloads.addons and url:find("^http://te4%.org/") then
160 171 local path = fs.getRealPath("/addons/")
161 172 if path then
... ... @@ -192,12 +203,12 @@ function _M:onDownload(handlers)
192 203 self.view:downloadAction(downid, false)
193 204 end
194 205
195   - handlers.on_download_update = function(view, downid, cur_size, total_size, percent, speed)
  206 + handlers.on_download_update = function(downid, cur_size, total_size, percent, speed)
196 207 if not self.download_dialog then return end
197 208 self.download_dialog:updateFill(cur_size, total_size, ("%d%% - %d KB/s"):format(cur_size * 100 / total_size, speed / 1024))
198 209 end
199 210
200   - handlers.on_download_finish = function(view, downid)
  211 + handlers.on_download_finish = function(downid)
201 212 if not self.download_dialog then return end
202 213 game:unregisterDialog(self.download_dialog)
203 214 if self.download_dialog.install_kind == "Addon" then
... ...
  1 +-- TE4 - T-Engine 4
  2 +-- Copyright (C) 2009 - 2014 Nicolas Casalini
  3 +--
  4 +-- This program is free software: you can redistribute it and/or modify
  5 +-- it under the terms of the GNU General Public License as published by
  6 +-- the Free Software Foundation, either version 3 of the License, or
  7 +-- (at your option) any later version.
  8 +--
  9 +-- This program is distributed in the hope that it will be useful,
  10 +-- but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 +-- GNU General Public License for more details.
  13 +--
  14 +-- You should have received a copy of the GNU General Public License
  15 +-- along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 +--
  17 +-- Nicolas Casalini "DarkGod"
  18 +-- darkgod@te4.org
  19 +
  20 +if not core.webview then return end
  21 +
  22 +local class = require "class"
  23 +
  24 +core.webview.paths = {}
  25 +
  26 +function core.webview.responder(id, path)
  27 + path = "/"..path
  28 + print("[WEBCORE] path request: ", path)
  29 +
  30 + -- Let hook do their stuff
  31 + local reply = {}
  32 + if class:triggerHook{"Web:request", path=path, reply=reply} and reply.data then
  33 + core.webview.localReplyData(id, reply.mime, reply.data)
  34 + return
  35 + end
  36 +
  37 + -- No hooks, perhaps we have a registered path matching
  38 + for mpath, fct in pairs(core.webview.paths) do
  39 + local r = {path:find("^"..mpath)}
  40 + if r[1] then
  41 + table.remove(r, 1) table.remove(r, 1)
  42 + local mime, data = fct(path, unpack(r))
  43 + if mime and data then
  44 + core.webview.localReplyData(id, mime, data)
  45 + return
  46 + end
  47 + end
  48 + end
  49 +
  50 + -- Default, check for a file in /data/
  51 + local mime = "application/octet-stream"
  52 + if path:find("%.html$") then mime = "text/html"
  53 + elseif path:find("%.js$") then mime = "text/javascript"
  54 + elseif path:find("%.css$") then mime = "text/css"
  55 + elseif path:find("%.png$") then mime = "image/png"
  56 + end
  57 + core.webview.localReplyFile(id, mime, "/data"..path)
  58 +end
  59 +
  60 +core.webview.paths["/example/(.*)"] = function(path, sub)
  61 + return "text/html", "example sub url was: "..sub
  62 +end
... ...
... ... @@ -57,7 +57,7 @@ function _M:init()
57 57 l[#l+1] = {name="Credits", fct=function() game:registerDialog(require("mod.dialogs.Credits").new()) end}
58 58 l[#l+1] = {name="Exit", fct=function() game:onQuit() end}
59 59 if config.settings.cheat then l[#l+1] = {name="Reboot", fct=function() util.showMainMenu() end} end
60   - -- if config.settings.cheat then l[#l+1] = {name="webtest", fct=function() util.browserOpenUrl("http://te4.org/addons/tome?_te4") end} end
  60 + if config.settings.cheat then l[#l+1] = {name="webtest", fct=function() util.browserOpenUrl("asset://te4/html/test.html") end} end
61 61
62 62 self.c_background = Button.new{text=game.stopped and "Enable background" or "Disable background", fct=function() self:switchBackground() end}
63 63 self.c_version = Textzone.new{auto_width=true, auto_height=true, text=("#{bold}##B9E100#T-Engine4 version: %d.%d.%d"):format(engine.version[1], engine.version[2], engine.version[3])}
... ...
... ... @@ -27,14 +27,15 @@ unsigned int (*web_make_texture)(int w, int h);
27 27 void (*web_del_texture)(unsigned int tex);
28 28 void (*web_texture_update)(unsigned int tex, int w, int h, const void* buffer);
29 29 static void (*web_key_mods)(bool *shift, bool *ctrl, bool *alt, bool *meta);
  30 +static void (*web_instant_js)(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret);
30 31
31 32 using namespace Awesomium;
32 33
33   -class PhysfsDataSource;
  34 +class TE4DataSource;
34 35
35 36 static WebCore *web_core = NULL;
36 37 static WebSession *web_session = NULL;
37   -static PhysfsDataSource *web_data_source = NULL;
  38 +static TE4DataSource *web_data_source = NULL;
38 39
39 40 class WebListener;
40 41
... ... @@ -58,6 +59,7 @@ class WebListener :
58 59 private:
59 60 int handlers;
60 61 public:
  62 + JSObject te4_js;
61 63 WebListener(int handlers) { this->handlers = handlers; }
62 64
63 65 virtual void OnChangeTitle(Awesomium::WebView* caller, const Awesomium::WebString& title) {
... ... @@ -85,6 +87,11 @@ public:
85 87 }
86 88
87 89 virtual void OnAddConsoleMessage(Awesomium::WebView* caller, const Awesomium::WebString& message, int line_number, const Awesomium::WebString& source) {
  90 + char *msg = webstring_to_buf(message, NULL);
  91 + char *src = webstring_to_buf(source, NULL);
  92 + printf("[WEBCORE:console %s:%d] %s\n", src, line_number, msg);
  93 + free(msg);
  94 + free(src);
88 95 }
89 96
90 97 virtual void OnShowCreatedWebView(Awesomium::WebView* caller, Awesomium::WebView* new_view, const Awesomium::WebURL& opener_url, const Awesomium::WebURL& target_url, const Awesomium::Rect& initial_pos, bool is_popup) {
... ... @@ -101,7 +108,7 @@ public:
101 108 event->data.popup.h = initial_pos.height;
102 109 push_event(event);
103 110
104   - printf("[WEB] stopped popup to %s (%dx%d), pushing event...\n", url, event->data.popup.w, event->data.popup.h);
  111 + printf("[WEBCORE] stopped popup to %s (%dx%d), pushing event...\n", url, event->data.popup.w, event->data.popup.h);
105 112 }
106 113
107 114 void OnRequestDownload(WebView* caller, int download_id, const WebURL& wurl, const WebString& suggested_filename, const WebString& mime_type) {
... ... @@ -109,7 +116,7 @@ public:
109 116 const char *mime = webstring_to_buf(mime_type, NULL);
110 117 const char *url = webstring_to_buf(rurl, NULL);
111 118 const char *name = webstring_to_buf(suggested_filename, NULL);
112   - printf("[WEB] Download request [name: %s] [mime: %s] [url: %s]\n", name, mime, url);
  119 + printf("[WEBCORE] Download request [name: %s] [mime: %s] [url: %s]\n", name, mime, url);
113 120
114 121 WebEvent *event = new WebEvent();
115 122 event->kind = TE4_WEB_EVENT_DOWNLOAD_REQUEST;
... ... @@ -187,17 +194,79 @@ public:
187 194 }
188 195
189 196 virtual void OnMethodCall(WebView* caller, unsigned int remote_object_id, const WebString& method_name, const JSArray& args) {
  197 + if (remote_object_id == te4_js.remote_id() && method_name == WSLit("lua")) {
  198 + JSValue arg = args[0];
  199 + WebString wcode = arg.ToString();
  200 + const char *code = webstring_to_buf(wcode, NULL);
  201 +
  202 + WebEvent *event = new WebEvent();
  203 + event->kind = TE4_WEB_EVENT_RUN_LUA;
  204 + event->handlers = handlers;
  205 + event->data.run_lua.code = code;
  206 + push_event(event);
  207 + }
190 208 }
191 209
192   - virtual JSValue OnMethodCallWithReturnValue(WebView* caller, unsigned int remote_object_id, const WebString& method_name, const JSArray& args) {
193   - JSValue ret(false);
194   - return ret;
  210 + virtual JSValue OnMethodCallWithReturnValue(WebView* caller, unsigned int remote_object_id, const WebString& method_name, const JSArray& jsargs) {
  211 + if (remote_object_id != te4_js.remote_id()) {
  212 + JSValue ret(false);
  213 + return ret;
  214 + }
  215 +
  216 + const char *fct = webstring_to_buf(method_name, NULL);
  217 + WebJsValue ret;
  218 + int nb_args = jsargs.size();
  219 + WebJsValue *args = new WebJsValue[nb_args];
  220 + for (int i = 0; i < nb_args; i++) {
  221 + WebJsValue *wv = &args[i];
  222 + JSValue v = jsargs[i];
  223 + if (v.IsNull()) {
  224 + wv->kind = TE4_WEB_JS_NULL;
  225 + } else if (v.IsBoolean()) {
  226 + wv->kind = TE4_WEB_JS_BOOLEAN;
  227 + wv->data.b = v.ToBoolean();
  228 + } else if (v.IsNumber()) {
  229 + wv->kind = TE4_WEB_JS_NUMBER;
  230 + wv->data.n = v.ToDouble();
  231 + } else if (v.IsString()) {
  232 + wv->kind = TE4_WEB_JS_STRING;
  233 + const char *s = webstring_to_buf(v.ToString(), NULL);
  234 + wv->data.s = s;
  235 + }
  236 + }
  237 +
  238 + web_instant_js(handlers, fct, nb_args, args, &ret);
  239 +
  240 + // Free the fucking strings. I love GC. I want a GC :/
  241 + for (int i = 0; i < nb_args; i++) {
  242 + WebJsValue *wv = &args[i];
  243 + JSValue v = jsargs[i];
  244 + if (v.IsString()) free((void*)wv->data.s);
  245 + }
  246 + delete args;
  247 + free((void*)fct);
  248 +
  249 + if (ret.kind == TE4_WEB_JS_NULL) return JSValue::Null();
  250 + else if (ret.kind == TE4_WEB_JS_BOOLEAN) return JSValue(ret.data.b);
  251 + else if (ret.kind == TE4_WEB_JS_NUMBER) return JSValue(ret.data.n);
  252 + else if (ret.kind == TE4_WEB_JS_STRING) {
  253 + WebString s = WebString::CreateFromUTF8(ret.data.s, strlen(ret.data.s));
  254 + return JSValue(s);
  255 + }
  256 + return JSValue();
195 257 }
196 258 };
197 259
198   -class PhysfsDataSource : public DataSource {
  260 +class TE4DataSource : public DataSource {
199 261 public:
200   - virtual void OnRequest(int request_id, const WebString& path) {
  262 + virtual void OnRequest(int request_id, const WebString& wpath) {
  263 + const char *path = webstring_to_buf(wpath, NULL);
  264 +
  265 + WebEvent *event = new WebEvent();
  266 + event->kind = TE4_WEB_EVENT_LOCAL_REQUEST;
  267 + event->data.local_request.id = request_id;
  268 + event->data.local_request.path = path;
  269 + push_event(event);
201 270 }
202 271 };
203 272
... ... @@ -206,12 +275,9 @@ class WebViewOpaque {
206 275 public:
207 276 WebView *view;
208 277 WebListener *listener;
209   - JSObject *te4core;
210 278 };
211 279
212   -void te4_web_new(web_view_type *view, const char *url, int w, int h) {
213   - size_t urllen = strlen(url);
214   -
  280 +void te4_web_new(web_view_type *view, int w, int h) {
215 281 WebViewOpaque *opaque = new WebViewOpaque();
216 282 view->opaque = (void*)opaque;
217 283
... ... @@ -220,15 +286,16 @@ void te4_web_new(web_view_type *view, const char *url, int w, int h) {
220 286 opaque->view->set_view_listener(opaque->listener);
221 287 opaque->view->set_download_listener(opaque->listener);
222 288 opaque->view->set_load_listener(opaque->listener);
223   - opaque->te4core = NULL;
  289 + opaque->view->set_js_method_handler(opaque->listener);
224 290 view->w = w;
225 291 view->h = h;
226 292 view->closed = false;
227 293
228   - WebURL lurl(WebString::CreateFromUTF8(url, urllen));
229   - opaque->view->LoadURL(lurl);
  294 + opaque->listener->te4_js = (opaque->view->CreateGlobalJavascriptObject(WSLit("te4"))).ToObject();
  295 + opaque->listener->te4_js.SetCustomMethod(WSLit("lua"), false);
  296 +
230 297 opaque->view->SetTransparent(true);
231   - printf("Created webview: %s\n", url);
  298 + printf("Created webview: %dx%d\n", w, h);
232 299 }
233 300
234 301 bool te4_web_close(web_view_type *view) {
... ... @@ -237,13 +304,28 @@ bool te4_web_close(web_view_type *view) {
237 304 opaque->view->Destroy();
238 305 delete opaque->listener;
239 306 view->closed = true;
240   - if (opaque->te4core) delete opaque->te4core;
241 307 printf("Destroyed webview\n");
242 308 return true;
243 309 }
244 310 return false;
245 311 }
246 312
  313 +void te4_web_load_url(web_view_type *view, const char *url) {
  314 + WebViewOpaque *opaque = (WebViewOpaque*)view->opaque;
  315 + if (view->closed) return;
  316 +
  317 + size_t urllen = strlen(url);
  318 + WebURL lurl(WebString::CreateFromUTF8(url, urllen));
  319 + opaque->view->LoadURL(lurl);
  320 +}
  321 +
  322 +void te4_web_set_js_call(web_view_type *view, const char *name) {
  323 + WebViewOpaque *opaque = (WebViewOpaque*)view->opaque;
  324 + if (view->closed) return;
  325 +
  326 + opaque->listener->te4_js.SetCustomMethod(WebString::CreateFromUTF8(name, strlen(name)), true);
  327 +}
  328 +
247 329 bool te4_web_toscreen(web_view_type *view, int *w, int *h, unsigned int *tex) {
248 330 WebViewOpaque *opaque = (WebViewOpaque*)view->opaque;
249 331 if (view->closed) return false;
... ... @@ -352,6 +434,12 @@ void te4_web_download_action(web_view_type *view, long id, const char *path) {
352 434 }
353 435 }
354 436
  437 +void te4_web_reply_local(int id, const char *mime, const char *result, size_t len) {
  438 + WebString wmime = WebString::CreateFromUTF8(mime, strlen(mime));
  439 + web_data_source->SendResponse(id, len, (unsigned char *)result, wmime);
  440 +}
  441 +
  442 +
355 443 void te4_web_do_update(void (*cb)(WebEvent*)) {
356 444 if (!web_core) return;
357 445
... ... @@ -375,6 +463,12 @@ void te4_web_do_update(void (*cb)(WebEvent*)) {
375 463 case TE4_WEB_EVENT_LOADING:
376 464 free((void*)event->data.loading.url);
377 465 break;
  466 + case TE4_WEB_EVENT_LOCAL_REQUEST:
  467 + free((void*)event->data.local_request.path);
  468 + break;
  469 + case TE4_WEB_EVENT_RUN_LUA:
  470 + free((void*)event->data.run_lua.code);
  471 + break;
378 472 }
379 473
380 474 delete event;
... ... @@ -385,7 +479,8 @@ void te4_web_setup(
385 479 int argc, char **gargv, char *spawnc,
386 480 void*(*mutex_create)(), void(*mutex_destroy)(void*), void(*mutex_lock)(void*), void(*mutex_unlock)(void*),
387 481 unsigned int (*make_texture)(int, int), void (*del_texture)(unsigned int), void (*texture_update)(unsigned int, int, int, const void*),
388   - void (*key_mods)(bool*, bool*, bool*, bool*)
  482 + void (*key_mods)(bool*, bool*, bool*, bool*),
  483 + void (*instant_js)(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret)
389 484 ) {
390 485
391 486 web_mutex_create = mutex_create;
... ... @@ -396,11 +491,12 @@ void te4_web_setup(
396 491 web_del_texture = del_texture;
397 492 web_texture_update = texture_update;
398 493 web_key_mods = key_mods;
  494 + web_instant_js = instant_js;
399 495 if (!web_core) {
400 496 web_core = WebCore::Initialize(WebConfig());
401 497 web_core->set_surface_factory(new GLTextureSurfaceFactory());
402 498 web_session = web_core->CreateWebSession(WSLit(""), WebPreferences());
403   - web_data_source = new PhysfsDataSource();
  499 + web_data_source = new TE4DataSource();
404 500 web_session->AddDataSource(WSLit("te4"), web_data_source);
405 501 }
406 502 }
... ...
... ... @@ -22,10 +22,16 @@
22 22 #define WEB_TE4_API
23 23 #endif
24 24
25   -WEB_TE4_API void te4_web_setup(int argc, char **argv, char *spawn, void*(*mutex_create)(), void(*mutex_destroy)(void*), void(*mutex_lock)(void*), void(*mutex_unlock)(void*), unsigned int (*make_texture)(int, int), void (*del_texture)(unsigned int), void (*texture_update)(unsigned int, int, int, const void*), void (*)(bool*, bool*, bool*, bool*));
  25 +WEB_TE4_API void te4_web_setup(
  26 + int argc, char **argv, char *spawn,
  27 + void*(*mutex_create)(), void(*mutex_destroy)(void*), void(*mutex_lock)(void*), void(*mutex_unlock)(void*),
  28 + unsigned int (*make_texture)(int, int), void (*del_texture)(unsigned int), void (*texture_update)(unsigned int, int, int, const void*),
  29 + void (*key_mods)(bool*, bool*, bool*, bool*),
  30 + void (*web_instant_js)(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret)
  31 +);
26 32 WEB_TE4_API void te4_web_initialize();
27 33 WEB_TE4_API void te4_web_do_update(void (*cb)(WebEvent*));
28   -WEB_TE4_API void te4_web_new(web_view_type *view, const char *url, int w, int h);
  34 +WEB_TE4_API void te4_web_new(web_view_type *view, int w, int h);
29 35 WEB_TE4_API bool te4_web_close(web_view_type *view);
30 36 WEB_TE4_API bool te4_web_toscreen(web_view_type *view, int *w, int *h, unsigned int *tex);
31 37 WEB_TE4_API bool te4_web_loading(web_view_type *view);
... ... @@ -35,5 +41,8 @@ WEB_TE4_API void te4_web_inject_mouse_wheel(web_view_type *view, int x, int y);
35 41 WEB_TE4_API void te4_web_inject_mouse_button(web_view_type *view, int kind, bool up);
36 42 WEB_TE4_API void te4_web_inject_key(web_view_type *view, int scancode, int asymb, const char *uni, int unilen, bool up);
37 43 WEB_TE4_API void te4_web_download_action(web_view_type *view, long id, const char *path);
  44 +WEB_TE4_API void te4_web_reply_local(int id, const char *mime, const char *result, size_t len);
  45 +WEB_TE4_API void te4_web_load_url(web_view_type *view, const char *url);
  46 +WEB_TE4_API void te4_web_set_js_call(web_view_type *view, const char *name);
38 47
39 48 #endif
... ...
... ... @@ -15,6 +15,8 @@ enum web_event_kind {
15 15 TE4_WEB_EVENT_DOWNLOAD_UPDATE,
16 16 TE4_WEB_EVENT_DOWNLOAD_FINISH,
17 17 TE4_WEB_EVENT_LOADING,
  18 + TE4_WEB_EVENT_LOCAL_REQUEST,
  19 + TE4_WEB_EVENT_RUN_LUA,
18 20 };
19 21
20 22 typedef struct {
... ... @@ -44,9 +46,32 @@ typedef struct {
44 46 const char *url;
45 47 signed char status;
46 48 } loading;
  49 + struct {
  50 + int id;
  51 + const char *path;
  52 + } local_request;
  53 + struct {
  54 + const char *code;
  55 + } run_lua;
47 56 } data;
48 57 } WebEvent;
49 58
  59 +enum web_js_kind {
  60 + TE4_WEB_JS_NULL,
  61 + TE4_WEB_JS_BOOLEAN,
  62 + TE4_WEB_JS_NUMBER,
  63 + TE4_WEB_JS_STRING,
  64 +};
  65 +
  66 +typedef struct {
  67 + enum web_js_kind kind;
  68 + union {
  69 + bool b;
  70 + double n;
  71 + const char *s;
  72 + } data;
  73 +} WebJsValue;
  74 +
50 75 typedef struct {
51 76 void *opaque;
52 77 int w, h;
... ...
... ... @@ -24,6 +24,7 @@
24 24 #include "lauxlib.h"
25 25 #include "lualib.h"
26 26 #include "auxiliar.h"
  27 +#include "physfs.h"
27 28 #include "core_lua.h"
28 29 #include "types.h"
29 30 #include "main.h"
... ... @@ -35,10 +36,16 @@
35 36 * Grab web browser methods -- availabe only here
36 37 */
37 38 static bool webcore = FALSE;
38   -static void (*te4_web_setup)(int, char**, char*, void*(*)(), void(*)(void*), void(*)(void*), void(*)(void*), unsigned int (*)(int, int), void (*)(unsigned int), void (*)(unsigned int, int, int, const void*), void (*)(bool*, bool*, bool*, bool*));
  39 +static void (*te4_web_setup)(
  40 + int, char**, char*,
  41 + void*(*)(), void(*)(void*), void(*)(void*), void(*)(void*),
  42 + unsigned int (*)(int, int), void (*)(unsigned int), void (*)(unsigned int, int, int, const void*),
  43 + void (*)(bool*, bool*, bool*, bool*),
  44 + void (*)(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret)
  45 +);
39 46 static void (*te4_web_initialize)();
40 47 static void (*te4_web_do_update)(void (*cb)(WebEvent*));
41   -static void (*te4_web_new)(web_view_type *view, const char *url, int w, int h);
  48 +static void (*te4_web_new)(web_view_type *view, int w, int h);
42 49 static bool (*te4_web_close)(web_view_type *view);
43 50 static bool (*te4_web_toscreen)(web_view_type *view, int *w, int *h, unsigned int *tex);
44 51 static bool (*te4_web_loading)(web_view_type *view);
... ... @@ -48,19 +55,21 @@ static void (*te4_web_inject_mouse_wheel)(web_view_type *view, int x, int y);
48 55 static void (*te4_web_inject_mouse_button)(web_view_type *view, int kind, bool up);
49 56 static void (*te4_web_inject_key)(web_view_type *view, int scancode, int asymb, const char *uni, int unilen, bool up);
50 57 static void (*te4_web_download_action)(web_view_type *view, long id, const char *path);
  58 +static void (*te4_web_reply_local)(int id, const char *mime, const char *result, size_t len);
  59 +static void (*te4_web_load_url)(web_view_type *view, const char *url);
  60 +static void (*te4_web_set_js_call)(web_view_type *view, const char *name);
51 61
52 62 static int lua_web_new(lua_State *L) {
53 63 int w = luaL_checknumber(L, 1);
54 64 int h = luaL_checknumber(L, 2);
55   - const char* url = luaL_checkstring(L, 3);
56 65
57 66 web_view_type *view = (web_view_type*)lua_newuserdata(L, sizeof(web_view_type));
58 67 auxiliar_setclass(L, "web{view}", -1);
59 68
60   - lua_pushvalue(L, 4);
  69 + lua_pushvalue(L, 3);
61 70 view->handlers = luaL_ref(L, LUA_REGISTRYINDEX);
62 71
63   - te4_web_new(view, url, w, h);
  72 + te4_web_new(view, w, h);
64 73
65 74 return 1;
66 75 }
... ... @@ -73,6 +82,13 @@ static int lua_web_close(lua_State *L) {
73 82 return 0;
74 83 }
75 84
  85 +static int lua_web_load_url(lua_State *L) {
  86 + web_view_type *view = (web_view_type*)auxiliar_checkclass(L, "web{view}", 1);
  87 + const char* url = luaL_checkstring(L, 2);
  88 + te4_web_load_url(view, url);
  89 + return 0;
  90 +}
  91 +
76 92 static int lua_web_toscreen(lua_State *L) {
77 93 web_view_type *view = (web_view_type*)auxiliar_checkclass(L, "web{view}", 1);
78 94 int x = luaL_checknumber(L, 2);
... ... @@ -177,10 +193,53 @@ static int lua_web_download_action(lua_State *L) {
177 193 return 0;
178 194 }
179 195
  196 +static int lua_web_set_method(lua_State *L) {
  197 + web_view_type *view = (web_view_type*)auxiliar_checkclass(L, "web{view}", 1);
  198 + const char *name = luaL_checkstring(L, 2);
  199 + te4_web_set_js_call(view, name);
  200 + return 0;
  201 +}
  202 +
  203 +static int lua_web_local_reply_file(lua_State *L) {
  204 + int id = lua_tonumber(L, 1);
  205 + const char *mime = luaL_checkstring(L, 2);
  206 + const char *file = luaL_checkstring(L, 3);
  207 +
  208 + PHYSFS_file *f = PHYSFS_openRead(file);
  209 + if (!f) {
  210 + te4_web_reply_local(id, mime, NULL, 0);
  211 + return 0;
  212 + }
  213 +
  214 + size_t len = PHYSFS_fileLength(f);
  215 + char *data = malloc(len * sizeof(char));
  216 + size_t read = 0;
  217 + while (read < len) {
  218 + size_t rl = PHYSFS_read(f, data + read, sizeof(char), len - read);
  219 + if (rl <= 0) break;
  220 + read += rl;
  221 + }
  222 + PHYSFS_close(f);
  223 +
  224 + te4_web_reply_local(id, mime, data, read);
  225 + return 0;
  226 +}
  227 +
  228 +static int lua_web_local_reply_data(lua_State *L) {
  229 + int id = lua_tonumber(L, 1);
  230 + const char *mime = luaL_checkstring(L, 2);
  231 + size_t len;
  232 + const char *data = luaL_checklstring(L, 3, &len);
  233 +
  234 + te4_web_reply_local(id, mime, data, len);
  235 + return 0;
  236 +}
  237 +
180 238 static const struct luaL_Reg view_reg[] =
181 239 {
182 240 {"__gc", lua_web_close},
183 241 {"downloadAction", lua_web_download_action},
  242 + {"loadURL", lua_web_load_url},
184 243 {"toScreen", lua_web_toscreen},
185 244 {"focus", lua_web_focus},
186 245 {"loading", lua_web_loading},
... ... @@ -188,13 +247,15 @@ static const struct luaL_Reg view_reg[] =
188 247 {"injectMouseWheel", lua_web_inject_mouse_wheel},
189 248 {"injectMouseButton", lua_web_inject_mouse_button},
190 249 {"injectKey", lua_web_inject_key},
191   -// {"setMethod", lua_web_set_method},
  250 + {"setMethod", lua_web_set_method},
192 251 {NULL, NULL},
193 252 };
194 253
195 254 static const struct luaL_Reg weblib[] =
196 255 {
197 256 {"new", lua_web_new},
  257 + {"localReplyData", lua_web_local_reply_data},
  258 + {"localReplyFile", lua_web_local_reply_file},
198 259 {NULL, NULL},
199 260 };
200 261
... ... @@ -207,9 +268,8 @@ static void handle_event(WebEvent *event) {
207 268 lua_gettable(he_L, -2);
208 269 lua_remove(he_L, -2);
209 270 if (!lua_isnil(he_L, -1)) {
210   - lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
211 271 lua_pushstring(he_L, event->data.title);
212   - docall(he_L, 2, 0);
  272 + docall(he_L, 1, 0);
213 273 } else lua_pop(he_L, 1);
214 274 break;
215 275
... ... @@ -219,11 +279,10 @@ static void handle_event(WebEvent *event) {
219 279 lua_gettable(he_L, -2);
220 280 lua_remove(he_L, -2);
221 281 if (!lua_isnil(he_L, -1)) {
222   - lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
223 282 lua_pushstring(he_L, event->data.popup.url);
224 283 lua_pushnumber(he_L, event->data.popup.w);
225 284 lua_pushnumber(he_L, event->data.popup.h);
226   - docall(he_L, 4, 0);
  285 + docall(he_L, 3, 0);
227 286 } else lua_pop(he_L, 1);
228 287 break;
229 288
... ... @@ -233,12 +292,11 @@ static void handle_event(WebEvent *event) {
233 292 lua_gettable(he_L, -2);
234 293 lua_remove(he_L, -2);
235 294 if (!lua_isnil(he_L, -1)) {
236   - lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
237 295 lua_pushnumber(he_L, event->data.download_request.id);
238 296 lua_pushstring(he_L, event->data.download_request.url);
239 297 lua_pushstring(he_L, event->data.download_request.name);
240 298 lua_pushstring(he_L, event->data.download_request.mime);
241   - docall(he_L, 5, 0);
  299 + docall(he_L, 4, 0);
242 300 } else lua_pop(he_L, 1);
243 301 break;
244 302
... ... @@ -248,13 +306,12 @@ static void handle_event(WebEvent *event) {
248 306 lua_gettable(he_L, -2);
249 307 lua_remove(he_L, -2);
250 308 if (!lua_isnil(he_L, -1)) {
251   - lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
252 309 lua_pushnumber(he_L, event->data.download_update.id);
253 310 lua_pushnumber(he_L, event->data.download_update.got);
254 311 lua_pushnumber(he_L, event->data.download_update.total);
255 312 lua_pushnumber(he_L, event->data.download_update.percent);
256 313 lua_pushnumber(he_L, event->data.download_update.speed);
257   - docall(he_L, 6, 0);
  314 + docall(he_L, 5, 0);
258 315 } else lua_pop(he_L, 1);
259 316 break;
260 317
... ... @@ -264,9 +321,8 @@ static void handle_event(WebEvent *event) {
264 321 lua_gettable(he_L, -2);
265 322 lua_remove(he_L, -2);
266 323 if (!lua_isnil(he_L, -1)) {
267   - lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
268 324 lua_pushnumber(he_L, event->data.download_update.id);
269   - docall(he_L, 2, 0);
  325 + docall(he_L, 1, 0);
270 326 } else lua_pop(he_L, 1);
271 327 break;
272 328
... ... @@ -276,19 +332,40 @@ static void handle_event(WebEvent *event) {
276 332 lua_gettable(he_L, -2);
277 333 lua_remove(he_L, -2);
278 334 if (!lua_isnil(he_L, -1)) {
279   - lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
280 335 lua_pushstring(he_L, event->data.loading.url);
281 336 lua_pushnumber(he_L, event->data.loading.status);
282   - docall(he_L, 3, 0);
  337 + docall(he_L, 2, 0);
  338 + } else lua_pop(he_L, 1);
  339 + break;
  340 +
  341 + case TE4_WEB_EVENT_LOCAL_REQUEST:
  342 + lua_getglobal(he_L, "core");
  343 + lua_getfield(he_L, -1, "webview");
  344 + lua_getfield(he_L, -1, "responder");
  345 + lua_remove(he_L, -2);
  346 + lua_remove(he_L, -2);
  347 + if (!lua_isnil(he_L, -1)) {
  348 + lua_pushnumber(he_L, event->data.local_request.id);
  349 + lua_pushstring(he_L, event->data.local_request.path);
  350 + docall(he_L, 2, 0);
283 351 } else lua_pop(he_L, 1);
284 352 break;
  353 +
  354 + case TE4_WEB_EVENT_RUN_LUA:
  355 + if (!luaL_loadstring(he_L, event->data.run_lua.code)) {
  356 + docall(he_L, 0, 0);
  357 + } else {
  358 + printf("[WEBCORE] Failed to run lua code:\n%s\n ==>> Error: %s\n", event->data.run_lua.code, lua_tostring(he_L, -1));
  359 + lua_pop(he_L, 1);
  360 + }
  361 + break;
285 362 }
286 363 }
287 364
288 365 void te4_web_update(lua_State *L) {
289 366 if (webcore) {
290 367 he_L = L;
291   - te4_web_do_update(handle_event);
  368 + te4_web_do_update(handle_event);
292 369 }
293 370 }
294 371
... ... @@ -353,6 +430,42 @@ static void web_key_mods(bool *shift, bool *ctrl, bool *alt, bool *meta) {
353 430 if (smod & KMOD_GUI) *meta = TRUE;
354 431 }
355 432
  433 +static void web_instant_js(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret) {
  434 + lua_rawgeti(he_L, LUA_REGISTRYINDEX, handlers);
  435 + lua_pushstring(he_L, fct);
  436 + lua_gettable(he_L, -2);
  437 + lua_remove(he_L, -2);
  438 + if (!lua_isnil(he_L, -1)) {
  439 + int i;
  440 + for (i = 0; i < nb_args; i++) {
  441 + if (args[i].kind == TE4_WEB_JS_NULL) lua_pushnil(he_L);
  442 + else if (args[i].kind == TE4_WEB_JS_BOOLEAN) lua_pushboolean(he_L, args[i].data.b);
  443 + else if (args[i].kind == TE4_WEB_JS_NUMBER) lua_pushnumber(he_L, args[i].data.n);
  444 + else if (args[i].kind == TE4_WEB_JS_STRING) lua_pushstring(he_L, args[i].data.s);
  445 + }
  446 + if (!docall(he_L, nb_args, 1)) {
  447 + if (lua_isnumber(he_L, -1)) {
  448 + ret->kind = TE4_WEB_JS_NUMBER;
  449 + ret->data.n = lua_tonumber(he_L, -1);
  450 + } else if (lua_isstring(he_L, -1)) {
  451 + ret->kind = TE4_WEB_JS_STRING;
  452 + ret->data.s = lua_tostring(he_L, -1);
  453 + } else if (lua_isboolean(he_L, -1)) {
  454 + ret->kind = TE4_WEB_JS_BOOLEAN;
  455 + ret->data.b = lua_toboolean(he_L, -1);
  456 + } else {
  457 + ret->kind = TE4_WEB_JS_NULL;
  458 + }
  459 + lua_pop(he_L, 1);
  460 + } else {
  461 + ret->kind = TE4_WEB_JS_NULL;
  462 + }
  463 + } else {
  464 + ret->kind = TE4_WEB_JS_NULL;
  465 + lua_pop(he_L, 1);
  466 + }
  467 +}
  468 +
356 469 void te4_web_load() {
357 470 #if defined(SELFEXE_LINUX)
358 471 void *web = SDL_LoadObject("libte4-web.so");
... ... @@ -369,10 +482,16 @@ void te4_web_load() {
369 482
370 483 if (web) {
371 484 webcore = TRUE;
372   - te4_web_setup = (void (*)(int, char**, char*, void*(*)(), void(*)(void*), void(*)(void*), void(*)(void*), unsigned int (*)(int, int), void (*)(unsigned int), void (*)(unsigned int, int, int, const void*), void (*)(bool*, bool*, bool*, bool*) )) SDL_LoadFunction(web, "te4_web_setup");
  485 + te4_web_setup = (void (*)(
  486 + int, char**, char*,
  487 + void*(*)(), void(*)(void*), void(*)(void*), void(*)(void*),
  488 + unsigned int (*)(int, int), void (*)(unsigned int), void (*)(unsigned int, int, int, const void*),
  489 + void (*)(bool*, bool*, bool*, bool*),
  490 + void (*)(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret)
  491 + )) SDL_LoadFunction(web, "te4_web_setup");
373 492 te4_web_initialize = (void (*)()) SDL_LoadFunction(web, "te4_web_initialize");
374 493 te4_web_do_update = (void (*)(void (*cb)(WebEvent*))) SDL_LoadFunction(web, "te4_web_do_update");
375   - te4_web_new = (void (*)(web_view_type *view, const char *url, int w, int h)) SDL_LoadFunction(web, "te4_web_new");
  494 + te4_web_new = (void (*)(web_view_type *view, int w, int h)) SDL_LoadFunction(web, "te4_web_new");
376 495 te4_web_close = (bool (*)(web_view_type *view)) SDL_LoadFunction(web, "te4_web_close");
377 496 te4_web_toscreen = (bool (*)(web_view_type *view, int *w, int *h, unsigned int *tex)) SDL_LoadFunction(web, "te4_web_toscreen");
378 497 te4_web_loading = (bool (*)(web_view_type *view)) SDL_LoadFunction(web, "te4_web_loading");
... ... @@ -382,12 +501,16 @@ void te4_web_load() {
382 501 te4_web_inject_mouse_button = (void (*)(web_view_type *view, int kind, bool up)) SDL_LoadFunction(web, "te4_web_inject_mouse_button");
383 502 te4_web_inject_key = (void (*)(web_view_type *view, int scancode, int asymb, const char *uni, int unilen, bool up)) SDL_LoadFunction(web, "te4_web_inject_key");
384 503 te4_web_download_action = (void (*)(web_view_type *view, long id, const char *path)) SDL_LoadFunction(web, "te4_web_download_action");
  504 + te4_web_reply_local = (void (*)(int id, const char *mime, const char *result, size_t len)) SDL_LoadFunction(web, "te4_web_reply_local");
  505 + te4_web_load_url = (void (*)(web_view_type *view, const char *url)) SDL_LoadFunction(web, "te4_web_load_url");
  506 + te4_web_set_js_call = (void (*)(web_view_type *view, const char *name)) SDL_LoadFunction(web, "te4_web_set_js_call");
385 507
386 508 te4_web_setup(
387 509 g_argc, g_argv, NULL,
388 510 web_mutex_create, web_mutex_destroy, web_mutex_lock, web_mutex_unlock,
389 511 web_make_texture, web_del_texture, web_texture_update,
390   - web_key_mods
  512 + web_key_mods,
  513 + web_instant_js
391 514 );
392 515 }
393 516 }
... ...