This commit is contained in:
2026-03-02 23:10:29 +01:00
parent 07004097e9
commit 25ca1ec4a4
24 changed files with 1054 additions and 31 deletions

View File

@@ -18,7 +18,7 @@
rkt_webview_set_html
rkt_webview_valid
rkt_webview_run_js
rkt_webview_call_js
;rkt_webview_call_js
rkt_webview_pending_events
rkt_webview_get_event
rkt_webview_set_event_callback!
@@ -39,9 +39,11 @@
(define libname (let ((os (system-type 'os*)))
(cond ((eq? os 'windows) (format "rktwebview.dll"))
((eq? os 'linux) (format "librktwebview.so"))
(else (error (format "OS ~a not supported" os)))))
)
(set! libname "../rtkwebview/build/Release/rktwebview.dll")
;(set! libname "../rktwebview/build/Release/rktwebview.dll")
(set! libname "../rktwebview/build/Release/librktwebview.so")
(define webview-lib-file (build-path lib-dir libname))
(define webview-lib (ffi-lib webview-lib-file))

76
racket-webview-qt.rkt Normal file
View File

@@ -0,0 +1,76 @@
#lang racket/base
(require ffi/unsafe
ffi/unsafe/define
ffi/unsafe/atomic
ffi/unsafe/os-thread
racket/async-channel
racket/runtime-path
racket/port
data/queue
json
racket/string
racket/path
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; FFI Library
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define lib-type 'release)
(define-runtime-path lib-dir "lib")
(define libname (let ((os (system-type 'os*)))
(cond ((eq? os 'windows) (format "rktwebview.dll"))
((eq? os 'linux) (format "librktwebview.so"))
(else (error (format "OS ~a not supported" os)))))
)
;(set! libname "../rktwebview/build/Release/rktwebview.dll")
;(set! libname "../rktwebview/build/Release/librktwebview.so")
(set! libname "../rktwebview_qt/rktwebview_qt/build/Desktop-Release/librktwebview_qt.so")
(define webview-lib-file (build-path lib-dir libname))
(define webview-lib (ffi-lib webview-lib-file))
(define-ffi-definer define-rktwebview webview-lib)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Types
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;RKTWEBVIEW_QT_EXPORT void rkt_webview_init(int &argc, char **argv);
(define-rktwebview rkt_webview_init
(_fun -> _void))
;RKTWEBVIEW_QT_EXPORT void rkt_webview_process_events(int for_ms);
(define-rktwebview rkt_webview_process_events
(_fun _int -> _void))
;RKTWEBVIEW_QT_EXPORT int rkt_webview_create(int parent);
(define-rktwebview rkt_webview_create
(_fun _int -> _int))
;RKTWEBVIEW_QT_EXPORT void rkt_webview_close(int wv);
(define-rktwebview rkt_webview_close
(_fun _int -> _void))
;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_url(int wv, const char *url);
(define-rktwebview rkt_webview_set_url
(_fun _int _string/utf-8 -> _int))
;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_html(int wv, const char *html);
(define process-events #t)
(define (start-event-processing)
(thread (λ ()
(letrec ((f (λ ()
(rkt_webview_process_events 1)
(sleep 0.001)
(if process-events
(f)
'done))))
(f)))))
(rkt_webview_init)
(start-event-processing)

View File

@@ -164,9 +164,9 @@
(define (webview-run-js wv js)
(rkt_webview_run_js (wv-handle wv) js))
(define (webview-call-js wv js)
(let ((result (rkt_webview_call_js (wv-handle wv) js)))
result))
;(define (webview-call-js wv js)
; (let ((result (rkt_webview_call_js (wv-handle wv) js)))
; result))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; testing

1
rktwebview/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.user

View File

@@ -4,10 +4,88 @@ project(rktwebview LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(GIT_EXECUTABLE git)
set(CMAKE_VERBOSE_MAKEFILE ON)
include_directories(../webview/core/include)
include_directories(../webview/build/Release/_deps/microsoft_web_webview2-src/build/native/include)
link_directories(../webview/build/Release/core)
set(WEBVIEW_BUILD_STATIC_LIBRARY ON)
set(WEBVIEW_WEBKITGTK_API "6.0")
#set(WEBVIEW_WEBKITGTK_PREFERRED_API_LIST webkitgtk-6.0)
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE "Release")
endif()
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(LIBKIND "d")
else()
set(LIBKIND "r")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(LIBEXT lib)
set(LIBPRE )
else()
set(LIBEXT a)
set(LIBPRE lib)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# using Clang
add_compile_options(-fPIC)
set(CFLAGS_ENV "CFLAGS=-fPIC")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC
add_compile_options(-fPIC)
set(CFLAGS_ENV "CFLAGS=-fPIC")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
# using Intel C++
set(CFLAGS_ENV "")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# using Visual Studio C++
set(CFLAGS_ENV "")
endif()
if(NOT(EXISTS ./deps))
file(MAKE_DIRECTORY ./deps)
endif()
function(git_dep dir dep)
if(EXISTS ${rktwebview_SOURCE_DIR}/deps/${dir})
execute_process(
COMMAND ${GIT_EXECUTABLE} pull
COMMAND_ECHO STDOUT
WORKING_DIRECTORY ${rktwebview_SOURCE_DIR}/deps/${dir}
)
else()
message("Executing git clone...")
execute_process(
COMMAND ${GIT_EXECUTABLE} clone ${dep} ${rktwebview_SOURCE_DIR}/deps/${dir}
COMMAND_ECHO STDOUT
)
endif()
endfunction()
git_dep(webview https://github.com/webview/webview.git)
add_subdirectory(deps/webview)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED gtk+-3.0)
include_directories(${GTK_INCLUDE_DIRS})
message("${GTK_INCLUDE_DIRS}")
link_directories(${GTK_LIBRARY_DIRS})
pkg_check_modules(GTKWEBVIEW REQUIRED webkit2gtk-4.1)
include_directories(${GTKWEBVIEW_INCLUDE_DIRS})
message("${GTKWEBVIEW_INCLUDE_DIRS}")
link_directories(${GTKWEBVIEW_LIBRARY_DIRS})
endif()
include_directories(deps/webview/core/include)
include_directories(deps/webview/build/Release/_deps/microsoft_web_webview2-src/build/native/include)
link_directories(build/Release/deps/webview/core)
link_directories(build/Release)
add_library(rktwebview SHARED
@@ -15,18 +93,31 @@ add_library(rktwebview SHARED
rktwebview.cpp
rktwebview.h
json.h
json.cpp
main.cpp
)
add_executable(rktwebview_test
main.cpp
rktwebview_global.h
rktwebview.cpp
rktwebview.h
json.h
json.cpp
)
#add_dependencies(rktwebview webview)
target_link_libraries(rktwebview webview_static)
target_link_libraries(rktwebview_test rktwebview)
target_link_libraries(rktwebview webview_core_static)
#target_link_libraries(rktwebview_test rktwebview)
target_link_libraries(rktwebview_test webview_core_static)
target_compile_definitions(rktwebview PRIVATE RKTWEBVIEW_LIBRARY)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(rktwebview ${GTK_LIBRARIES} ${GTKWEBVIEW_LIBRARIES})
target_link_libraries(rktwebview_test ${GTK_LIBRARIES} ${GTKWEBVIEW_LIBRARIES})
endif()

View File

@@ -15,6 +15,10 @@
std::string json_escape( const std::string &str );
#ifdef Bool
#undef Bool
#endif
class JSON
{
union BackingData {

View File

@@ -5,12 +5,19 @@ int main()
{
rkt_webview_t *wv = rkt_create_webview();
result_t r = rkt_webview_navigate(wv, "https://wikipedia.org");
rkt_webview_t *wv1 = nullptr;
//result_t r = rkt_set_html(wv, "<html><head><title>He daar!</title></head><body><h1>He daar!</h1></body>");
printf("Navigate: result = %d\n", r);
int i = 0;
while(rkt_webview_valid(wv)) {
printf("Waiting...\n");
printf("Waiting...%d\n", i);
#ifdef USE_WIN_THREADS
Sleep(1000);
#endif
#ifdef USE_PTHREADS
usleep(1000 * 1000);
#endif
i += 1;
if (i > 5) {
item_t item = rkt_webview_call_js(wv, "{ window.location = 'https://dijkewijk.nl'; return 42; }");
@@ -20,6 +27,11 @@ int main()
printf("%d, %s\n", item1.context, item1.data);
rkt_webview_destroy_item(item1);
}
if (i == 16) {
wv1 = rkt_create_webview();
result_t r = rkt_webview_navigate(wv, "https://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html");
}
}
return 0;
}

View File

@@ -24,7 +24,7 @@ static result_t do_dispatch(rkt_webview_t *, item_t item);
static DWORD webviewThread(LPVOID args)
#endif
#ifdef USE_PTHREADS
static int webviewThread(void *args)
static void *webviewThread(void *args)
#endif
{
rkt_webview_t *wv = (rkt_webview_t *) args;
@@ -41,14 +41,19 @@ static int webviewThread(void *args)
wv->webview_handle = NULL;
wv->handle_destroyed = true;
mutex_unlock(wv);
#ifdef USE_WIN_THREADS
return 0;
#endif
#ifdef USE_PTHREADS
return NULL;
#endif
}
#ifdef USE_WIN_THREADS
static DWORD queueGuardThread(LPVOID args)
#endif
#ifdef USE_PTHREADS
static int queueGuardThread(void *args)
static void *queueGuardThread(void *args)
#endif
{
rkt_webview_t *wv = (rkt_webview_t *) args;
@@ -73,7 +78,12 @@ static DWORD queueGuardThread(LPVOID args)
thread_sleep_ms(wv, 10);
}
#ifdef USE_WIN_THREADS
return 0;
#endif
#ifdef USE_PTHREADS
return NULL;
#endif
}
@@ -82,9 +92,12 @@ RKTWEBVIEW_EXPORT rkt_webview_t *rkt_create_webview()
rkt_webview_t *wv = (rkt_webview_t *) malloc(sizeof(rkt_webview_t));
if (wv == NULL) { return NULL; }
#ifdef _WIN32
#ifdef USE_WIN_THREADS
wv->mutex = CreateMutex(NULL, FALSE, NULL);
#endif
#ifdef USE_PTHREADS
wv->mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
wv->handle_set = false;
wv->handle_destroyed = false;
queue_init(&wv->to_webview);
@@ -112,7 +125,9 @@ RKTWEBVIEW_EXPORT rkt_webview_t *rkt_create_webview()
&wv->queue_guard_thread_id
);
#endif
#ifdef USE_PTHREAD
#ifdef USE_PTHREADS
wv->webview_thread_id = pthread_create(&wv->webview_thread, NULL, webviewThread, wv);
wv->queue_guard_thread_id = pthread_create(&wv->queue_guard_thread, NULL, queueGuardThread, wv);
#endif
bool go_on = true;
while(go_on) {
@@ -123,6 +138,7 @@ RKTWEBVIEW_EXPORT rkt_webview_t *rkt_create_webview()
thread_sleep_ms(wv, 10);
}
}
printf("handle_set = %d\n", wv->handle_set);
return wv;
}
@@ -152,6 +168,7 @@ RKTWEBVIEW_EXPORT item_t rkt_webview_call_js(rkt_webview_t *wv, const char *js)
mutex_unlock(wv);
char buf[30];
sprintf(buf, "%d", call_nr);
std::string _js = std::string("{ let f = function() { ") + js + " };" +
" let call_nr = " + buf + ";" +
" try { let r = { result: f() };" +
@@ -159,7 +176,7 @@ RKTWEBVIEW_EXPORT item_t rkt_webview_call_js(rkt_webview_t *wv, const char *js)
" } catch(e) {" +
" rkt_webview_call_js_result(call_nr, false, e.message); " +
" }" +
"}"; "";
"}";
item_t item = { CONTEXT_CALL_JS, strdup(_js.c_str()) };
@@ -232,7 +249,9 @@ RKTWEBVIEW_EXPORT result_t rkt_destroy_webview(rkt_webview_t *wv)
CloseHandle(wv->queue_guard_thread);
CloseHandle(wv->mutex);
#endif
#ifdef USE_PTHREAD
#ifdef USE_PTHREADS
pthread_join(wv->webview_thread, NULL);
pthread_join(wv->queue_guard_thread, NULL);
#endif
delete wv->js_evaluated;
free(wv);
@@ -405,11 +424,24 @@ result_t do_dispatch(rkt_webview_t *wv, item_t item)
}
return r;
} else {
lr = reason_set_html_failed;
switch(e) {
case WEBVIEW_ERROR_MISSING_DEPENDENCY: lr = reason_webview_missing_dependency;
break;
case WEBVIEW_ERROR_CANCELED: lr = reason_webview_canceled;
break;
case WEBVIEW_ERROR_INVALID_STATE: lr = reason_webview_invalid_state;
break;
case WEBVIEW_ERROR_INVALID_ARGUMENT: lr = reason_webview_invalid_argument;
break;
case WEBVIEW_ERROR_UNSPECIFIED: lr = reason_webview_unspecified;
break;
default:
lr = reason_webview_dispatch_failed;
}
r = error;
}
printf("error = %d, reason = %d", r, lr);
printf("error = %d, reason = %d\n", r, lr);
return r;
}
@@ -490,7 +522,8 @@ void mutex_lock(rkt_webview_t *wv)
#ifdef USE_WIN_THREADS
WaitForSingleObject(wv->mutex, INFINITE);
#endif
#ifdef USE_PTHREAD
#ifdef USE_PTHREADS
pthread_mutex_lock(&wv->mutex);
#endif
}
@@ -500,7 +533,8 @@ void mutex_unlock(rkt_webview_t *wv)
#ifdef USE_WIN_THREADS
ReleaseMutex(wv->mutex);
#endif
#ifdef USE_PTHREAD
#ifdef USE_PTHREADS
pthread_mutex_unlock(&wv->mutex);
#endif
}
@@ -509,6 +543,7 @@ static void thread_sleep_ms(rkt_webview_t *wv, int ms)
#ifdef USE_WIN_THREADS
Sleep(ms);
#endif
#ifdef USE_PTHREAD
#ifdef USE_PTHREADS
usleep(ms * 1000);
#endif
}

View File

@@ -13,9 +13,13 @@ typedef DWORD thread_id_t;
#define USE_WIN_THREADS
#endif
#ifdef _linux
#define USE_PTHREADS
#ifdef __linux
#include <pthread.h>
#include <unistd.h>
typedef pthread_t thread_t;
typedef pthread_mutex_t mutex_t;
typedef int thread_id_t;
#define USE_PTHREADS
#endif
#define CONTEXT_INVALID 0
@@ -38,11 +42,17 @@ typedef enum {
typedef enum {
reason_no_result_yet = -1,
reason_oke = 0,
reason_set_html_failed,
reason_set_navigate_failed,
reason_eval_js_failed,
reason_no_devtools_on_platform,
reason_no_delegate_for_context
reason_set_html_failed = 1,
reason_set_navigate_failed = 2,
reason_eval_js_failed = 3,
reason_no_devtools_on_platform = 4,
reason_no_delegate_for_context = 5,
reason_webview_missing_dependency = 6,
reason_webview_canceled = 7,
reason_webview_invalid_state = 8,
reason_webview_invalid_argument = 9,
reason_webview_unspecified = 10,
reason_webview_dispatch_failed = 11
} reason_t;
typedef struct {

74
rktwebview_qt/.gitignore vendored Normal file
View File

@@ -0,0 +1,74 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
CMakeLists.txt.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe

View File

@@ -0,0 +1,47 @@
cmake_minimum_required(VERSION 3.14)
project(rktwebview_qt LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets WebEngineWidgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets WebEngineWidgets)
add_library(rktwebview_qt SHARED
rktwebview_qt_global.h
rktwebview_qt.cpp
rktwebview_qt.h
rktwebview.h
rktwebview.cpp
webviewqt.h webviewqt.cpp
rktwebview_internal.h
webviewwindow.h webviewwindow.cpp
webviewapp.h webviewapp.cpp
)
target_link_libraries(rktwebview_qt PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
target_link_libraries(rktwebview_qt PRIVATE Qt${QT_VERSION_MAJOR}::WebEngineWidgets)
target_compile_definitions(rktwebview_qt PRIVATE RKTWEBVIEW_QT_LIBRARY)
add_executable(rktwebview_qt_test
main.cpp
rktwebview_qt_global.h
rktwebview_qt.cpp
rktwebview_qt.h
rktwebview.h
rktwebview.cpp
webviewqt.h webviewqt.cpp
webviewwindow.h webviewwindow.cpp
rktwebview_internal.h
webviewapp.h webviewapp.cpp
)
target_compile_definitions(rktwebview_qt_test PRIVATE RKTWEBVIEW_QT_LIBRARY)
target_link_libraries(rktwebview_qt_test PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
target_link_libraries(rktwebview_qt_test PRIVATE Qt${QT_VERSION_MAJOR}::WebEngineWidgets)

37
rktwebview_qt/main.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include "rktwebview.h"
#include <QThread>
static int _argc;
static char **_argv;
int main(int argc, char *argv[])
{
int wv1;
int wv2;
_argc = argc;
_argv = argv;
rkt_webview_init();
wv1 = rkt_webview_create(0);
rkt_webview_set_url(wv1, "https://wikipedia.org");
int i = 0;
while(i < 20) {
printf("Waiting...%d\n", i);
rkt_webview_process_events(1000);
if (i == 10) {
wv2 = rkt_webview_create(0);
}
if (i == 15) {
rkt_webview_close(wv1);
}
i += 1;
}
rkt_webview_close(wv2);
}

View File

@@ -0,0 +1,157 @@
#include "rktwebview_internal.h"
#include <malloc.h>
#include <string.h>
#include <chrono>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include "rktwebview_qt.h"
#include "webviewapp.h"
uint64_t current_ms() {
using namespace std::chrono;
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
}
/////////////////////////////////////////////////////////////////////
// Main C Interface
/////////////////////////////////////////////////////////////////////
static int pipefd[2];
static bool started = false;
static pid_t webview_process;
static bool cannot_fork_or_pipe = false;
Rktwebview_qt *handler = nullptr;
void rkt_webview_init()
{
/*
if (!started) {
if (pipe(pipefd) != -1) {
webview_process = fork();
if (webview_process < 0)
cannot_fork_or_pipe = true;
} else if (webview_process == 0) {
WebViewApp app;
started = true;
} else {
cannot_fork_or_pipe = true;
}
}
*/
if (handler == nullptr) {
handler = new Rktwebview_qt(&handler);
}
}
int rkt_webview_create(int parent)
{
//rkt_webview_init();
return handler->rktWebViewCreate(parent);
}
void rkt_webview_close(int wv)
{
handler->rktWebViewClose(wv);
}
result_t rkt_webview_set_url(int wv, const char *url)
{
result_t r = handler->rktSetUrl(wv, url);
return r;
}
/////////////////////////////////////////////////////////////////////
// Supporting functions
/////////////////////////////////////////////////////////////////////
void queue_init(queue_t **q)
{
*q = static_cast<queue_t *>(malloc(sizeof(queue_t)));
queue_t *Q = *q;
Q->length = 0;
Q->first = nullptr;
Q->last = nullptr;
}
void enqueue(queue_t *q, item_t item)
{
queue_item_t *itm = (queue_item_t *) malloc(sizeof(queue_item_t));
itm->item.context = item.context;
itm->item.data = strdup(item.data);
if (q->first == nullptr) {
q->first = itm;
q->last = itm;
itm->prev = nullptr;
itm->next = nullptr;
q->length = 1;
} else {
itm->prev = q->last;
itm->next = nullptr;
q->last->next = itm;
q->last = itm;
q->length += 1;
}
}
bool dequeue(queue_t *q, item_t *item)
{
if (q->length == 0) {
item->context = CONTEXT_INVALID;
item->data = nullptr;
return false;
} else {
queue_item_t *itm = q->first;
q->first = q->first->next;
q->length -= 1;
if (q->length == 0) {
q->first = nullptr;
q->last = nullptr;
}
item->context = itm->item.context;
item->data = itm->item.data;
free(itm);
return true;
}
}
int queue_length(queue_t *q)
{
return q->length;
}
void queue_destroy(queue_t *q)
{
item_t i;
while(dequeue(q, &i)) {
free(i.data);
}
free(q);
}
void free_item(item_t item)
{
free(item.data);
}
void rkt_webview_process_events(int for_ms)
{
//rkt_webview_init();
int64_t start_ms = current_ms();
int64_t end_ms = start_ms + for_ms;
while (current_ms() < end_ms) {
usleep(500); // sleep 0.5 ms
handler->doEvents();
}
}

View File

@@ -0,0 +1,57 @@
#ifndef RKTWEBVIEW_H
#define RKTWEBVIEW_H
#include "rktwebview_qt_global.h"
#define CONTEXT_QUIT -2
#define CONTEXT_NIL -1
#define CONTEXT_INVALID 0
#define CONTEXT_BOUND_EVENT 1
#define CONTEXT_WINDOW_RESIZE 2
#define CONTEXT_WINDOW_MOVE 3
#define CONTEXT_WINDOW_CAN_CLOSE 4
#define CONTEXT_WINDOW_CLOSED 5
#define CONTEXT_SET_HTML 6
#define CONTEXT_NAVIGATE 7
#define CONTEXT_EVAL_JS 8
#define CONTEXT_OPEN_DEVTOOLS 9
#define CONTEXT_CALL_JS 10
#define CONTEXT_CMD_CLOSE 11
#define CONTEXT_CMD_CREATE_VIEW 12
extern "C" {
typedef int rktwebview_t;
typedef struct {
rktwebview_t wv;
int context;
char *data;
} item_t;
typedef enum {
no_result_yet = -1,
oke = 0,
set_html_failed = 1,
set_navigate_failed = 2,
eval_js_failed = 3,
no_devtools_on_platform = 4,
no_delegate_for_context = 5,
webview_missing_dependency = 6,
webview_canceled = 7,
webview_invalid_state = 8,
webview_invalid_argument = 9,
webview_unspecified = 10,
webview_dispatch_failed = 11
} result_t;
RKTWEBVIEW_QT_EXPORT void rkt_webview_init();
RKTWEBVIEW_QT_EXPORT void rkt_webview_process_events(int for_ms);
RKTWEBVIEW_QT_EXPORT int rkt_webview_create(int parent);
RKTWEBVIEW_QT_EXPORT void rkt_webview_close(int wv);
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_url(int wv, const char *url);
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_html(int wv, const char *html);
}
#endif // RKTWEBVIEW_H

View File

@@ -0,0 +1,25 @@
#ifndef RKTWEBVIEW_INTERNAL_H
#define RKTWEBVIEW_INTERNAL_H
#include "rktwebview.h"
typedef struct _item {
item_t item;
struct _item *next;
struct _item *prev;
} queue_item_t;
typedef struct {
queue_item_t *first;
queue_item_t *last;
int length;
} queue_t;
void queue_init(queue_t **q);
void enqueue(queue_t *q, item_t item);
bool dequeue(queue_t *q, item_t *item);
int queue_length(queue_t *q);
void queue_destroy(queue_t *q);
void free_item(item_t i);
#endif // RKTWEBVIEW_INTERNAL_H

View File

@@ -0,0 +1,196 @@
#include "rktwebview_qt.h"
#include "webviewqt.h"
#include "rktwebview.h"
#include "webviewwindow.h"
#include <QApplication>
#include <QTimer>
#include <QSemaphore>
#define COMMAND_QUIT 1
#define COMMAND_CLOSE 2
#define COMMAND_CREATE 3
#define COMMAND_SET_URL 4
class Command
{
public:
int cmd;
QVector<QVariant> args;
QVariant result;
bool done;
public:
Command(int _cmd) {
cmd = _cmd;
done = false;
}
};
void Rktwebview_qt::processCommands()
{
printf("COmmand processing\n");
while(!_command_queue.empty()) {
Command *cmd = _command_queue.dequeue();
switch(cmd->cmd) {
case COMMAND_QUIT: {
_app->quit();
cmd->done = true;
}
break;
case COMMAND_CREATE: {
int parent = cmd->args[0].toInt();
QWidget *p;
if (_views.contains(parent)) {
p = _views[parent];
} else {
p = nullptr;
}
WebviewWindow *w = new WebviewWindow(p);
WebViewQt *view = new WebViewQt(nextHandle(), w);
w->addView(view, this);
int id = view->id();
_views[id] = w;
w->show();
cmd->result = id;
cmd->done = true;
}
break;
case COMMAND_CLOSE: {
int wv = cmd->args[0].toInt();
if (_views.contains(wv)) {
WebviewWindow *w= _views[wv];
_views.remove(wv);
w->close();
w->deleteLater();
cmd->result = true;
} else {
cmd->result = false;
}
cmd->done = true;
}
break;
case COMMAND_SET_URL: {
int wv = cmd->args[0].toInt();
QString url = cmd->args[1].toString();
if (_views.contains(wv)) {
WebviewWindow *w = _views[wv];
WebViewQt *v = w->view();
QUrl u(url);
v->setUrl(u);
cmd->result = true;
} else {
cmd->result = false;
}
cmd->done = true;
}
break;
default: {
cmd->result = false;
cmd->done = true;
}
break;
}
}
}
void Rktwebview_qt::interruptEventLoop()
{
printf("Exeting application event loop\n");
//_app->quit();
}
void Rktwebview_qt::removeView(int id)
{
_views.remove(id);
}
int Rktwebview_qt::nextHandle()
{
int h = ++_current_handle;
return h;
}
int Rktwebview_qt::rktWebViewCreate(int parent)
{
Command c(COMMAND_CREATE);
c.args.push_back(parent);
_command_queue.enqueue(&c);
while(!c.done) { doEvents(); }
int id = c.result.toInt();
return id;
}
void Rktwebview_qt::rktWebViewClose(int wv)
{
Command c(COMMAND_CLOSE);
c.args.push_back(wv);
_command_queue.enqueue(&c);
while(!c.done) { doEvents(); }
}
result_t Rktwebview_qt::rktSetUrl(rktwebview_t wv, const char *url)
{
Command c(COMMAND_SET_URL);
QString _url(url);
c.args.push_back(wv);
c.args.push_back(_url);
_command_queue.enqueue(&c);
while(!c.done) { doEvents(); }
bool r = c.result.toBool();
return r ? result_t::oke : result_t::set_navigate_failed;
}
void Rktwebview_qt::rktQuit()
{
QList<int> keys = _views.keys();
int i;
for(i = 0; i < keys.size(); i++) {
int view_handle = keys[i];
rktWebViewClose(view_handle);
}
Command c(COMMAND_QUIT);
_command_queue.enqueue(&c);
while(!c.done) { doEvents(); }
}
void Rktwebview_qt::doEvents()
{
//_quit_event_loop.start(2000);
//_app->exec();
//processCommands();
_app->processEvents();
}
Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) :
QObject()
{
_argc = 1;
_argv[0] = const_cast<char *>("Rktwebview_qt");
_current_handle = 0;
_handler = handler;
_app = new QApplication(_argc, _argv);
connect(&_process_commands, &QTimer::timeout, this, &Rktwebview_qt::processCommands);
connect(&_quit_event_loop, &QTimer::timeout, this, &Rktwebview_qt::interruptEventLoop);
_process_commands.start(1000);
*_handler = nullptr;
}

View File

@@ -0,0 +1,68 @@
#ifndef RKTWEBVIEW_QT_H
#define RKTWEBVIEW_QT_H
#include "rktwebview_qt_global.h"
#include "rktwebview_internal.h"
#include <QApplication>
#include <QWebEngineView>
#include <QMutex>
#include <QThread>
#include <QHash>
#include <QQueue>
#include <QTimer>
class WebViewQt;
class WebviewWindow;
class Command;
class RKTWEBVIEW_QT_EXPORT Rktwebview_qt : public QObject
{
Q_OBJECT
private:
QApplication *_app;
rktwebview_t _current_handle;
QHash<int, WebviewWindow *> _views;
QQueue<Command *> _command_queue;
QTimer _process_commands;
QTimer _quit_event_loop;
Rktwebview_qt **_handler;
int _argc;
char *_argv[1];
public slots:
void processCommands();
void interruptEventLoop();
public:
void removeView(int id);
public:
int nextHandle();
public:
int rktWebViewCreate(int parent = 0); // threadsafe
void rktWebViewClose(int wv);
void rktQuit();
void runJs(rktwebview_t wv, const char *js); // threadsafe
item_t callJs(rktwebview_t wv, const char *js); // threadsafe
void setHtml(rktwebview_t wv, const char *html); // threadsafe
void navigate(rktwebview_t wv, const char *url); // threadsafe
result_t rktSetUrl(rktwebview_t wv, const char *url);
public:
void doEvents();
public:
void runCommandThread();
public:
Rktwebview_qt(Rktwebview_qt **handler);
};
#endif // RKTWEBVIEW_QT_H

View File

@@ -0,0 +1,12 @@
#ifndef RKTWEBVIEW_QT_GLOBAL_H
#define RKTWEBVIEW_QT_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(RKTWEBVIEW_QT_LIBRARY)
#define RKTWEBVIEW_QT_EXPORT Q_DECL_EXPORT
#else
#define RKTWEBVIEW_QT_EXPORT Q_DECL_IMPORT
#endif
#endif // RKTWEBVIEW_QT_GLOBAL_H

View File

@@ -0,0 +1,8 @@
#include "webviewapp.h"
WebViewApp::WebViewApp(int &argc, char **argv) :
QApplication(argc, argv)
{
}

View File

@@ -0,0 +1,13 @@
#ifndef WEBVIEWAPP_H
#define WEBVIEWAPP_H
#include <QApplication>
class WebViewApp : public QApplication
{
Q_OBJECT
public:
WebViewApp(int &argc, char **argv);
};
#endif // WEBVIEWAPP_H

View File

@@ -0,0 +1,19 @@
#include "webviewqt.h"
WebViewQt::WebViewQt(int id, QWidget *parent)
: QWebEngineView(parent)
{
_id = id;
}
int WebViewQt::id() const
{
return _id;
}
void WebViewQt::runJs(const char *js)
{
}

22
rktwebview_qt/webviewqt.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef WEBVIEWQT_H
#define WEBVIEWQT_H
#include <QWebEngineView>
class WebViewQt : public QWebEngineView
{
private:
int _id;
public:
int id() const;
public:
void runJs(const char *js);
public:
WebViewQt(int id, QWidget *parent = nullptr);
};
#endif // WEBVIEWQT_H

View File

@@ -0,0 +1,27 @@
#include "webviewwindow.h"
#include "webviewqt.h"
#include "rktwebview_qt.h"
void WebviewWindow::closeEvent(QCloseEvent *evt)
{
_container->removeView(_view->id());
}
void WebviewWindow::addView(WebViewQt *v, Rktwebview_qt *c)
{
_container = c;
_view = v;
this->setCentralWidget(v);
}
WebViewQt *WebviewWindow::view()
{
return _view;
}
WebviewWindow::WebviewWindow(QWidget *parent)
: QMainWindow{parent}
{
_view = nullptr;
}

View File

@@ -0,0 +1,30 @@
#ifndef WEBVIEWWINDOW_H
#define WEBVIEWWINDOW_H
#include <QMainWindow>
class WebViewQt;
class Rktwebview_qt;
class WebviewWindow : public QMainWindow
{
Q_OBJECT
private:
Rktwebview_qt *_container;
WebViewQt *_view;
protected:
void closeEvent(QCloseEvent *evt);
public:
void addView(WebViewQt *v, Rktwebview_qt *c);
WebViewQt *view();
public:
explicit WebviewWindow(QWidget *parent = nullptr);
signals:
};
#endif // WEBVIEWWINDOW_H