-
This commit is contained in:
@@ -1,31 +1,85 @@
|
||||
#include "rktwebview_internal.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <chrono>
|
||||
#include <stdint.h>
|
||||
//#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "rktwebview_qt.h"
|
||||
#include "rktwebview.h"
|
||||
#include "rkt_protocol.h"
|
||||
#include <spawn.h>
|
||||
#include "shmqueue.h"
|
||||
#include "json.h"
|
||||
|
||||
#define SHM_SIZE (10 * 1024 * 1024) // 10MB
|
||||
#define COMMAND_SLOT 1
|
||||
#define COMMAND_RESULT_SLOT 2
|
||||
#define EVENT_SLOT 3
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Utility functions
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct {
|
||||
std::string name;
|
||||
size_t shm_size;
|
||||
Shm *shm;
|
||||
ShmQueue *command_queue;
|
||||
ShmQueue *command_result_queue;
|
||||
ShmQueue *event_queue;
|
||||
pid_t rkt_webview_prg_pid;
|
||||
bool rkt_webview_prg_started;
|
||||
} Handle_t;
|
||||
|
||||
Handle_t *handler = nullptr;
|
||||
|
||||
static bool fileExists(const char *filename) {
|
||||
return access(filename, X_OK) != -1;
|
||||
}
|
||||
|
||||
uint64_t current_ms() {
|
||||
using namespace std::chrono;
|
||||
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
bool runRktWebview(Handle_t *handler)
|
||||
{
|
||||
// run rktwebview_prg using the environment variable RKT_WEBVIEW_PRG
|
||||
#ifdef _WIN32
|
||||
#else
|
||||
char *rkt_webview_prg_path = getenv("RKT_WEBVIEW_PRG");
|
||||
if (rkt_webview_prg_path == nullptr) {
|
||||
fprintf(stderr, "RKT_WEBVIEW_PRG environment variable not set, cannot start webview program\n");
|
||||
return false;
|
||||
}
|
||||
if (!fileExists(rkt_webview_prg_path)) {
|
||||
fprintf(stderr, "%s does not exist or is not executable\n", rkt_webview_prg_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
char shm_size_str[30];
|
||||
char command_slot[10];
|
||||
char command_result_slot[10];
|
||||
char event_slot[10];
|
||||
|
||||
sprintf(shm_size_str, "%ld", handler->shm_size);
|
||||
sprintf(command_slot, "%d", COMMAND_SLOT);
|
||||
sprintf(command_result_slot, "%d", COMMAND_RESULT_SLOT);
|
||||
sprintf(event_slot, "%d", EVENT_SLOT);
|
||||
|
||||
char *argv[] = { rkt_webview_prg_path, const_cast<char *>(handler->name.c_str()), shm_size_str, command_slot, command_result_slot, event_slot, nullptr };
|
||||
|
||||
int r = posix_spawn(&handler->rkt_webview_prg_pid, rkt_webview_prg_path, nullptr, nullptr, argv, environ);
|
||||
|
||||
return (r == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Main C Interface
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct {
|
||||
Shm *shm;
|
||||
ShmQueue *command_queue;
|
||||
ShmQueue *event_queue;
|
||||
Rktwebview_qt *rkt;
|
||||
} Handle_t;
|
||||
|
||||
Handle_t *handler = nullptr;
|
||||
|
||||
void rkt_webview_cleanup()
|
||||
{
|
||||
@@ -54,76 +108,190 @@ void rkt_webview_cleanup()
|
||||
handler = nullptr;
|
||||
}
|
||||
*/
|
||||
fprintf(stderr, "Sending quit message\n");
|
||||
handler->command_queue->enqueue(CMD_QUIT);
|
||||
fprintf(stderr, "Message sent\n");
|
||||
bool stopped = false;
|
||||
while(!stopped) {
|
||||
int cmd;
|
||||
std::string s;
|
||||
fprintf(stderr, "Getting result of quit message\n");
|
||||
handler->command_result_queue->dequeue(cmd, s, true);
|
||||
fprintf(stderr, "got %d\n", cmd);
|
||||
if (cmd == RESULT_QUIT) {
|
||||
stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
delete handler->event_queue;
|
||||
delete handler->command_result_queue;
|
||||
delete handler->command_queue;
|
||||
delete handler->shm;
|
||||
delete handler;
|
||||
handler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void rkt_webview_init()
|
||||
{
|
||||
if (handler == nullptr) {
|
||||
handler = new Rktwebview_qt();
|
||||
}
|
||||
// Create shared memory and communication queues
|
||||
|
||||
if (handler->app() == nullptr) {
|
||||
handler->initApp();
|
||||
char buf[1024];
|
||||
#ifdef DEBUG
|
||||
sprintf(buf, "rktwebview-dbg");
|
||||
#else
|
||||
pid_t p = getpid();
|
||||
sprintf(buf, "rktwebview-%x", p);
|
||||
#endif
|
||||
|
||||
handler = new Handle_t;
|
||||
handler->name = buf;
|
||||
|
||||
handler->shm_size = SHM_SIZE;
|
||||
handler->shm = new Shm(handler->name.data(), handler->shm_size, true);
|
||||
handler->command_queue = new ShmQueue(handler->shm, COMMAND_SLOT, true);
|
||||
handler->command_result_queue = new ShmQueue(handler->shm, COMMAND_RESULT_SLOT, true);
|
||||
handler->event_queue = new ShmQueue(handler->shm, EVENT_SLOT, true);
|
||||
|
||||
// Start rktwebview_prg application with the right information
|
||||
#ifndef DEBUG
|
||||
handler->rkt_webview_prg_started = runRktWebview(handler);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool rkt_webview_valid(rktwebview_t wv)
|
||||
{
|
||||
rkt_webview_init();
|
||||
if (handler != nullptr && handler->rkt_webview_prg_started) {
|
||||
handler->command_queue->enqueue(CMD_HANDLE_IS_VALID);
|
||||
int result;
|
||||
std::string json_result;
|
||||
handler->command_result_queue->dequeue(result, json_result, true);
|
||||
return result == 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
rkt_wv_context_t rkt_webview_new_context(const char *boilerplate_js, const char *optional_server_cert_pem)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->newContext(boilerplate_js, optional_server_cert_pem);
|
||||
|
||||
JSON j;
|
||||
|
||||
std::string bpj(boilerplate_js);
|
||||
bool has_pem_cert = optional_server_cert_pem != nullptr;
|
||||
std::string osc(has_pem_cert ? optional_server_cert_pem : "");
|
||||
|
||||
j["boilerplate_js"] = bpj;
|
||||
j["has_pem_cert"] = has_pem_cert;
|
||||
j["pem_cert"] = osc;
|
||||
|
||||
handler->command_queue->enqueue(CMD_CONTEXT_NEW, j.dump());
|
||||
|
||||
int result;
|
||||
std::string json_result;
|
||||
handler->command_result_queue->dequeue(result, json_result, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
int rkt_webview_create(rkt_wv_context_t context, rktwebview_t parent, event_cb_t js_event_cb)
|
||||
int rkt_webview_create(rkt_wv_context_t context, rktwebview_t parent)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktWebViewCreate(context, parent, js_event_cb);
|
||||
JSON j;
|
||||
j["context"] = context;
|
||||
j["parent"] = parent;
|
||||
|
||||
handler->command_queue->enqueue(CMD_CREATE_WV, j.dump());
|
||||
|
||||
int result;
|
||||
std::string json_result;
|
||||
handler->command_result_queue->dequeue(result, json_result, true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void rkt_webview_close(rktwebview_t wv)
|
||||
{
|
||||
rkt_webview_init();
|
||||
handler->rktWebViewClose(wv);
|
||||
|
||||
JSON j;
|
||||
j["wv"] = wv;
|
||||
handler->command_queue->enqueue(CMD_CLOSE_WV, j.dump());
|
||||
}
|
||||
|
||||
#define CMDRES4(cmd, wv, key, val, key2, val2, key3, val3, key4, val4) \
|
||||
rkt_webview_init(); \
|
||||
JSON j; \
|
||||
j["wv"] = wv; \
|
||||
j[key] = val; \
|
||||
j[key2] = val2; \
|
||||
j[key3] = val3; \
|
||||
j[key4] = val4; \
|
||||
handler->command_queue->enqueue(cmd, j.dump()); \
|
||||
int result; \
|
||||
std::string json_result; \
|
||||
handler->command_result_queue->dequeue(result, json_result, true); \
|
||||
result_t r = static_cast<result_t>(result); \
|
||||
return r;
|
||||
|
||||
#define CMDRES3(cmd, wv, key, val, key2, val2, key3, val3) \
|
||||
CMDRES4(cmd, wv, key, val, key2, val2, key3, val3, "nil3", "none")
|
||||
|
||||
#define CMDRES2(cmd, wv, key, val, key2, val2) \
|
||||
CMDRES3(cmd, wv, key, val, key2, val2, "nil2", "none")
|
||||
|
||||
#define CMDRES(cmd, wv, key, val) \
|
||||
CMDRES2(cmd, wv, key, val, "nil1", "none")
|
||||
|
||||
#define CMDRES0(cmd, wv) \
|
||||
CMDRES(cmd, wv, "nil0", "none")
|
||||
|
||||
result_t rkt_webview_set_url(rktwebview_t wv, const char *url)
|
||||
{
|
||||
rkt_webview_init();
|
||||
result_t r = handler->rktSetUrl(wv, url);
|
||||
return r;
|
||||
CMDRES(CMD_SET_URL, wv, "url", url)
|
||||
}
|
||||
|
||||
result_t rkt_webview_set_html(rktwebview_t wv, const char *url)
|
||||
result_t rkt_webview_set_html(rktwebview_t wv, const char *html)
|
||||
{
|
||||
rkt_webview_init();
|
||||
result_t r = handler->rktSetHtml(wv, url);
|
||||
return r;
|
||||
CMDRES(CMD_SET_HTML, wv, "html", html)
|
||||
}
|
||||
|
||||
|
||||
result_t rkt_webview_run_js(rktwebview_t wv, const char *js)
|
||||
{
|
||||
rkt_webview_init();
|
||||
result_t r = handler->rktRunJs(wv, js);
|
||||
return r;
|
||||
CMDRES(CMD_RUN_JS, wv, "js", js)
|
||||
}
|
||||
|
||||
rkt_data_t *rkt_webview_call_js(rktwebview_t wv, const char *js)
|
||||
{
|
||||
rkt_webview_init();
|
||||
rkt_data_t *r = handler->rktCallJs(wv, js);
|
||||
|
||||
JSON j;
|
||||
j["wv"] = wv;
|
||||
j["js"] = std::string(js);
|
||||
handler->command_queue->enqueue(CMD_CALL_JS, j.dump());
|
||||
|
||||
int result;
|
||||
std::string json_result;
|
||||
handler->command_result_queue->dequeue(result, json_result, true);
|
||||
|
||||
rkt_data_t *r = new rkt_data_t();
|
||||
r->kind = rkt_data_kind_t::js_result;
|
||||
r->data.js_result.result = static_cast<result_t>(result);
|
||||
r->data.js_result.value = strdup(json_result.c_str());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
result_t rkt_webview_open_devtools(rktwebview_t wv)
|
||||
{
|
||||
rkt_webview_init();
|
||||
result_t r = handler->rktOpenDevtools(wv);
|
||||
return r;
|
||||
CMDRES(CMD_OPEN_DEVTOOLS, wv, "nil", "none")
|
||||
}
|
||||
|
||||
/*
|
||||
void rkt_webview_process_events(int for_ms)
|
||||
{
|
||||
rkt_webview_init();
|
||||
@@ -136,106 +304,94 @@ void rkt_webview_process_events(int for_ms)
|
||||
handler->doEvents();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
result_t rkt_webview_move(rktwebview_t wv, int x, int y)
|
||||
{
|
||||
rkt_webview_init();
|
||||
|
||||
result_t r = handler->rktMove(wv, x, y);
|
||||
return r;
|
||||
CMDRES2(CMD_MOVE, wv, "x", x, "y", y)
|
||||
}
|
||||
|
||||
|
||||
result_t rkt_webview_resize(rktwebview_t wv, int width, int height)
|
||||
{
|
||||
rkt_webview_init();
|
||||
|
||||
result_t r = handler->rktResize(wv, width, height);
|
||||
return r;
|
||||
CMDRES2(CMD_RESIZE, wv, "w", width, "h", height)
|
||||
}
|
||||
|
||||
|
||||
bool rkt_webview_valid(rktwebview_t wv)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktValid(wv);
|
||||
}
|
||||
|
||||
result_t rkt_webview_hide(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktHideWindow(w);
|
||||
|
||||
CMDRES0(CMD_HIDE, w)
|
||||
}
|
||||
|
||||
result_t rkt_webview_show(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktShowWindow(w);
|
||||
CMDRES0(CMD_SHOW, w)
|
||||
}
|
||||
|
||||
result_t rkt_webview_present(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktPresentWindow(w);
|
||||
CMDRES0(CMD_PRESENT, w)
|
||||
}
|
||||
|
||||
result_t rkt_webview_maximize(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktMaximizeWindow(w);
|
||||
CMDRES0(CMD_MAXIMIZE, w)
|
||||
}
|
||||
|
||||
result_t rkt_webview_minimize(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktMinimizeWindow(w);
|
||||
CMDRES0(CMD_MINIMIZE, w)
|
||||
}
|
||||
|
||||
result_t rkt_webview_show_normal(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktShowNormalWindow(w);
|
||||
CMDRES0(CMD_SHOW_NORMAL, w)
|
||||
}
|
||||
|
||||
window_state_t rkt_webview_window_state(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktWindowState(w);
|
||||
auto f = [w]() {
|
||||
CMDRES0(CMD_WINDOW_STATE, w)
|
||||
};
|
||||
int r = f();
|
||||
return static_cast<window_state_t>(r);
|
||||
}
|
||||
|
||||
result_t rkt_webview_set_title(rktwebview_t wv, const char *title)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktWindowSetTitle(wv, title);
|
||||
CMDRES(CMD_SET_TITLE, wv, "title", title)
|
||||
}
|
||||
|
||||
result_t rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktChooseDir(w, title, base_dir);
|
||||
CMDRES2(CMD_CHOOSE_DIR, w, "title", title, "base_dir", base_dir)
|
||||
}
|
||||
|
||||
result_t rkt_webview_file_open(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktFileOpen(w, title, base_dir, permitted_exts);
|
||||
CMDRES3(CMD_FILE_OPEN, w, "title", title, "base_dir", base_dir, "permitted_exts", permitted_exts)
|
||||
}
|
||||
|
||||
result_t rkt_webview_file_save(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktFileSave(w, title, base_dir, permitted_exts);
|
||||
CMDRES3(CMD_FILE_SAVE, w, "title", title, "base_dir", base_dir, "permitted_exts", permitted_exts)
|
||||
}
|
||||
|
||||
void rkt_webview_set_ou_token(rktwebview_t wv, const char *token)
|
||||
{
|
||||
rkt_webview_init();
|
||||
handler->rktSetOUToken(wv, token);
|
||||
|
||||
JSON j;
|
||||
j["wv"] = wv;
|
||||
j["token"] = std::string(token);
|
||||
|
||||
handler->command_queue->enqueue(CMD_SET_OU_TOKEN, j.dump());
|
||||
}
|
||||
|
||||
void rkt_webview_free_data(rkt_data_t *d)
|
||||
{
|
||||
if (d == nullptr) { return; }
|
||||
|
||||
if (d->kind == version) {
|
||||
free(d);
|
||||
} else if (d->kind == event) {
|
||||
@@ -256,14 +412,37 @@ rkt_data_t *rkt_webview_version()
|
||||
d->data.version.api_major = RKT_WEBVIEW_API_MAJOR;
|
||||
d->data.version.api_minor = RKT_WEBVIEW_API_MINOR;
|
||||
d->data.version.api_patch = RKT_WEBVIEW_API_PATCH;
|
||||
d->data.version.qt_major = QT_VERSION_MAJOR;
|
||||
d->data.version.qt_minor = QT_VERSION_MINOR;
|
||||
d->data.version.qt_patch = QT_VERSION_PATCH;
|
||||
return d;
|
||||
}
|
||||
|
||||
result_t rkt_webview_message_box(rktwebview_t w, const char *title, const char *message, const char *submessage, rkt_messagetype_t type)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktMessageBox(w, title, message, submessage, type);
|
||||
CMDRES4(CMD_MSG_BOX, w, "title", title, "message", message, "submessage", submessage, "type", static_cast<int>(type))
|
||||
}
|
||||
|
||||
int rkt_webview_events_waiting()
|
||||
{
|
||||
return handler->event_queue->depth();
|
||||
}
|
||||
|
||||
rkt_data_t *rkt_webview_get_event()
|
||||
{
|
||||
//fprintf(stderr, "rkt_webview_get_event\n");
|
||||
int wv;
|
||||
std::string data;
|
||||
if (handler->event_queue->dequeue(wv, data, false)) {
|
||||
//fprintf(stderr, "got event %d %s\n", wv, data.c_str());
|
||||
rkt_data_t *d = reinterpret_cast<rkt_data_t *>(malloc(sizeof(rkt_data_t)));
|
||||
d->kind = rkt_data_kind_t::event;
|
||||
|
||||
size_t ds = data.size();
|
||||
d->data.event.event = reinterpret_cast<char *>(malloc(ds + 1));
|
||||
memcpy(d->data.event.event, data.c_str(), ds);
|
||||
d->data.event.event[ds] = '\0';
|
||||
d->data.event.wv = wv;
|
||||
fprintf(stderr, "event: %d - '%s'\n", d->data.event.wv, d->data.event.event);
|
||||
return d;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user