Skip to content
Snippets Groups Projects
Commit 0e17e9a2 authored by DarkGod's avatar DarkGod
Browse files

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

Added a generic web rendered (not available on OSX yet): a module or addon can render UI, or parts of UI in html5/css3/javascript now.
parent 85909b73
No related branches found
No related tags found
No related merge requests found
<script type="text/javascript" src='asset://te4/data/html/jquery-1.10.2.min.js'></script> <script type="text/javascript" src='asset://te4/html/jquery-1.10.2.min.js'></script>
<p><strong>lol</strong> lolll</p> <p><strong>lol</strong> lolll</p>
<script type="text/javascript" src='asset://te4/data/html/test.js'></script> <script type="text/javascript" src='asset://te4/html/test.js'></script>
<script type="text/javascript">
te4.lua("print('plop')");
console.log("=====ret: " + te4.lolzor(1, "plop"));
$('strong').css("color", "red");
</script>
$('strong').click(function() { $('strong').click(function() {
$(this).html("CLICKED"); $(this).html("CLICKED");
te4core.testclick("theclick", 7);
}); });
\ No newline at end of file
...@@ -139,6 +139,9 @@ core.display.setGamma(config.settings.gamma_correction / 100) ...@@ -139,6 +139,9 @@ core.display.setGamma(config.settings.gamma_correction / 100)
if not config.settings.fbo_active then core.display.disableFBO() print("Disabling FBO") end if not config.settings.fbo_active then core.display.disableFBO() print("Disabling FBO") end
if not config.settings.shaders_active then core.shader.disable() print("Disabling Shaders") end if not config.settings.shaders_active then core.shader.disable() print("Disabling Shaders") end
-- Webcore local request resolver
dofile("/engine/webcore.lua")
-- Load profile configs -- Load profile configs
core.profile.createThread() core.profile.createThread()
profile = engine.PlayerProfile.new() profile = engine.PlayerProfile.new()
......
...@@ -34,6 +34,7 @@ function _M:init(t) ...@@ -34,6 +34,7 @@ function _M:init(t)
self.never_clean = t.never_clean self.never_clean = t.never_clean
self.allow_popup = t.allow_popup self.allow_popup = t.allow_popup
self.allow_login = t.allow_login self.allow_login = t.allow_login
self.custom_calls = t.custom_calls or {}
if self.allow_login == nil then self.allow_login = true end if self.allow_login == nil then self.allow_login = true end
if self.allow_login and self.url:find("^http://te4%.org/") and profile.auth then if self.allow_login and self.url:find("^http://te4%.org/") and profile.auth then
...@@ -60,18 +61,28 @@ function _M:generate() ...@@ -60,18 +61,28 @@ function _M:generate()
self.key:reset() self.key:reset()
local handlers = { local handlers = {
on_title = function(view, title) if self.on_title then self.on_title(title) end end, on_title = function(title) if self.on_title then self.on_title(title) end end,
on_popup = function(view, url, w, h) if self.allow_popup then on_popup = function(url, w, h) if self.allow_popup then
local Dialog = require "engine.ui.Dialog" local Dialog = require "engine.ui.Dialog"
Dialog:webPopup(url, w, h) Dialog:webPopup(url, w, h)
end end, end end,
on_loading = function(view, url, status) on_loading = function(url, status)
print("===loading", url, status)
self.loading = status self.loading = status
end, end,
} }
if self.allow_downloads then self:onDownload(handlers) end if self.allow_downloads then self:onDownload(handlers) end
self.view = core.webview.new(self.w, self.h, self.url, handlers) self.view = core.webview.new(self.w, self.h, handlers)
self.custom_calls.lolzor = function(nb, str)
print("call from js got: ", nb, str)
return "PLAP"
end
for name, fct in pairs(self.custom_calls) do
handlers[name] = fct
self.view:setMethod(name)
end
self.view:loadURL(self.url)
self.loading = 0 self.loading = 0
self.loading_rotation = 0 self.loading_rotation = 0
self.scroll_inertia = 0 self.scroll_inertia = 0
...@@ -155,7 +166,7 @@ end ...@@ -155,7 +166,7 @@ end
function _M:onDownload(handlers) function _M:onDownload(handlers)
local Dialog = require "engine.ui.Dialog" local Dialog = require "engine.ui.Dialog"
handlers.on_download_request = function(view, downid, url, file, mime) handlers.on_download_request = function(downid, url, file, mime)
if mime == "application/t-engine-addon" and self.allow_downloads.addons and url:find("^http://te4%.org/") then if mime == "application/t-engine-addon" and self.allow_downloads.addons and url:find("^http://te4%.org/") then
local path = fs.getRealPath("/addons/") local path = fs.getRealPath("/addons/")
if path then if path then
...@@ -192,12 +203,12 @@ function _M:onDownload(handlers) ...@@ -192,12 +203,12 @@ function _M:onDownload(handlers)
self.view:downloadAction(downid, false) self.view:downloadAction(downid, false)
end end
handlers.on_download_update = function(view, downid, cur_size, total_size, percent, speed) handlers.on_download_update = function(downid, cur_size, total_size, percent, speed)
if not self.download_dialog then return end if not self.download_dialog then return end
self.download_dialog:updateFill(cur_size, total_size, ("%d%% - %d KB/s"):format(cur_size * 100 / total_size, speed / 1024)) self.download_dialog:updateFill(cur_size, total_size, ("%d%% - %d KB/s"):format(cur_size * 100 / total_size, speed / 1024))
end end
handlers.on_download_finish = function(view, downid) handlers.on_download_finish = function(downid)
if not self.download_dialog then return end if not self.download_dialog then return end
game:unregisterDialog(self.download_dialog) game:unregisterDialog(self.download_dialog)
if self.download_dialog.install_kind == "Addon" then if self.download_dialog.install_kind == "Addon" then
......
-- TE4 - T-Engine 4
-- Copyright (C) 2009 - 2014 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
if not core.webview then return end
local class = require "class"
core.webview.paths = {}
function core.webview.responder(id, path)
path = "/"..path
print("[WEBCORE] path request: ", path)
-- Let hook do their stuff
local reply = {}
if class:triggerHook{"Web:request", path=path, reply=reply} and reply.data then
core.webview.localReplyData(id, reply.mime, reply.data)
return
end
-- No hooks, perhaps we have a registered path matching
for mpath, fct in pairs(core.webview.paths) do
local r = {path:find("^"..mpath)}
if r[1] then
table.remove(r, 1) table.remove(r, 1)
local mime, data = fct(path, unpack(r))
if mime and data then
core.webview.localReplyData(id, mime, data)
return
end
end
end
-- Default, check for a file in /data/
local mime = "application/octet-stream"
if path:find("%.html$") then mime = "text/html"
elseif path:find("%.js$") then mime = "text/javascript"
elseif path:find("%.css$") then mime = "text/css"
elseif path:find("%.png$") then mime = "image/png"
end
core.webview.localReplyFile(id, mime, "/data"..path)
end
core.webview.paths["/example/(.*)"] = function(path, sub)
return "text/html", "example sub url was: "..sub
end
...@@ -57,7 +57,7 @@ function _M:init() ...@@ -57,7 +57,7 @@ function _M:init()
l[#l+1] = {name="Credits", fct=function() game:registerDialog(require("mod.dialogs.Credits").new()) end} l[#l+1] = {name="Credits", fct=function() game:registerDialog(require("mod.dialogs.Credits").new()) end}
l[#l+1] = {name="Exit", fct=function() game:onQuit() end} l[#l+1] = {name="Exit", fct=function() game:onQuit() end}
if config.settings.cheat then l[#l+1] = {name="Reboot", fct=function() util.showMainMenu() end} end if config.settings.cheat then l[#l+1] = {name="Reboot", fct=function() util.showMainMenu() end} end
-- if config.settings.cheat then l[#l+1] = {name="webtest", fct=function() util.browserOpenUrl("http://te4.org/addons/tome?_te4") end} end if config.settings.cheat then l[#l+1] = {name="webtest", fct=function() util.browserOpenUrl("asset://te4/html/test.html") end} end
self.c_background = Button.new{text=game.stopped and "Enable background" or "Disable background", fct=function() self:switchBackground() end} self.c_background = Button.new{text=game.stopped and "Enable background" or "Disable background", fct=function() self:switchBackground() end}
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])} 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,14 +27,15 @@ unsigned int (*web_make_texture)(int w, int h);
void (*web_del_texture)(unsigned int tex); void (*web_del_texture)(unsigned int tex);
void (*web_texture_update)(unsigned int tex, int w, int h, const void* buffer); void (*web_texture_update)(unsigned int tex, int w, int h, const void* buffer);
static void (*web_key_mods)(bool *shift, bool *ctrl, bool *alt, bool *meta); static void (*web_key_mods)(bool *shift, bool *ctrl, bool *alt, bool *meta);
static void (*web_instant_js)(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret);
using namespace Awesomium; using namespace Awesomium;
class PhysfsDataSource; class TE4DataSource;
static WebCore *web_core = NULL; static WebCore *web_core = NULL;
static WebSession *web_session = NULL; static WebSession *web_session = NULL;
static PhysfsDataSource *web_data_source = NULL; static TE4DataSource *web_data_source = NULL;
class WebListener; class WebListener;
...@@ -58,6 +59,7 @@ class WebListener : ...@@ -58,6 +59,7 @@ class WebListener :
private: private:
int handlers; int handlers;
public: public:
JSObject te4_js;
WebListener(int handlers) { this->handlers = handlers; } WebListener(int handlers) { this->handlers = handlers; }
virtual void OnChangeTitle(Awesomium::WebView* caller, const Awesomium::WebString& title) { virtual void OnChangeTitle(Awesomium::WebView* caller, const Awesomium::WebString& title) {
...@@ -85,6 +87,11 @@ public: ...@@ -85,6 +87,11 @@ public:
} }
virtual void OnAddConsoleMessage(Awesomium::WebView* caller, const Awesomium::WebString& message, int line_number, const Awesomium::WebString& source) { virtual void OnAddConsoleMessage(Awesomium::WebView* caller, const Awesomium::WebString& message, int line_number, const Awesomium::WebString& source) {
char *msg = webstring_to_buf(message, NULL);
char *src = webstring_to_buf(source, NULL);
printf("[WEBCORE:console %s:%d] %s\n", src, line_number, msg);
free(msg);
free(src);
} }
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) { 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,7 +108,7 @@ public:
event->data.popup.h = initial_pos.height; event->data.popup.h = initial_pos.height;
push_event(event); push_event(event);
printf("[WEB] stopped popup to %s (%dx%d), pushing event...\n", url, event->data.popup.w, event->data.popup.h); printf("[WEBCORE] stopped popup to %s (%dx%d), pushing event...\n", url, event->data.popup.w, event->data.popup.h);
} }
void OnRequestDownload(WebView* caller, int download_id, const WebURL& wurl, const WebString& suggested_filename, const WebString& mime_type) { void OnRequestDownload(WebView* caller, int download_id, const WebURL& wurl, const WebString& suggested_filename, const WebString& mime_type) {
...@@ -109,7 +116,7 @@ public: ...@@ -109,7 +116,7 @@ public:
const char *mime = webstring_to_buf(mime_type, NULL); const char *mime = webstring_to_buf(mime_type, NULL);
const char *url = webstring_to_buf(rurl, NULL); const char *url = webstring_to_buf(rurl, NULL);
const char *name = webstring_to_buf(suggested_filename, NULL); const char *name = webstring_to_buf(suggested_filename, NULL);
printf("[WEB] Download request [name: %s] [mime: %s] [url: %s]\n", name, mime, url); printf("[WEBCORE] Download request [name: %s] [mime: %s] [url: %s]\n", name, mime, url);
WebEvent *event = new WebEvent(); WebEvent *event = new WebEvent();
event->kind = TE4_WEB_EVENT_DOWNLOAD_REQUEST; event->kind = TE4_WEB_EVENT_DOWNLOAD_REQUEST;
...@@ -187,17 +194,79 @@ public: ...@@ -187,17 +194,79 @@ public:
} }
virtual void OnMethodCall(WebView* caller, unsigned int remote_object_id, const WebString& method_name, const JSArray& args) { virtual void OnMethodCall(WebView* caller, unsigned int remote_object_id, const WebString& method_name, const JSArray& args) {
if (remote_object_id == te4_js.remote_id() && method_name == WSLit("lua")) {
JSValue arg = args[0];
WebString wcode = arg.ToString();
const char *code = webstring_to_buf(wcode, NULL);
WebEvent *event = new WebEvent();
event->kind = TE4_WEB_EVENT_RUN_LUA;
event->handlers = handlers;
event->data.run_lua.code = code;
push_event(event);
}
} }
virtual JSValue OnMethodCallWithReturnValue(WebView* caller, unsigned int remote_object_id, const WebString& method_name, const JSArray& args) { virtual JSValue OnMethodCallWithReturnValue(WebView* caller, unsigned int remote_object_id, const WebString& method_name, const JSArray& jsargs) {
JSValue ret(false); if (remote_object_id != te4_js.remote_id()) {
return ret; JSValue ret(false);
return ret;
}
const char *fct = webstring_to_buf(method_name, NULL);
WebJsValue ret;
int nb_args = jsargs.size();
WebJsValue *args = new WebJsValue[nb_args];
for (int i = 0; i < nb_args; i++) {
WebJsValue *wv = &args[i];
JSValue v = jsargs[i];
if (v.IsNull()) {
wv->kind = TE4_WEB_JS_NULL;
} else if (v.IsBoolean()) {
wv->kind = TE4_WEB_JS_BOOLEAN;
wv->data.b = v.ToBoolean();
} else if (v.IsNumber()) {
wv->kind = TE4_WEB_JS_NUMBER;
wv->data.n = v.ToDouble();
} else if (v.IsString()) {
wv->kind = TE4_WEB_JS_STRING;
const char *s = webstring_to_buf(v.ToString(), NULL);
wv->data.s = s;
}
}
web_instant_js(handlers, fct, nb_args, args, &ret);
// Free the fucking strings. I love GC. I want a GC :/
for (int i = 0; i < nb_args; i++) {
WebJsValue *wv = &args[i];
JSValue v = jsargs[i];
if (v.IsString()) free((void*)wv->data.s);
}
delete args;
free((void*)fct);
if (ret.kind == TE4_WEB_JS_NULL) return JSValue::Null();
else if (ret.kind == TE4_WEB_JS_BOOLEAN) return JSValue(ret.data.b);
else if (ret.kind == TE4_WEB_JS_NUMBER) return JSValue(ret.data.n);
else if (ret.kind == TE4_WEB_JS_STRING) {
WebString s = WebString::CreateFromUTF8(ret.data.s, strlen(ret.data.s));
return JSValue(s);
}
return JSValue();
} }
}; };
class PhysfsDataSource : public DataSource { class TE4DataSource : public DataSource {
public: public:
virtual void OnRequest(int request_id, const WebString& path) { virtual void OnRequest(int request_id, const WebString& wpath) {
const char *path = webstring_to_buf(wpath, NULL);
WebEvent *event = new WebEvent();
event->kind = TE4_WEB_EVENT_LOCAL_REQUEST;
event->data.local_request.id = request_id;
event->data.local_request.path = path;
push_event(event);
} }
}; };
...@@ -206,12 +275,9 @@ class WebViewOpaque { ...@@ -206,12 +275,9 @@ class WebViewOpaque {
public: public:
WebView *view; WebView *view;
WebListener *listener; WebListener *listener;
JSObject *te4core;
}; };
void te4_web_new(web_view_type *view, const char *url, int w, int h) { void te4_web_new(web_view_type *view, int w, int h) {
size_t urllen = strlen(url);
WebViewOpaque *opaque = new WebViewOpaque(); WebViewOpaque *opaque = new WebViewOpaque();
view->opaque = (void*)opaque; view->opaque = (void*)opaque;
...@@ -220,15 +286,16 @@ void te4_web_new(web_view_type *view, const char *url, int w, int h) { ...@@ -220,15 +286,16 @@ void te4_web_new(web_view_type *view, const char *url, int w, int h) {
opaque->view->set_view_listener(opaque->listener); opaque->view->set_view_listener(opaque->listener);
opaque->view->set_download_listener(opaque->listener); opaque->view->set_download_listener(opaque->listener);
opaque->view->set_load_listener(opaque->listener); opaque->view->set_load_listener(opaque->listener);
opaque->te4core = NULL; opaque->view->set_js_method_handler(opaque->listener);
view->w = w; view->w = w;
view->h = h; view->h = h;
view->closed = false; view->closed = false;
WebURL lurl(WebString::CreateFromUTF8(url, urllen)); opaque->listener->te4_js = (opaque->view->CreateGlobalJavascriptObject(WSLit("te4"))).ToObject();
opaque->view->LoadURL(lurl); opaque->listener->te4_js.SetCustomMethod(WSLit("lua"), false);
opaque->view->SetTransparent(true); opaque->view->SetTransparent(true);
printf("Created webview: %s\n", url); printf("Created webview: %dx%d\n", w, h);
} }
bool te4_web_close(web_view_type *view) { bool te4_web_close(web_view_type *view) {
...@@ -237,13 +304,28 @@ bool te4_web_close(web_view_type *view) { ...@@ -237,13 +304,28 @@ bool te4_web_close(web_view_type *view) {
opaque->view->Destroy(); opaque->view->Destroy();
delete opaque->listener; delete opaque->listener;
view->closed = true; view->closed = true;
if (opaque->te4core) delete opaque->te4core;
printf("Destroyed webview\n"); printf("Destroyed webview\n");
return true; return true;
} }
return false; return false;
} }
void te4_web_load_url(web_view_type *view, const char *url) {
WebViewOpaque *opaque = (WebViewOpaque*)view->opaque;
if (view->closed) return;
size_t urllen = strlen(url);
WebURL lurl(WebString::CreateFromUTF8(url, urllen));
opaque->view->LoadURL(lurl);
}
void te4_web_set_js_call(web_view_type *view, const char *name) {
WebViewOpaque *opaque = (WebViewOpaque*)view->opaque;
if (view->closed) return;
opaque->listener->te4_js.SetCustomMethod(WebString::CreateFromUTF8(name, strlen(name)), true);
}
bool te4_web_toscreen(web_view_type *view, int *w, int *h, unsigned int *tex) { bool te4_web_toscreen(web_view_type *view, int *w, int *h, unsigned int *tex) {
WebViewOpaque *opaque = (WebViewOpaque*)view->opaque; WebViewOpaque *opaque = (WebViewOpaque*)view->opaque;
if (view->closed) return false; if (view->closed) return false;
...@@ -352,6 +434,12 @@ void te4_web_download_action(web_view_type *view, long id, const char *path) { ...@@ -352,6 +434,12 @@ void te4_web_download_action(web_view_type *view, long id, const char *path) {
} }
} }
void te4_web_reply_local(int id, const char *mime, const char *result, size_t len) {
WebString wmime = WebString::CreateFromUTF8(mime, strlen(mime));
web_data_source->SendResponse(id, len, (unsigned char *)result, wmime);
}
void te4_web_do_update(void (*cb)(WebEvent*)) { void te4_web_do_update(void (*cb)(WebEvent*)) {
if (!web_core) return; if (!web_core) return;
...@@ -375,6 +463,12 @@ void te4_web_do_update(void (*cb)(WebEvent*)) { ...@@ -375,6 +463,12 @@ void te4_web_do_update(void (*cb)(WebEvent*)) {
case TE4_WEB_EVENT_LOADING: case TE4_WEB_EVENT_LOADING:
free((void*)event->data.loading.url); free((void*)event->data.loading.url);
break; break;
case TE4_WEB_EVENT_LOCAL_REQUEST:
free((void*)event->data.local_request.path);
break;
case TE4_WEB_EVENT_RUN_LUA:
free((void*)event->data.run_lua.code);
break;
} }
delete event; delete event;
...@@ -385,7 +479,8 @@ void te4_web_setup( ...@@ -385,7 +479,8 @@ void te4_web_setup(
int argc, char **gargv, char *spawnc, int argc, char **gargv, char *spawnc,
void*(*mutex_create)(), void(*mutex_destroy)(void*), void(*mutex_lock)(void*), void(*mutex_unlock)(void*), 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*), unsigned int (*make_texture)(int, int), void (*del_texture)(unsigned int), void (*texture_update)(unsigned int, int, int, const void*),
void (*key_mods)(bool*, bool*, bool*, bool*) void (*key_mods)(bool*, bool*, bool*, bool*),
void (*instant_js)(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret)
) { ) {
web_mutex_create = mutex_create; web_mutex_create = mutex_create;
...@@ -396,11 +491,12 @@ void te4_web_setup( ...@@ -396,11 +491,12 @@ void te4_web_setup(
web_del_texture = del_texture; web_del_texture = del_texture;
web_texture_update = texture_update; web_texture_update = texture_update;
web_key_mods = key_mods; web_key_mods = key_mods;
web_instant_js = instant_js;
if (!web_core) { if (!web_core) {
web_core = WebCore::Initialize(WebConfig()); web_core = WebCore::Initialize(WebConfig());
web_core->set_surface_factory(new GLTextureSurfaceFactory()); web_core->set_surface_factory(new GLTextureSurfaceFactory());
web_session = web_core->CreateWebSession(WSLit(""), WebPreferences()); web_session = web_core->CreateWebSession(WSLit(""), WebPreferences());
web_data_source = new PhysfsDataSource(); web_data_source = new TE4DataSource();
web_session->AddDataSource(WSLit("te4"), web_data_source); web_session->AddDataSource(WSLit("te4"), web_data_source);
} }
} }
......
...@@ -22,10 +22,16 @@ ...@@ -22,10 +22,16 @@
#define WEB_TE4_API #define WEB_TE4_API
#endif #endif
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*)); 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 (*key_mods)(bool*, bool*, bool*, bool*),
void (*web_instant_js)(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret)
);
WEB_TE4_API void te4_web_initialize(); WEB_TE4_API void te4_web_initialize();
WEB_TE4_API void te4_web_do_update(void (*cb)(WebEvent*)); WEB_TE4_API void te4_web_do_update(void (*cb)(WebEvent*));
WEB_TE4_API void te4_web_new(web_view_type *view, const char *url, int w, int h); WEB_TE4_API void te4_web_new(web_view_type *view, int w, int h);
WEB_TE4_API bool te4_web_close(web_view_type *view); WEB_TE4_API bool te4_web_close(web_view_type *view);
WEB_TE4_API bool te4_web_toscreen(web_view_type *view, int *w, int *h, unsigned int *tex); WEB_TE4_API bool te4_web_toscreen(web_view_type *view, int *w, int *h, unsigned int *tex);
WEB_TE4_API bool te4_web_loading(web_view_type *view); 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,5 +41,8 @@ WEB_TE4_API void te4_web_inject_mouse_wheel(web_view_type *view, int x, int y);
WEB_TE4_API void te4_web_inject_mouse_button(web_view_type *view, int kind, bool up); WEB_TE4_API void te4_web_inject_mouse_button(web_view_type *view, int kind, bool up);
WEB_TE4_API void te4_web_inject_key(web_view_type *view, int scancode, int asymb, const char *uni, int unilen, bool up); WEB_TE4_API void te4_web_inject_key(web_view_type *view, int scancode, int asymb, const char *uni, int unilen, bool up);
WEB_TE4_API void te4_web_download_action(web_view_type *view, long id, const char *path); WEB_TE4_API void te4_web_download_action(web_view_type *view, long id, const char *path);
WEB_TE4_API void te4_web_reply_local(int id, const char *mime, const char *result, size_t len);
WEB_TE4_API void te4_web_load_url(web_view_type *view, const char *url);
WEB_TE4_API void te4_web_set_js_call(web_view_type *view, const char *name);
#endif #endif
...@@ -15,6 +15,8 @@ enum web_event_kind { ...@@ -15,6 +15,8 @@ enum web_event_kind {
TE4_WEB_EVENT_DOWNLOAD_UPDATE, TE4_WEB_EVENT_DOWNLOAD_UPDATE,
TE4_WEB_EVENT_DOWNLOAD_FINISH, TE4_WEB_EVENT_DOWNLOAD_FINISH,
TE4_WEB_EVENT_LOADING, TE4_WEB_EVENT_LOADING,
TE4_WEB_EVENT_LOCAL_REQUEST,
TE4_WEB_EVENT_RUN_LUA,
}; };
typedef struct { typedef struct {
...@@ -44,9 +46,32 @@ typedef struct { ...@@ -44,9 +46,32 @@ typedef struct {
const char *url; const char *url;
signed char status; signed char status;
} loading; } loading;
struct {
int id;
const char *path;
} local_request;
struct {
const char *code;
} run_lua;
} data; } data;
} WebEvent; } WebEvent;
enum web_js_kind {
TE4_WEB_JS_NULL,
TE4_WEB_JS_BOOLEAN,
TE4_WEB_JS_NUMBER,
TE4_WEB_JS_STRING,
};
typedef struct {
enum web_js_kind kind;
union {
bool b;
double n;
const char *s;
} data;
} WebJsValue;
typedef struct { typedef struct {
void *opaque; void *opaque;
int w, h; int w, h;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
#include "auxiliar.h" #include "auxiliar.h"
#include "physfs.h"
#include "core_lua.h" #include "core_lua.h"
#include "types.h" #include "types.h"
#include "main.h" #include "main.h"
...@@ -35,10 +36,16 @@ ...@@ -35,10 +36,16 @@
* Grab web browser methods -- availabe only here * Grab web browser methods -- availabe only here
*/ */
static bool webcore = FALSE; static bool webcore = FALSE;
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*)); 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*),
void (*)(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret)
);
static void (*te4_web_initialize)(); static void (*te4_web_initialize)();
static void (*te4_web_do_update)(void (*cb)(WebEvent*)); static void (*te4_web_do_update)(void (*cb)(WebEvent*));
static void (*te4_web_new)(web_view_type *view, const char *url, int w, int h); static void (*te4_web_new)(web_view_type *view, int w, int h);
static bool (*te4_web_close)(web_view_type *view); static bool (*te4_web_close)(web_view_type *view);
static bool (*te4_web_toscreen)(web_view_type *view, int *w, int *h, unsigned int *tex); static bool (*te4_web_toscreen)(web_view_type *view, int *w, int *h, unsigned int *tex);
static bool (*te4_web_loading)(web_view_type *view); 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,19 +55,21 @@ static void (*te4_web_inject_mouse_wheel)(web_view_type *view, int x, int y);
static void (*te4_web_inject_mouse_button)(web_view_type *view, int kind, bool up); static void (*te4_web_inject_mouse_button)(web_view_type *view, int kind, bool up);
static void (*te4_web_inject_key)(web_view_type *view, int scancode, int asymb, const char *uni, int unilen, bool up); static void (*te4_web_inject_key)(web_view_type *view, int scancode, int asymb, const char *uni, int unilen, bool up);
static void (*te4_web_download_action)(web_view_type *view, long id, const char *path); static void (*te4_web_download_action)(web_view_type *view, long id, const char *path);
static void (*te4_web_reply_local)(int id, const char *mime, const char *result, size_t len);
static void (*te4_web_load_url)(web_view_type *view, const char *url);
static void (*te4_web_set_js_call)(web_view_type *view, const char *name);
static int lua_web_new(lua_State *L) { static int lua_web_new(lua_State *L) {
int w = luaL_checknumber(L, 1); int w = luaL_checknumber(L, 1);
int h = luaL_checknumber(L, 2); int h = luaL_checknumber(L, 2);
const char* url = luaL_checkstring(L, 3);
web_view_type *view = (web_view_type*)lua_newuserdata(L, sizeof(web_view_type)); web_view_type *view = (web_view_type*)lua_newuserdata(L, sizeof(web_view_type));
auxiliar_setclass(L, "web{view}", -1); auxiliar_setclass(L, "web{view}", -1);
lua_pushvalue(L, 4); lua_pushvalue(L, 3);
view->handlers = luaL_ref(L, LUA_REGISTRYINDEX); view->handlers = luaL_ref(L, LUA_REGISTRYINDEX);
te4_web_new(view, url, w, h); te4_web_new(view, w, h);
return 1; return 1;
} }
...@@ -73,6 +82,13 @@ static int lua_web_close(lua_State *L) { ...@@ -73,6 +82,13 @@ static int lua_web_close(lua_State *L) {
return 0; return 0;
} }
static int lua_web_load_url(lua_State *L) {
web_view_type *view = (web_view_type*)auxiliar_checkclass(L, "web{view}", 1);
const char* url = luaL_checkstring(L, 2);
te4_web_load_url(view, url);
return 0;
}
static int lua_web_toscreen(lua_State *L) { static int lua_web_toscreen(lua_State *L) {
web_view_type *view = (web_view_type*)auxiliar_checkclass(L, "web{view}", 1); web_view_type *view = (web_view_type*)auxiliar_checkclass(L, "web{view}", 1);
int x = luaL_checknumber(L, 2); int x = luaL_checknumber(L, 2);
...@@ -177,10 +193,53 @@ static int lua_web_download_action(lua_State *L) { ...@@ -177,10 +193,53 @@ static int lua_web_download_action(lua_State *L) {
return 0; return 0;
} }
static int lua_web_set_method(lua_State *L) {
web_view_type *view = (web_view_type*)auxiliar_checkclass(L, "web{view}", 1);
const char *name = luaL_checkstring(L, 2);
te4_web_set_js_call(view, name);
return 0;
}
static int lua_web_local_reply_file(lua_State *L) {
int id = lua_tonumber(L, 1);
const char *mime = luaL_checkstring(L, 2);
const char *file = luaL_checkstring(L, 3);
PHYSFS_file *f = PHYSFS_openRead(file);
if (!f) {
te4_web_reply_local(id, mime, NULL, 0);
return 0;
}
size_t len = PHYSFS_fileLength(f);
char *data = malloc(len * sizeof(char));
size_t read = 0;
while (read < len) {
size_t rl = PHYSFS_read(f, data + read, sizeof(char), len - read);
if (rl <= 0) break;
read += rl;
}
PHYSFS_close(f);
te4_web_reply_local(id, mime, data, read);
return 0;
}
static int lua_web_local_reply_data(lua_State *L) {
int id = lua_tonumber(L, 1);
const char *mime = luaL_checkstring(L, 2);
size_t len;
const char *data = luaL_checklstring(L, 3, &len);
te4_web_reply_local(id, mime, data, len);
return 0;
}
static const struct luaL_Reg view_reg[] = static const struct luaL_Reg view_reg[] =
{ {
{"__gc", lua_web_close}, {"__gc", lua_web_close},
{"downloadAction", lua_web_download_action}, {"downloadAction", lua_web_download_action},
{"loadURL", lua_web_load_url},
{"toScreen", lua_web_toscreen}, {"toScreen", lua_web_toscreen},
{"focus", lua_web_focus}, {"focus", lua_web_focus},
{"loading", lua_web_loading}, {"loading", lua_web_loading},
...@@ -188,13 +247,15 @@ static const struct luaL_Reg view_reg[] = ...@@ -188,13 +247,15 @@ static const struct luaL_Reg view_reg[] =
{"injectMouseWheel", lua_web_inject_mouse_wheel}, {"injectMouseWheel", lua_web_inject_mouse_wheel},
{"injectMouseButton", lua_web_inject_mouse_button}, {"injectMouseButton", lua_web_inject_mouse_button},
{"injectKey", lua_web_inject_key}, {"injectKey", lua_web_inject_key},
// {"setMethod", lua_web_set_method}, {"setMethod", lua_web_set_method},
{NULL, NULL}, {NULL, NULL},
}; };
static const struct luaL_Reg weblib[] = static const struct luaL_Reg weblib[] =
{ {
{"new", lua_web_new}, {"new", lua_web_new},
{"localReplyData", lua_web_local_reply_data},
{"localReplyFile", lua_web_local_reply_file},
{NULL, NULL}, {NULL, NULL},
}; };
...@@ -207,9 +268,8 @@ static void handle_event(WebEvent *event) { ...@@ -207,9 +268,8 @@ static void handle_event(WebEvent *event) {
lua_gettable(he_L, -2); lua_gettable(he_L, -2);
lua_remove(he_L, -2); lua_remove(he_L, -2);
if (!lua_isnil(he_L, -1)) { if (!lua_isnil(he_L, -1)) {
lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
lua_pushstring(he_L, event->data.title); lua_pushstring(he_L, event->data.title);
docall(he_L, 2, 0); docall(he_L, 1, 0);
} else lua_pop(he_L, 1); } else lua_pop(he_L, 1);
break; break;
...@@ -219,11 +279,10 @@ static void handle_event(WebEvent *event) { ...@@ -219,11 +279,10 @@ static void handle_event(WebEvent *event) {
lua_gettable(he_L, -2); lua_gettable(he_L, -2);
lua_remove(he_L, -2); lua_remove(he_L, -2);
if (!lua_isnil(he_L, -1)) { if (!lua_isnil(he_L, -1)) {
lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
lua_pushstring(he_L, event->data.popup.url); lua_pushstring(he_L, event->data.popup.url);
lua_pushnumber(he_L, event->data.popup.w); lua_pushnumber(he_L, event->data.popup.w);
lua_pushnumber(he_L, event->data.popup.h); lua_pushnumber(he_L, event->data.popup.h);
docall(he_L, 4, 0); docall(he_L, 3, 0);
} else lua_pop(he_L, 1); } else lua_pop(he_L, 1);
break; break;
...@@ -233,12 +292,11 @@ static void handle_event(WebEvent *event) { ...@@ -233,12 +292,11 @@ static void handle_event(WebEvent *event) {
lua_gettable(he_L, -2); lua_gettable(he_L, -2);
lua_remove(he_L, -2); lua_remove(he_L, -2);
if (!lua_isnil(he_L, -1)) { if (!lua_isnil(he_L, -1)) {
lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
lua_pushnumber(he_L, event->data.download_request.id); lua_pushnumber(he_L, event->data.download_request.id);
lua_pushstring(he_L, event->data.download_request.url); lua_pushstring(he_L, event->data.download_request.url);
lua_pushstring(he_L, event->data.download_request.name); lua_pushstring(he_L, event->data.download_request.name);
lua_pushstring(he_L, event->data.download_request.mime); lua_pushstring(he_L, event->data.download_request.mime);
docall(he_L, 5, 0); docall(he_L, 4, 0);
} else lua_pop(he_L, 1); } else lua_pop(he_L, 1);
break; break;
...@@ -248,13 +306,12 @@ static void handle_event(WebEvent *event) { ...@@ -248,13 +306,12 @@ static void handle_event(WebEvent *event) {
lua_gettable(he_L, -2); lua_gettable(he_L, -2);
lua_remove(he_L, -2); lua_remove(he_L, -2);
if (!lua_isnil(he_L, -1)) { if (!lua_isnil(he_L, -1)) {
lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
lua_pushnumber(he_L, event->data.download_update.id); lua_pushnumber(he_L, event->data.download_update.id);
lua_pushnumber(he_L, event->data.download_update.got); lua_pushnumber(he_L, event->data.download_update.got);
lua_pushnumber(he_L, event->data.download_update.total); lua_pushnumber(he_L, event->data.download_update.total);
lua_pushnumber(he_L, event->data.download_update.percent); lua_pushnumber(he_L, event->data.download_update.percent);
lua_pushnumber(he_L, event->data.download_update.speed); lua_pushnumber(he_L, event->data.download_update.speed);
docall(he_L, 6, 0); docall(he_L, 5, 0);
} else lua_pop(he_L, 1); } else lua_pop(he_L, 1);
break; break;
...@@ -264,9 +321,8 @@ static void handle_event(WebEvent *event) { ...@@ -264,9 +321,8 @@ static void handle_event(WebEvent *event) {
lua_gettable(he_L, -2); lua_gettable(he_L, -2);
lua_remove(he_L, -2); lua_remove(he_L, -2);
if (!lua_isnil(he_L, -1)) { if (!lua_isnil(he_L, -1)) {
lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
lua_pushnumber(he_L, event->data.download_update.id); lua_pushnumber(he_L, event->data.download_update.id);
docall(he_L, 2, 0); docall(he_L, 1, 0);
} else lua_pop(he_L, 1); } else lua_pop(he_L, 1);
break; break;
...@@ -276,19 +332,40 @@ static void handle_event(WebEvent *event) { ...@@ -276,19 +332,40 @@ static void handle_event(WebEvent *event) {
lua_gettable(he_L, -2); lua_gettable(he_L, -2);
lua_remove(he_L, -2); lua_remove(he_L, -2);
if (!lua_isnil(he_L, -1)) { if (!lua_isnil(he_L, -1)) {
lua_rawgeti(he_L, LUA_REGISTRYINDEX, event->handlers);
lua_pushstring(he_L, event->data.loading.url); lua_pushstring(he_L, event->data.loading.url);
lua_pushnumber(he_L, event->data.loading.status); lua_pushnumber(he_L, event->data.loading.status);
docall(he_L, 3, 0); docall(he_L, 2, 0);
} else lua_pop(he_L, 1);
break;
case TE4_WEB_EVENT_LOCAL_REQUEST:
lua_getglobal(he_L, "core");
lua_getfield(he_L, -1, "webview");
lua_getfield(he_L, -1, "responder");
lua_remove(he_L, -2);
lua_remove(he_L, -2);
if (!lua_isnil(he_L, -1)) {
lua_pushnumber(he_L, event->data.local_request.id);
lua_pushstring(he_L, event->data.local_request.path);
docall(he_L, 2, 0);
} else lua_pop(he_L, 1); } else lua_pop(he_L, 1);
break; break;
case TE4_WEB_EVENT_RUN_LUA:
if (!luaL_loadstring(he_L, event->data.run_lua.code)) {
docall(he_L, 0, 0);
} else {
printf("[WEBCORE] Failed to run lua code:\n%s\n ==>> Error: %s\n", event->data.run_lua.code, lua_tostring(he_L, -1));
lua_pop(he_L, 1);
}
break;
} }
} }
void te4_web_update(lua_State *L) { void te4_web_update(lua_State *L) {
if (webcore) { if (webcore) {
he_L = L; he_L = L;
te4_web_do_update(handle_event); te4_web_do_update(handle_event);
} }
} }
...@@ -353,6 +430,42 @@ static void web_key_mods(bool *shift, bool *ctrl, bool *alt, bool *meta) { ...@@ -353,6 +430,42 @@ static void web_key_mods(bool *shift, bool *ctrl, bool *alt, bool *meta) {
if (smod & KMOD_GUI) *meta = TRUE; if (smod & KMOD_GUI) *meta = TRUE;
} }
static void web_instant_js(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret) {
lua_rawgeti(he_L, LUA_REGISTRYINDEX, handlers);
lua_pushstring(he_L, fct);
lua_gettable(he_L, -2);
lua_remove(he_L, -2);
if (!lua_isnil(he_L, -1)) {
int i;
for (i = 0; i < nb_args; i++) {
if (args[i].kind == TE4_WEB_JS_NULL) lua_pushnil(he_L);
else if (args[i].kind == TE4_WEB_JS_BOOLEAN) lua_pushboolean(he_L, args[i].data.b);
else if (args[i].kind == TE4_WEB_JS_NUMBER) lua_pushnumber(he_L, args[i].data.n);
else if (args[i].kind == TE4_WEB_JS_STRING) lua_pushstring(he_L, args[i].data.s);
}
if (!docall(he_L, nb_args, 1)) {
if (lua_isnumber(he_L, -1)) {
ret->kind = TE4_WEB_JS_NUMBER;
ret->data.n = lua_tonumber(he_L, -1);
} else if (lua_isstring(he_L, -1)) {
ret->kind = TE4_WEB_JS_STRING;
ret->data.s = lua_tostring(he_L, -1);
} else if (lua_isboolean(he_L, -1)) {
ret->kind = TE4_WEB_JS_BOOLEAN;
ret->data.b = lua_toboolean(he_L, -1);
} else {
ret->kind = TE4_WEB_JS_NULL;
}
lua_pop(he_L, 1);
} else {
ret->kind = TE4_WEB_JS_NULL;
}
} else {
ret->kind = TE4_WEB_JS_NULL;
lua_pop(he_L, 1);
}
}
void te4_web_load() { void te4_web_load() {
#if defined(SELFEXE_LINUX) #if defined(SELFEXE_LINUX)
void *web = SDL_LoadObject("libte4-web.so"); void *web = SDL_LoadObject("libte4-web.so");
...@@ -369,10 +482,16 @@ void te4_web_load() { ...@@ -369,10 +482,16 @@ void te4_web_load() {
if (web) { if (web) {
webcore = TRUE; webcore = TRUE;
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"); 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*),
void (*)(int handlers, const char *fct, int nb_args, WebJsValue *args, WebJsValue *ret)
)) SDL_LoadFunction(web, "te4_web_setup");
te4_web_initialize = (void (*)()) SDL_LoadFunction(web, "te4_web_initialize"); te4_web_initialize = (void (*)()) SDL_LoadFunction(web, "te4_web_initialize");
te4_web_do_update = (void (*)(void (*cb)(WebEvent*))) SDL_LoadFunction(web, "te4_web_do_update"); te4_web_do_update = (void (*)(void (*cb)(WebEvent*))) SDL_LoadFunction(web, "te4_web_do_update");
te4_web_new = (void (*)(web_view_type *view, const char *url, int w, int h)) SDL_LoadFunction(web, "te4_web_new"); te4_web_new = (void (*)(web_view_type *view, int w, int h)) SDL_LoadFunction(web, "te4_web_new");
te4_web_close = (bool (*)(web_view_type *view)) SDL_LoadFunction(web, "te4_web_close"); te4_web_close = (bool (*)(web_view_type *view)) SDL_LoadFunction(web, "te4_web_close");
te4_web_toscreen = (bool (*)(web_view_type *view, int *w, int *h, unsigned int *tex)) SDL_LoadFunction(web, "te4_web_toscreen"); te4_web_toscreen = (bool (*)(web_view_type *view, int *w, int *h, unsigned int *tex)) SDL_LoadFunction(web, "te4_web_toscreen");
te4_web_loading = (bool (*)(web_view_type *view)) SDL_LoadFunction(web, "te4_web_loading"); te4_web_loading = (bool (*)(web_view_type *view)) SDL_LoadFunction(web, "te4_web_loading");
...@@ -382,12 +501,16 @@ void te4_web_load() { ...@@ -382,12 +501,16 @@ void te4_web_load() {
te4_web_inject_mouse_button = (void (*)(web_view_type *view, int kind, bool up)) SDL_LoadFunction(web, "te4_web_inject_mouse_button"); te4_web_inject_mouse_button = (void (*)(web_view_type *view, int kind, bool up)) SDL_LoadFunction(web, "te4_web_inject_mouse_button");
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"); 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");
te4_web_download_action = (void (*)(web_view_type *view, long id, const char *path)) SDL_LoadFunction(web, "te4_web_download_action"); te4_web_download_action = (void (*)(web_view_type *view, long id, const char *path)) SDL_LoadFunction(web, "te4_web_download_action");
te4_web_reply_local = (void (*)(int id, const char *mime, const char *result, size_t len)) SDL_LoadFunction(web, "te4_web_reply_local");
te4_web_load_url = (void (*)(web_view_type *view, const char *url)) SDL_LoadFunction(web, "te4_web_load_url");
te4_web_set_js_call = (void (*)(web_view_type *view, const char *name)) SDL_LoadFunction(web, "te4_web_set_js_call");
te4_web_setup( te4_web_setup(
g_argc, g_argv, NULL, g_argc, g_argv, NULL,
web_mutex_create, web_mutex_destroy, web_mutex_lock, web_mutex_unlock, web_mutex_create, web_mutex_destroy, web_mutex_lock, web_mutex_unlock,
web_make_texture, web_del_texture, web_texture_update, web_make_texture, web_del_texture, web_texture_update,
web_key_mods web_key_mods,
web_instant_js
); );
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment