diff --git a/racket-webview-ffi.rkt b/racket-webview-ffi.rkt
index a67e7c3..988292d 100644
--- a/racket-webview-ffi.rkt
+++ b/racket-webview-ffi.rkt
@@ -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))
diff --git a/racket-webview-qt.rkt b/racket-webview-qt.rkt
new file mode 100644
index 0000000..b9fb336
--- /dev/null
+++ b/racket-webview-qt.rkt
@@ -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)
+
\ No newline at end of file
diff --git a/racket-webview.rkt b/racket-webview.rkt
index e1d1582..f58157e 100644
--- a/racket-webview.rkt
+++ b/racket-webview.rkt
@@ -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
diff --git a/rktwebview/.gitignore b/rktwebview/.gitignore
new file mode 100644
index 0000000..8a9d35c
--- /dev/null
+++ b/rktwebview/.gitignore
@@ -0,0 +1 @@
+*.user
diff --git a/rktwebview/CMakeLists.txt b/rktwebview/CMakeLists.txt
index eb5b5c7..a4dfdc7 100644
--- a/rktwebview/CMakeLists.txt
+++ b/rktwebview/CMakeLists.txt
@@ -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()
+
diff --git a/rktwebview/json.h b/rktwebview/json.h
index 87f1b57..7f54c39 100644
--- a/rktwebview/json.h
+++ b/rktwebview/json.h
@@ -15,6 +15,10 @@
std::string json_escape( const std::string &str );
+#ifdef Bool
+#undef Bool
+#endif
+
class JSON
{
union BackingData {
diff --git a/rktwebview/main.cpp b/rktwebview/main.cpp
index 7c6ba58..eb0a3b6 100644
--- a/rktwebview/main.cpp
+++ b/rktwebview/main.cpp
@@ -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, "
He daar!He daar!
");
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;
}
diff --git a/rktwebview/rktwebview.cpp b/rktwebview/rktwebview.cpp
index 6e127fe..b50d288 100644
--- a/rktwebview/rktwebview.cpp
+++ b/rktwebview/rktwebview.cpp
@@ -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
}
diff --git a/rktwebview/rktwebview.h b/rktwebview/rktwebview.h
index 939cefc..762fd0e 100644
--- a/rktwebview/rktwebview.h
+++ b/rktwebview/rktwebview.h
@@ -13,9 +13,13 @@ typedef DWORD thread_id_t;
#define USE_WIN_THREADS
#endif
-#ifdef _linux
-#define USE_PTHREADS
+#ifdef __linux
#include
+#include
+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 {
diff --git a/rktwebview_qt/.gitignore b/rktwebview_qt/.gitignore
new file mode 100644
index 0000000..4a0b530
--- /dev/null
+++ b/rktwebview_qt/.gitignore
@@ -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
+
diff --git a/rktwebview_qt/CMakeLists.txt b/rktwebview_qt/CMakeLists.txt
new file mode 100644
index 0000000..8b5d597
--- /dev/null
+++ b/rktwebview_qt/CMakeLists.txt
@@ -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)
diff --git a/rktwebview_qt/main.cpp b/rktwebview_qt/main.cpp
new file mode 100644
index 0000000..e7840a6
--- /dev/null
+++ b/rktwebview_qt/main.cpp
@@ -0,0 +1,37 @@
+#include "rktwebview.h"
+
+#include
+
+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);
+
+}
diff --git a/rktwebview_qt/rktwebview.cpp b/rktwebview_qt/rktwebview.cpp
new file mode 100644
index 0000000..c1380ec
--- /dev/null
+++ b/rktwebview_qt/rktwebview.cpp
@@ -0,0 +1,157 @@
+#include "rktwebview_internal.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "rktwebview_qt.h"
+#include "webviewapp.h"
+
+uint64_t current_ms() {
+ using namespace std::chrono;
+ return duration_cast(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(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();
+ }
+}
diff --git a/rktwebview_qt/rktwebview.h b/rktwebview_qt/rktwebview.h
new file mode 100644
index 0000000..61e22ec
--- /dev/null
+++ b/rktwebview_qt/rktwebview.h
@@ -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
diff --git a/rktwebview_qt/rktwebview_internal.h b/rktwebview_qt/rktwebview_internal.h
new file mode 100644
index 0000000..43aee0e
--- /dev/null
+++ b/rktwebview_qt/rktwebview_internal.h
@@ -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
diff --git a/rktwebview_qt/rktwebview_qt.cpp b/rktwebview_qt/rktwebview_qt.cpp
new file mode 100644
index 0000000..62b02f3
--- /dev/null
+++ b/rktwebview_qt/rktwebview_qt.cpp
@@ -0,0 +1,196 @@
+#include "rktwebview_qt.h"
+#include "webviewqt.h"
+#include "rktwebview.h"
+#include "webviewwindow.h"
+#include
+#include
+#include
+
+#define COMMAND_QUIT 1
+#define COMMAND_CLOSE 2
+#define COMMAND_CREATE 3
+#define COMMAND_SET_URL 4
+
+class Command
+{
+public:
+ int cmd;
+ QVector 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 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("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;
+}
diff --git a/rktwebview_qt/rktwebview_qt.h b/rktwebview_qt/rktwebview_qt.h
new file mode 100644
index 0000000..fd92878
--- /dev/null
+++ b/rktwebview_qt/rktwebview_qt.h
@@ -0,0 +1,68 @@
+#ifndef RKTWEBVIEW_QT_H
+#define RKTWEBVIEW_QT_H
+
+#include "rktwebview_qt_global.h"
+#include "rktwebview_internal.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+class WebViewQt;
+class WebviewWindow;
+class Command;
+
+class RKTWEBVIEW_QT_EXPORT Rktwebview_qt : public QObject
+{
+ Q_OBJECT
+private:
+ QApplication *_app;
+ rktwebview_t _current_handle;
+ QHash _views;
+
+ QQueue _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
diff --git a/rktwebview_qt/rktwebview_qt_global.h b/rktwebview_qt/rktwebview_qt_global.h
new file mode 100644
index 0000000..98ed696
--- /dev/null
+++ b/rktwebview_qt/rktwebview_qt_global.h
@@ -0,0 +1,12 @@
+#ifndef RKTWEBVIEW_QT_GLOBAL_H
+#define RKTWEBVIEW_QT_GLOBAL_H
+
+#include
+
+#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
diff --git a/rktwebview_qt/webviewapp.cpp b/rktwebview_qt/webviewapp.cpp
new file mode 100644
index 0000000..357bc2f
--- /dev/null
+++ b/rktwebview_qt/webviewapp.cpp
@@ -0,0 +1,8 @@
+#include "webviewapp.h"
+
+
+WebViewApp::WebViewApp(int &argc, char **argv) :
+ QApplication(argc, argv)
+{
+
+}
diff --git a/rktwebview_qt/webviewapp.h b/rktwebview_qt/webviewapp.h
new file mode 100644
index 0000000..a450b65
--- /dev/null
+++ b/rktwebview_qt/webviewapp.h
@@ -0,0 +1,13 @@
+#ifndef WEBVIEWAPP_H
+#define WEBVIEWAPP_H
+
+#include
+
+class WebViewApp : public QApplication
+{
+ Q_OBJECT
+public:
+ WebViewApp(int &argc, char **argv);
+};
+
+#endif // WEBVIEWAPP_H
diff --git a/rktwebview_qt/webviewqt.cpp b/rktwebview_qt/webviewqt.cpp
new file mode 100644
index 0000000..d7a0a89
--- /dev/null
+++ b/rktwebview_qt/webviewqt.cpp
@@ -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)
+{
+
+}
+
+
diff --git a/rktwebview_qt/webviewqt.h b/rktwebview_qt/webviewqt.h
new file mode 100644
index 0000000..8e65c3f
--- /dev/null
+++ b/rktwebview_qt/webviewqt.h
@@ -0,0 +1,22 @@
+#ifndef WEBVIEWQT_H
+#define WEBVIEWQT_H
+
+#include
+
+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
diff --git a/rktwebview_qt/webviewwindow.cpp b/rktwebview_qt/webviewwindow.cpp
new file mode 100644
index 0000000..d97e9a7
--- /dev/null
+++ b/rktwebview_qt/webviewwindow.cpp
@@ -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;
+}
diff --git a/rktwebview_qt/webviewwindow.h b/rktwebview_qt/webviewwindow.h
new file mode 100644
index 0000000..c54797f
--- /dev/null
+++ b/rktwebview_qt/webviewwindow.h
@@ -0,0 +1,30 @@
+#ifndef WEBVIEWWINDOW_H
+#define WEBVIEWWINDOW_H
+
+#include
+
+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