diff --git a/js/boilerplate.js b/js/boilerplate.js index a8246dd..02cfe22 100644 --- a/js/boilerplate.js +++ b/js/boilerplate.js @@ -1,20 +1,11 @@ -window._web_wire_evt_queue = []; +if (window.rkt_event_queue === undefined) { window.rkt_event_queue = []; } -window._web_wire_queue_worker = function() { - if (typeof web_ui_wire_handle_event === 'function') { - while (window._web_wire_evt_queue.length > 0) { - let evt = window._web_wire_evt_queue.shift(); - web_ui_wire_handle_event(JSON.stringify(evt)); - } - } - window.setTimeout(window._web_wire_queue_worker, 5); +window.rkt_put_evt = function(evt) { + window.rkt_event_queue.push(evt); }; -window.setTimeout(window._web_wire_queue_worker, 15); -window._web_wire_put_evt = function(evt) { window._web_wire_evt_queue.push(evt); }; - -window._web_wire_event_info = function(e, id, evt) { +window.rkt_event_info = function(e, id, evt) { let obj = {}; if (e == 'input') { obj['data'] = evt.data; @@ -53,13 +44,7 @@ window._web_wire_event_info = function(e, id, evt) { return obj; }; -window._web_wire_get_evts = function() { - let v = _web_wire_evt_queue; - _web_wire_evt_queue = []; - return JSON.stringify(v); // This needs no extra type info, as it is internally used only -}; - -window._web_wire_bind_evt_ids = function(win_nr, selector, event_kind) { +window.rkt_bind_evt_ids = function(win_nr, selector, event_kind) { try { let nodelist = document.querySelectorAll(selector); if (nodelist === undefined || nodelist === null) { @@ -75,8 +60,8 @@ window._web_wire_bind_evt_ids = function(win_nr, selector, event_kind) { el.addEventListener(event_kind, function(e) { let obj = {evt: event_kind, id: el_id, selector: selector, window: win_nr, - js_evt: window._web_wire_event_info(event_kind, el_id, e) }; - window._web_wire_put_evt(obj); + js_evt: window.rkt_event_info(event_kind, el_id, e) }; + window.rkt_put_evt(obj); } ); let info = [ el_id, el_tag, el_type ]; @@ -89,35 +74,3 @@ window._web_wire_bind_evt_ids = function(win_nr, selector, event_kind) { } }; -window._web_wire_resize_timeout = false; -window.addEventListener('resize', function() { - clearTimeout(window._web_wire_resize_timeout); - let f = function() { - let obj = { selector: 'global', evt: 'window-resize', h: window.outerWidth, w: window.outerHeight }; - window._web_wire_put_evt(obj); - }; - window._web_wire_resize_timeout = setTimeout(f, 250); -}); - -window._web_wire_x = window.screenX; -window._web_wire_y = window.screenY; -window._web_wire_move_interval = setInterval(function() { - let x = window.screenX; - let y = window.screenY; - if (x != window._web_wire_x || y != window._web_wire_y) { - window._web_wire_x = x; - window._web_wire_y = y; - let obj = { selector: 'global', evt: 'window-move', x: x, y: y }; - window._web_wire_put_evt(obj); - } -}, 500); - -document.addEventListener('readystatechange', event => { - - // When window loaded ( external resources are loaded too- `css`,`src`, etc...) - if (event.target.readyState === "complete") { - let obj = { selector: 'global', evt: 'html-loaded' }; - window._web_wire_put_evt(obj); - } -}); - diff --git a/racket-webview-qt.rkt b/racket-webview-qt.rkt index 51d52bc..bb13019 100644 --- a/racket-webview-qt.rkt +++ b/racket-webview-qt.rkt @@ -13,6 +13,21 @@ racket/path ) +(provide rkt-wv + rkt-wv-win + + rkt-webview-create + rkt-webview-close + rkt-webview-set-url! + rkt-webview-set-html! + rkt-webview-run-js + rkt-webview-move + rkt-webview-resize + rkt-webview-exit + rkt-webview-valid? + rkt-webview-open-devtools + ) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; FFI Library ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -34,10 +49,19 @@ (define webview-lib (ffi-lib webview-lib-file)) (define-ffi-definer define-rktwebview webview-lib) +(define callback-box (box '())) +(define (applier thunk) + (thunk)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Types +;; Types / Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(define-cstruct _rkt_evt_t + ([w _int] + [evt _pointer] + )) + ;RKTWEBVIEW_QT_EXPORT void rkt_webview_init(int &argc, char **argv); (define-rktwebview rkt_webview_init (_fun -> _void)) @@ -48,7 +72,8 @@ ;RKTWEBVIEW_QT_EXPORT int rkt_webview_create(int parent); (define-rktwebview rkt_webview_create - (_fun _int -> _int)) + (_fun _int (_fun #:keep callback-box #:async-apply applier + _rkt_evt_t-pointer -> _void) -> _int)) ;RKTWEBVIEW_QT_EXPORT void rkt_webview_close(int wv); (define-rktwebview rkt_webview_close @@ -59,6 +84,37 @@ (_fun _int _string/utf-8 -> _int)) ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_html(int wv, const char *html); +(define-rktwebview rkt_webview_set_html + (_fun _int _string/utf-8 -> _int)) + +;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_run_js(int wv, const char *js); +(define-rktwebview rkt_webview_run_js + (_fun _int _string/utf-8 -> _int)) + +;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_open_devtools(int wv); +(define-rktwebview rkt_webview_open_devtools + (_fun _int -> _int)) + +;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_destroy_event(rkt_event_t e); +(define-rktwebview rkt_webview_destroy_event + (_fun _rkt_evt_t-pointer -> _int)) + +;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_move(rktwebview_t w, int x, int y); +(define-rktwebview rkt_webview_move + (_fun _int _int _int -> _int)) + +;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_resize(rktwebview_t w, int width, int height); +(define-rktwebview rkt_webview_resize + (_fun _int _int _int -> _int)) + +;RKTWEBVIEW_QT_EXPORT bool rkt_webview_valid(rktwebview_t wv); +(define-rktwebview rkt_webview_valid + (_fun _int -> _int)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Initialize and start library +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define process-events #t) @@ -79,4 +135,95 @@ (rkt_webview_init) (start-event-processing) - \ No newline at end of file + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Provided features +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-struct rkt-wv + (win evt-queue callback [valid #:mutable]) + #:transparent + ) + +(define rkt-wv-store (make-hash)) + +(define (rkt-process-events handle) + (if (> (queue-length (rkt-wv-evt-queue handle)) 0) + (let ((e (dequeue! (rkt-wv-evt-queue handle)))) + (if (symbol? e) + (if (eq? e 'quit) + (begin + (hash-remove! rkt-wv-store (rkt-wv-win handle)) + 'quit) + (rkt-process-events handle)) + (let ((evt (cast (rkt_evt_t-evt e) _pointer _string*/utf-8))) + ((rkt-wv-callback handle) handle evt) + (rkt_webview_destroy_event e) + (rkt-process-events handle))) + ) + 'done)) + +(define (rkt-webview-create parent evt-callback) + (let ((evt-queue (make-queue))) + (let ((wv (rkt_webview_create parent + (λ (rkt-evt) + (enqueue! evt-queue rkt-evt))))) + (let ((handle (make-rkt-wv wv evt-queue evt-callback #t))) + (thread (λ () + (sleep 1) + (letrec ((f (λ () + (let ((r (rkt-process-events handle))) + (if (eq? r 'quit) + (begin + (set-rkt-wv-valid! handle #f) + (displayln "Quitting event loop") + 'done) + (begin + ;(displayln "Waiting for events.") + (sleep 0.01) + (f))))))) + (f)))) + (hash-set! rkt-wv-store (rkt-wv-win handle) handle) + handle)))) + +(define (rkt-webview-close handle) + (rkt_webview_close (rkt-wv-win handle)) + (enqueue! (rkt-wv-evt-queue handle) 'quit) + #t) + +(define (rkt-webview-set-url! wv url) + (rkt_webview_set_url (rkt-wv-win wv) url)) + +(define (rkt-webview-set-html! wv html) + (rkt_webview_set_html (rkt-wv-win wv) html)) + +(define (rkt-webview-run-js wv js) + (rkt_webview_run_js (rkt-wv-win wv) js)) + +(define (rkt-webview-resize wv w h) + (rkt_webview_resize (rkt-wv-win wv) w h)) + +(define (rkt-webview-move wv x y) + (rkt_webview_move (rkt-wv-win wv) x y)) + +(define (rkt-webview-open-devtools wv) + (rkt_webview_open_devtools (rkt-wv-win wv))) + +(define (rkt-webview-valid? wv) + (if (eq? (rkt-wv-valid wv) #f) + #f + (if (= (rkt_webview_valid wv) 0) + #f + #t))) + +(define (rkt-webview-exit) + (let ((open-windows (hash->list rkt-wv-store))) + (for-each (λ (kv) + (let ((win (car kv)) + (handle (cdr kv))) + (rkt-webview-close handle))) + open-windows)) + (stop-event-processing)) + + + diff --git a/racket-webview.rkt b/racket-webview.rkt index f58157e..db838d0 100644 --- a/racket-webview.rkt +++ b/racket-webview.rkt @@ -1,6 +1,6 @@ #lang racket/base -(require "racket-webview-ffi.rkt" +(require "racket-webview-qt.rkt" "utils.rkt" web-server/servlet web-server/servlet-env @@ -16,16 +16,17 @@ (provide webview-create webview-devtools - webview-has-events? - webview-event-count - webview-get-event - webview-set-event-callback! - webview-clear-event-callback! - webview-bind + webview-close webview-run-js - ;webview-call-js + webview-move + webview-resize + webview-bind! ) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Web server +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (define current-servlet-port 8083) (define current-window-nr 1) @@ -36,10 +37,12 @@ (file->string file))) (define-struct wv - (handle port window-nr - [file-getter #:mutable] - [boilerplate-js #:mutable] - [webserver-thread #:mutable])) + ([handle #:mutable] + port + [window-nr #:mutable] + [file-getter #:mutable] + [boilerplate-js #:mutable] + [webserver-thread #:mutable])) (define (process-html wv-handle path out) (let ((html (file->string path)) @@ -90,79 +93,65 @@ #:stateless? #t ;#:launch-browser #f #:servlet-regexp #rx"")))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Utilities +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define (util-parse-event evt) + (let ((wv-d0 (with-input-from-string evt read-json))) + wv-d0)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Webview functions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define (webview-create file-getter #:boilerplate-js [bj (default-boilerplate-js)]) - (let* ((wv (rkt_create_webview)) - (h (make-wv wv current-servlet-port current-window-nr file-getter bj #f)) +(define (webview-create file-getter event-callback + #:boilerplate-js [bj (default-boilerplate-js)] + #:parent [p 0]) + (let* ((h (make-wv #f current-servlet-port -1 file-getter bj #f)) + (server (let ((s (start-web-server h))) + (sleep 1) + s)) + (event-processor (λ (wv evt) + (event-callback h (util-parse-event evt)))) + (wv (rkt-webview-create p event-processor)) (base-req (format "http://127.0.0.1:~a" (wv-port h))) ) - (set-wv-webserver-thread! h (start-web-server h)) - (rkt_webview_navigate (wv-handle h) base-req) + (set-wv-handle! h wv) + (set-wv-window-nr! h (rkt-wv-win wv)) + (set-wv-webserver-thread! h server) + (rkt-webview-set-url! (wv-handle h) base-req) (set! current-servlet-port (+ current-servlet-port 1)) - (set! current-window-nr (+ current-window-nr 1)) h)) (define (webview-devtools wv) - (rkt_webview_devtools (wv-handle wv))) + (rkt-webview-open-devtools (wv-handle wv))) -(define (webview-parse-event evt) - (let ((wv-d0 (with-input-from-string evt read-json))) - ;(displayln wv-d0) - (let ((wv-d1 (with-input-from-string (hash-ref wv-d0 'data) read-json))) - ;(displayln wv-d1) - (let ((wv-d2 (with-input-from-string (car wv-d1) read-json))) - ;(displayln wv-d2) - wv-d2)))) +(define (webview-move wv x y) + (rkt-webview-move (wv-handle wv) x y)) -(define (webview-set-event-callback! wv cb) - (rkt_webview_set_event_callback! (wv-handle wv) (wv-window-nr wv) - (λ (context data) - (let ((e (webview-parse-event data))) - (cb context e))))) +(define (webview-resize wv w h) + (rkt-webview-resize (wv-handle wv) w h)) -(define (webview-clear-event-callback! wv) - (rkt_webview_clear_event_callback! (wv-handle wv) (wv-window-nr wv))) - - -(define (webview-get-event wv) - (if (> (rkt_webview_pending_events (wv-handle wv)) 0) - (let ((item (rkt_webview_get_event (wv-handle wv)))) - (let ((data (rkt_webview_item_data item))) - (rkt_webview_destroy_item item) - (let ((wv-d0 (with-input-from-string data read-json))) - ;(displayln wv-d0) - (let ((wv-d1 (with-input-from-string (hash-ref wv-d0 'data) read-json))) - ;(displayln wv-d1) - (let ((wv-d2 (with-input-from-string (car wv-d1) read-json))) - ;(displayln wv-d2) - wv-d2 - ) - ) - ) - ) - ) - #f) +(define (webview-close wv) + (rkt-webview-close (wv-handle wv)) + (kill-thread (wv-webserver-thread wv)) ) -(define (webview-has-events? wv) - (>= (rkt_webview_pending_events (wv-handle wv)) 1) - ) - -(define (webview-event-count wv) - (rkt_webview_pending_events (wv-handle wv))) - -(define (webview-bind wv selector event) +(define (webview-bind! wv selector event) (let ((sel (if (symbol? selector) (format "#~a" selector) selector)) (evt (format "~a" event))) - (rkt_webview_run_js (wv-handle wv) - (format "window._web_wire_bind_evt_ids(~a, '~a', '~a')" + (webview-run-js wv + (format "window.rkt_bind_evt_ids(~a, '~a', '~a')" (wv-window-nr wv) sel evt)))) (define (webview-run-js wv js) - (rkt_webview_run_js (wv-handle 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))) @@ -184,13 +173,16 @@ p))) (define (test) - (let ((h (webview-create file-getter))) - (displayln (webview-has-events? h)) + (let* ((cb (λ (handle evt) + (displayln evt))) + (h (webview-create file-getter cb))) + h)) + - (while (not (webview-has-events? h)) - (displayln "Waiting...") - (sleep 1)) - (let ((evt (webview-get-event h))) - (when (string=? (hash-ref evt 'evt) "html-loaded") - (webview-bind h "button" "click"))) - h)) \ No newline at end of file +; (while (not (webview-has-events? h)) +; (displayln "Waiting...") +; (sleep 1)) +; (let ((evt (webview-get-event h))) +; (when (string=? (hash-ref evt 'evt) "html-loaded") +; (webview-bind h "button" "click"))) +; h)) \ No newline at end of file diff --git a/rktwebview_qt/CMakeLists.txt b/rktwebview_qt/CMakeLists.txt index 8f0efa6..3816279 100644 --- a/rktwebview_qt/CMakeLists.txt +++ b/rktwebview_qt/CMakeLists.txt @@ -22,6 +22,7 @@ add_library(rktwebview_qt SHARED rktwebview_internal.h webviewwindow.h webviewwindow.cpp webviewapp.h webviewapp.cpp + rktutils.h rktutils.cpp ) target_link_libraries(rktwebview_qt PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) @@ -40,6 +41,7 @@ add_executable(rktwebview_qt_test webviewwindow.h webviewwindow.cpp rktwebview_internal.h webviewapp.h webviewapp.cpp + rktutils.h rktutils.cpp ) target_compile_definitions(rktwebview_qt_test PRIVATE RKTWEBVIEW_QT_LIBRARY) diff --git a/rktwebview_qt/main.cpp b/rktwebview_qt/main.cpp index e7840a6..fdf00f8 100644 --- a/rktwebview_qt/main.cpp +++ b/rktwebview_qt/main.cpp @@ -5,6 +5,12 @@ static int _argc; static char **_argv; +void eventCb(rkt_event_t *e) +{ + printf("event: %s\n", e->event); + rkt_webview_destroy_event(e); +} + int main(int argc, char *argv[]) { int wv1; @@ -14,20 +20,30 @@ int main(int argc, char *argv[]) _argv = argv; rkt_webview_init(); - wv1 = rkt_webview_create(0); + wv1 = rkt_webview_create(0, eventCb); rkt_webview_set_url(wv1, "https://wikipedia.org"); int i = 0; - while(i < 20) { + while(i < 60) { printf("Waiting...%d\n", i); rkt_webview_process_events(1000); - if (i == 10) { - wv2 = rkt_webview_create(0); + if (i == 6) { + rkt_webview_open_devtools(wv1); } - if (i == 15) { - rkt_webview_close(wv1); + if (i == 10) { + wv2 = rkt_webview_create(0, eventCb); + } + + if (i > 10) { + char buf[1000]; + sprintf(buf, "{ let obj = { e: 'test', i: %d }; window.rkt_send_event(obj); }", i); + rkt_webview_run_js(wv1, buf); + } + + if (i == 24) { + rkt_webview_close(wv2); } i += 1; } diff --git a/rktwebview_qt/rktutils.cpp b/rktwebview_qt/rktutils.cpp new file mode 100644 index 0000000..58cff39 --- /dev/null +++ b/rktwebview_qt/rktutils.cpp @@ -0,0 +1,27 @@ +#include "rktutils.h" + +#include +#include +#include + +QString mkEventJson(const EventContainer &kv) +{ + QJsonObject obj; + + QList keys = kv.keys(); + int i, N; + for(i = 0, N = keys.length(); i < N; i++) { + const QString &key = keys[i]; + const QVariant &v = kv[key]; + obj[key] = v.toJsonValue(); + } + + QJsonDocument doc(obj); + return QString::fromUtf8(doc.toJson(QJsonDocument::JsonFormat::Compact)); +} + +QHash mkEvent() +{ + QHash h; + return h; +} diff --git a/rktwebview_qt/rktutils.h b/rktwebview_qt/rktutils.h new file mode 100644 index 0000000..ef3ac0f --- /dev/null +++ b/rktwebview_qt/rktutils.h @@ -0,0 +1,18 @@ +#ifndef __RKT_UTILS_H__ +#define __RKT_UTILS_H__ + +#include +#include +#include + +class EventContainer : public QHash +{ +public: + EventContainer(const QString &evt) { + this->insert("event", evt); + } +}; + +QString mkEventJson(const EventContainer &kv); + +#endif diff --git a/rktwebview_qt/rktwebview.cpp b/rktwebview_qt/rktwebview.cpp index 07ee3c5..c887b4e 100644 --- a/rktwebview_qt/rktwebview.cpp +++ b/rktwebview_qt/rktwebview.cpp @@ -27,127 +27,56 @@ 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, void (*js_event_cb)(const char *)) +int rkt_webview_create(rktwebview_t parent, event_cb_t js_event_cb) { rkt_webview_init(); return handler->rktWebViewCreate(parent, js_event_cb); } -void rkt_webview_close(int wv) +void rkt_webview_close(rktwebview_t wv) { rkt_webview_init(); handler->rktWebViewClose(wv); } -result_t rkt_webview_set_url(int wv, const char *url) +result_t rkt_webview_set_url(rktwebview_t wv, const char *url) { rkt_webview_init(); result_t r = handler->rktSetUrl(wv, url); return r; } -///////////////////////////////////////////////////////////////////// -// Supporting functions -///////////////////////////////////////////////////////////////////// - -void queue_init(queue_t **q) +result_t rkt_webview_set_html(rktwebview_t wv, const char *url) { - *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); + rkt_webview_init(); + result_t r = handler->rktSetHtml(wv, url); + return r; } +result_t rkt_webview_run_js(rktwebview_t wv, const char *js) +{ + rkt_webview_init(); + result_t r = handler->rktRunJs(wv, js); + return r; +} + + +result_t rkt_webview_open_devtools(rktwebview_t wv) +{ + rkt_webview_init(); + result_t r = handler->rktOpenDevtools(wv); + return r; +} void rkt_webview_process_events(int for_ms) { - //rkt_webview_init(); + rkt_webview_init(); int64_t start_ms = current_ms(); int64_t end_ms = start_ms + for_ms; @@ -157,3 +86,35 @@ void rkt_webview_process_events(int for_ms) handler->doEvents(); } } + + +result_t rkt_webview_destroy_event(rkt_event_t *e) +{ + free(e->event); + free(e); + return result_t::oke; +} + +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; +} + + +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; +} + + +bool rkt_webview_valid(rktwebview_t wv) +{ + rkt_webview_init(); + return handler->rktValid(wv); +} diff --git a/rktwebview_qt/rktwebview.h b/rktwebview_qt/rktwebview.h index 4d43590..47c1626 100644 --- a/rktwebview_qt/rktwebview.h +++ b/rktwebview_qt/rktwebview.h @@ -3,31 +3,16 @@ #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; + char *event; +} rkt_event_t; + +typedef void (*event_cb_t)(rkt_event_t *); typedef enum { no_result_yet = -1, @@ -42,15 +27,29 @@ typedef enum { webview_invalid_state = 8, webview_invalid_argument = 9, webview_unspecified = 10, - webview_dispatch_failed = 11 + webview_dispatch_failed = 11, + move_failed = 12, + resize_failed = 13 } 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, void (*js_event_cb)(const char *msg)); -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); + +RKTWEBVIEW_QT_EXPORT int rkt_webview_create(rktwebview_t parent, event_cb_t js_event_cb); +RKTWEBVIEW_QT_EXPORT void rkt_webview_close(rktwebview_t wv); +RKTWEBVIEW_QT_EXPORT bool rkt_webview_valid(rktwebview_t wv); + + +RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_url(rktwebview_t wv, const char *url); +RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_html(rktwebview_t wv, const char *html); + +RKTWEBVIEW_QT_EXPORT result_t rkt_webview_run_js(rktwebview_t wv, const char *js); +RKTWEBVIEW_QT_EXPORT result_t rkt_webview_open_devtools(rktwebview_t wv); + +RKTWEBVIEW_QT_EXPORT result_t rkt_webview_destroy_event(rkt_event_t *e); + +RKTWEBVIEW_QT_EXPORT result_t rkt_webview_move(rktwebview_t w, int x, int y); +RKTWEBVIEW_QT_EXPORT result_t rkt_webview_resize(rktwebview_t w, int width, int height); } diff --git a/rktwebview_qt/rktwebview_internal.h b/rktwebview_qt/rktwebview_internal.h index 43aee0e..71ff3c2 100644 --- a/rktwebview_qt/rktwebview_internal.h +++ b/rktwebview_qt/rktwebview_internal.h @@ -3,23 +3,4 @@ #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 index c475862..4c44b59 100644 --- a/rktwebview_qt/rktwebview_qt.cpp +++ b/rktwebview_qt/rktwebview_qt.cpp @@ -2,16 +2,22 @@ #include "webviewqt.h" #include "rktwebview.h" #include "webviewwindow.h" +#include "rktutils.h" #include #include #include #include #include -#define COMMAND_QUIT 1 -#define COMMAND_CLOSE 2 -#define COMMAND_CREATE 3 -#define COMMAND_SET_URL 4 +#define COMMAND_QUIT 1 +#define COMMAND_CLOSE 2 +#define COMMAND_CREATE 3 +#define COMMAND_SET_URL 4 +#define COMMAND_SET_HTML 5 +#define COMMAND_RUN_JS 6 +#define COMMAND_DEV_TOOLS 7 +#define COMMAND_MOVE 8 +#define COMMAND_RESIZE 9 class Command { @@ -27,13 +33,6 @@ public: } }; -static QString jsonString(QJsonObject obj) -{ - QJsonDocument doc(obj); - QString j = QString::fromUtf8(doc.toJson(QJsonDocument::JsonFormat::Compact)); - return j; -} - void Rktwebview_qt::processCommands() { while(!_command_queue.empty()) { @@ -49,7 +48,7 @@ void Rktwebview_qt::processCommands() int parent = cmd->args[0].toInt(); void *f = cmd->args[1].value(); - void (*js_event_cb)(const char *msg) = reinterpret_cast (f); + event_cb_t js_event_cb = reinterpret_cast (f); QWidget *p; if (_views.contains(parent)) { @@ -78,8 +77,7 @@ void Rktwebview_qt::processCommands() if (_views.contains(wv)) { WebviewWindow *w= _views[wv]; _views.remove(wv); - w->close(); - w->deleteLater(); + w->closeView(); cmd->result = true; } else { cmd->result = false; @@ -102,6 +100,73 @@ void Rktwebview_qt::processCommands() cmd->done = true; } break; + case COMMAND_SET_HTML: { + int wv = cmd->args[0].toInt(); + QString html = cmd->args[1].toString(); + if (_views.contains(wv)) { + WebviewWindow *w = _views[wv]; + WebViewQt *v = w->view(); + v->setHtml(html); + cmd->result = true; + } else { + cmd->result = false; + } + cmd->done = true; + } + break; + case COMMAND_RUN_JS: { + int wv = cmd->args[0].toInt(); + QString js = cmd->args[1].toString(); + if (_views.contains(wv)) { + WebviewWindow *w = _views[wv]; + w->runJs(js); + cmd->result = true; + } else { + cmd->result = false; + } + cmd->done = true; + } + break; + case COMMAND_DEV_TOOLS: { + int wv = cmd->args[0].toInt(); + if (_views.contains(wv)) { + WebviewWindow *w = _views[wv]; + w->openDevTools(); + cmd->result = true; + } else { + cmd->result = false; + } + cmd->done = true; + } + break; + case COMMAND_MOVE: { + int wv = cmd->args[0].toInt(); + int x = cmd->args[1].toInt(); + int y = cmd->args[2].toInt(); + if (_views.contains(wv)) { + WebviewWindow *w = _views[wv]; + w->move(x, y); + cmd->result = true; + } else { + cmd->result = false; + } + cmd->done = true; + } + break; + case COMMAND_RESIZE: { + int wv = cmd->args[0].toInt(); + int width = cmd->args[1].toInt(); + int height = cmd->args[2].toInt(); + if (_views.contains(wv)) { + WebviewWindow *w = _views[wv]; + w->resize(width, height); + cmd->result = true; + } else { + cmd->result = false; + } + cmd->done = true; + } + break; default: { cmd->result = false; cmd->done = true; @@ -111,14 +176,26 @@ void Rktwebview_qt::processCommands() } } -void Rktwebview_qt::processJsEventQueue() +void Rktwebview_qt::processJsEventQueues() { - + QList wvs = _views.keys(); + int i, N; + for(i = 0, N = wvs.length(); i < N; i++) { + int wv = wvs[i]; + if (_views.contains(wv)) { + WebviewWindow *win = _views[wv]; + win->processJsEvents(); + } + } } void Rktwebview_qt::removeView(int id) { - _views.remove(id); + if (_views.contains(id)) { + WebviewWindow *win = _views[id]; + _views.remove(id); + _view_js_callbacks.remove(id); + } } int Rktwebview_qt::nextHandle() @@ -127,7 +204,7 @@ int Rktwebview_qt::nextHandle() return h; } -int Rktwebview_qt::rktWebViewCreate(int parent, void (*js_evt_cb)(const char *)) +int Rktwebview_qt::rktWebViewCreate(int parent, event_cb_t js_evt_cb) { Command c(COMMAND_CREATE); c.args.push_back(parent); @@ -168,28 +245,113 @@ result_t Rktwebview_qt::rktSetUrl(rktwebview_t wv, const char *url) return r ? result_t::oke : result_t::set_navigate_failed; } +result_t Rktwebview_qt::rktSetHtml(rktwebview_t wv, const char *html) +{ + Command c(COMMAND_SET_HTML); + QString _html(html); + c.args.push_back(wv); + c.args.push_back(_html); + _command_queue.enqueue(&c); + + while(!c.done) { doEvents(); } + + bool r = c.result.toBool(); + + return r ? result_t::oke : result_t::set_navigate_failed; +} + +result_t Rktwebview_qt::rktRunJs(rktwebview_t wv, const char *js) +{ + Command c(COMMAND_RUN_JS); + QString _js(js); + c.args.push_back(wv); + c.args.push_back(_js); + _command_queue.enqueue(&c); + while(!c.done) { doEvents(); } + bool r = c.result.toBool(); + return r ? result_t::oke : result_t::eval_js_failed; +} + +result_t Rktwebview_qt::rktMove(rktwebview_t wv, int x, int y) +{ + Command c(COMMAND_MOVE); + c.args.push_back(wv); + c.args.push_back(x); + c.args.push_back(y); + _command_queue.enqueue(&c); + while(!c.done) { doEvents(); } + bool r = c.result.toBool(); + return r ? result_t::oke : result_t::move_failed; +} + +result_t Rktwebview_qt::rktResize(rktwebview_t wv, int w, int h) +{ + Command c(COMMAND_RESIZE); + c.args.push_back(wv); + c.args.push_back(w); + c.args.push_back(h); + _command_queue.enqueue(&c); + while(!c.done) { doEvents(); } + bool r = c.result.toBool(); + return r ? result_t::oke : result_t::resize_failed; +} + +bool Rktwebview_qt::rktValid(rktwebview_t wv) +{ + return _views.contains(wv); +} + +result_t Rktwebview_qt::rktOpenDevtools(rktwebview_t wv) +{ + Command c(COMMAND_DEV_TOOLS); + c.args.push_back(wv); + _command_queue.enqueue(&c); + while(!c.done) { doEvents(); } + bool r = c.result.toBool(); + return r ? result_t::oke : result_t::eval_js_failed; +} + +void Rktwebview_qt::onPageLoad(rktwebview_t w) +{ +} + void Rktwebview_qt::pageLoaded(rktwebview_t w, bool ok) { - // Inject event handling code for the javascript side - runJs(w, "window.rkt_event_queue = [];\n" - "window.rkt_send_event = function(obj) { window.rkt_event_queue.push(obj); };\n" - "window.rkt_get_events = function() { " - " let q = window.rkt_event_queue; " - " window.rkt_event_queue = [];" - " let json_q = JSON.stringify(q);" - " return json_q;" - "};"); + runJs(w, + "if (window.rkt_event_queue === undefined) { window.rkt_event_queue = []; }\n" + "window.rkt_send_event = function(obj) {\n" + " console.log('Sending event: ' + obj);\n" + " window.rkt_event_queue.push(obj);\n" + "};\n" + "window.rkt_get_events = function() {\n" + " let q = window.rkt_event_queue;\n" + " window.rkt_event_queue = [];\n" + " let json_q = JSON.stringify(q);\n" + " return json_q;\n" + "};\n" + ); // trigger page loaded. - QJsonObject obj; - obj["event"] = "page-loaded"; - obj["oke"] = ok; - triggerEvent(w, jsonString(obj)); + EventContainer e("page-loaded"); + e["oke"] = ok; + triggerEvent(w, e); +} + +void Rktwebview_qt::triggerEvent(rktwebview_t wv, const EventContainer &e) +{ + triggerEvent(wv, mkEventJson(e)); } void Rktwebview_qt::triggerEvent(rktwebview_t wv, const QString &msg) { - + if (_view_js_callbacks.contains(wv)) { + event_cb_t js_event_cb = _view_js_callbacks[wv]; + char *evt = strdup(msg.toUtf8().constData()); + rkt_event_t *e = static_cast(malloc(sizeof(rkt_event_t))); + e->wv = wv; + e->event = evt; + js_event_cb(e); + } } void Rktwebview_qt::rktQuit() @@ -211,8 +373,8 @@ void Rktwebview_qt::runJs(rktwebview_t wv, const char *js) { if (_views.contains(wv)) { QString _js(js); - WebViewQt *view = _views[wv]->view(); - view->runJs(_js); + WebviewWindow *win = _views[wv]; + win->runJs(_js); } } @@ -234,6 +396,8 @@ Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) : _app = new QApplication(_argc, _argv); connect(&_process_commands, &QTimer::timeout, this, &Rktwebview_qt::processCommands); _process_commands.start(10); + connect(&_process_events, &QTimer::timeout, this, &Rktwebview_qt::processJsEventQueues); + _process_events.start(5); *_handler = nullptr; } diff --git a/rktwebview_qt/rktwebview_qt.h b/rktwebview_qt/rktwebview_qt.h index 86afa91..0cf6ccf 100644 --- a/rktwebview_qt/rktwebview_qt.h +++ b/rktwebview_qt/rktwebview_qt.h @@ -3,6 +3,7 @@ #include "rktwebview_qt_global.h" #include "rktwebview_internal.h" +#include "rktutils.h" #include #include @@ -24,18 +25,23 @@ private: QApplication *_app; rktwebview_t _current_handle; QHash _views; - QHash _view_js_callbacks; + QHash _view_js_callbacks; QQueue _command_queue; QTimer _process_commands; + QTimer _process_events; Rktwebview_qt **_handler; int _argc; char *_argv[1]; +private: + void runJs(rktwebview_t wv, const char *js); + public slots: void processCommands(); + void processJsEventQueues(); public: void removeView(int id); @@ -43,23 +49,26 @@ public: public: int nextHandle(); public: - int rktWebViewCreate(int parent, void(*js_evt_cb)(const char *msg)); + int rktWebViewCreate(int parent, event_cb_t js_evt_cb); void rktWebViewClose(int wv); void rktQuit(); - void runJs(rktwebview_t wv, const char *js); - item_t callJs(rktwebview_t wv, const char *js); - - void setHtml(rktwebview_t wv, const char *html); - void navigate(rktwebview_t wv, const char *url); + result_t rktOpenDevtools(rktwebview_t wv); result_t rktSetUrl(rktwebview_t wv, const char *url); + result_t rktSetHtml(rktwebview_t wv, const char *html); + result_t rktRunJs(rktwebview_t wv, const char *js); + result_t rktMove(rktwebview_t wv, int x, int y); + result_t rktResize(rktwebview_t wv, int w, int h); + bool rktValid(rktwebview_t wv); public: // Events for the backend void pageLoaded(rktwebview_t w, bool ok); + void onPageLoad(rktwebview_t w); public: void triggerEvent(rktwebview_t wv, const QString &msg); + void triggerEvent(rktwebview_t wv, const EventContainer &e); public: void doEvents(); diff --git a/rktwebview_qt/webviewqt.cpp b/rktwebview_qt/webviewqt.cpp index b3357c8..9526b5e 100644 --- a/rktwebview_qt/webviewqt.cpp +++ b/rktwebview_qt/webviewqt.cpp @@ -1,11 +1,13 @@ #include "webviewqt.h" +#include "webviewwindow.h" #include #include -WebViewQt::WebViewQt(int id, QWidget *parent) - : QWebEngineView(parent) +WebViewQt::WebViewQt(int id, WebviewWindow *window) + : QWebEngineView(window) { _id = id; + _window = window; } int WebViewQt::id() const @@ -13,8 +15,9 @@ int WebViewQt::id() const return _id; } -QString WebViewQt::runJs(const QString &js) +WebviewWindow *WebViewQt::wvWin() { + return _window; } diff --git a/rktwebview_qt/webviewqt.h b/rktwebview_qt/webviewqt.h index d979396..396b06c 100644 --- a/rktwebview_qt/webviewqt.h +++ b/rktwebview_qt/webviewqt.h @@ -4,24 +4,25 @@ #include #include +class WebviewWindow; + class WebViewQt : public QWebEngineView { Q_OBJECT private: - int _id; + int _id; + WebviewWindow *_window; public: int id() const; - -public: - QString runJs(const QString &js); + WebviewWindow *wvWin(); signals: void pageLoaded(WebViewQt *, bool ok); public: - WebViewQt(int id, QWidget *parent = nullptr); + WebViewQt(int id, WebviewWindow *window); }; diff --git a/rktwebview_qt/webviewwindow.cpp b/rktwebview_qt/webviewwindow.cpp index 18cf159..9e5f118 100644 --- a/rktwebview_qt/webviewwindow.cpp +++ b/rktwebview_qt/webviewwindow.cpp @@ -2,15 +2,33 @@ #include "webviewqt.h" #include "rktwebview_qt.h" +#include "rktutils.h" #include #include #include #include +#include +#include + +#include + +WebviewWindow::WebviewWindow(QWidget *parent) + : QMainWindow{parent} +{ + _view = nullptr; + _must_close = false; + + _devtools = nullptr; + + connect(&_resize_timer, &QTimer::timeout, this, &WebviewWindow::triggerResize); + connect(&_move_timer, &QTimer::timeout, this, &WebviewWindow::triggerMove); +} + void WebviewWindow::processJsEvents() { QWebEnginePage *p = _view->page(); - p->runJavaScript("window.getPendingEvents();", + p->runJavaScript("if (window.rkt_get_events) { window.rkt_get_events(); } else { JSON.stringify([]); }", [this](const QVariant &v) { QString s = v.toString(); QJsonParseError err; @@ -19,11 +37,15 @@ void WebviewWindow::processJsEvents() QJsonArray a = doc.array(); int i, N; for(i = 0, N = a.size(); i < N; i++) { - QJsonObject evt = a[i].toObject(); - QJsonDocument doc_out(evt); - QString msg = doc_out.toJson(QJsonDocument::JsonFormat::Compact); - this->_container->triggerJsEvent(_view->id(), msg); + QJsonObject js_evt = a[i].toObject(); + + EventContainer e("js-evt"); + e["js-evt"] = js_evt; + + this->_container->triggerEvent(_view->id(), e); } + } else { + } } ); @@ -31,7 +53,25 @@ void WebviewWindow::processJsEvents() void WebviewWindow::closeEvent(QCloseEvent *evt) { - _container->removeView(_view->id()); + if (_must_close) { + EventContainer e("closed"); + _container->triggerEvent(_view->id(), e); + _container->removeView(_view->id()); + this->deleteLater(); + if (_devtools != nullptr) { + _devtools->deleteLater(); + } + } else { + evt->ignore(); + EventContainer e("can-close?"); + _container->triggerEvent(_view->id(), e); + } +} + +void WebviewWindow::closeView() +{ + _must_close = true; + close(); } void WebviewWindow::addView(WebViewQt *v, Rktwebview_qt *c) @@ -41,9 +81,41 @@ void WebviewWindow::addView(WebViewQt *v, Rktwebview_qt *c) this->setCentralWidget(v); QWebEnginePage *page = _view->page(); + + // Inject event handling code for the javascript side + QWebEngineScriptCollection &col = page->scripts(); + QWebEngineScript evt_script; + evt_script.setInjectionPoint(QWebEngineScript::DocumentReady); + evt_script.setName("rkt_webview_event_handling"); + evt_script.setSourceCode( + "window.rkt_event_queue = [];\n" + "window.rkt_send_event = function(obj) {\n" + " console.log('Sending event: ' + obj);\n" + " window.rkt_event_queue.push(obj);\n" + "};\n" + "window.rkt_get_events = function() {\n" + " let q = window.rkt_event_queue;\n" + " window.rkt_event_queue = [];\n" + " let json_q = JSON.stringify(q);\n" + " return json_q;\n" + "};\n" + "console.log('We have set:');\n" + "console.log('window.rkt_event_queue:');\n" + "console.log(window.rkt_event_queue);\n" + "console.log('window.rkt_send_event:');\n" + "console.log(window.rkt_send_event);\n" + "console.log('window.rkt_get_events:');\n" + "console.log(window.rkt_get_events);\n" + ); + evt_script.setWorldId(QWebEngineScript::ApplicationWorld); + //col.insert(evt_script); + connect(page, &QWebEnginePage::loadFinished, this, [this](bool ok) { _container->pageLoaded(_view->id(), ok); }); + connect(page, &QWebEnginePage::loadStarted, this, [this]() { + _container->onPageLoad(_view->id()); + }); } WebViewQt *WebviewWindow::view() @@ -51,9 +123,70 @@ WebViewQt *WebviewWindow::view() return _view; } -WebviewWindow::WebviewWindow(QWidget *parent) - : QMainWindow{parent} +void WebviewWindow::runJs(const QString &js) { - _view = nullptr; - connect(&_process_js_events, &QTimer::timeout, this, &WebviewWindow::processJsEvents); + QWebEnginePage *p = _view->page(); + p->runJavaScript(js); } + +void WebviewWindow::openDevTools() +{ + _devtools = new QMainWindow(this); + QWebEngineView *devtools_view = new QWebEngineView(_devtools); + _devtools->setCentralWidget(devtools_view); + _devtools->resize(800, 600); + _devtools->show(); + _view->page()->setDevToolsPage(devtools_view->page()); + connect(_devtools, &WebviewWindow::destroyed, this, [this](QObject *) { + _devtools = nullptr; + }); +} + + +void WebviewWindow::moveEvent(QMoveEvent *event) +{ + _x = event->pos().x(); + _y = event->pos().y(); + _move_timer.setSingleShot(true); + _move_timer.start(500); +} + +void WebviewWindow::triggerMove() +{ + EventContainer xy("move"); + xy["x"] = _x; + xy["y"] = _y; + _container->triggerEvent(_view->id(), xy); +} + +void WebviewWindow::resizeEvent(QResizeEvent *event) +{ + _w = event->size().width(); + _h = event->size().height(); + _resize_timer.setSingleShot(true); + _resize_timer.start(500); +} + +void WebviewWindow::triggerResize() +{ + EventContainer s("resize"); + s["w"] = _w; + s["h"] = _h; + _container->triggerEvent(_view->id(), s); +} + +void WebviewWindow::showEvent(QShowEvent *event) +{ + EventContainer show("show"); + _container->triggerEvent(_view->id(), show); +} + +void WebviewWindow::hideEvent(QHideEvent *event) +{ + if (!_must_close) { + EventContainer hide("hide"); + _container->triggerEvent(_view->id(), hide); + } +} + + diff --git a/rktwebview_qt/webviewwindow.h b/rktwebview_qt/webviewwindow.h index 8b91411..4e48520 100644 --- a/rktwebview_qt/webviewwindow.h +++ b/rktwebview_qt/webviewwindow.h @@ -13,7 +13,16 @@ class WebviewWindow : public QMainWindow private: Rktwebview_qt *_container; WebViewQt *_view; - QTimer _process_js_events; + QMainWindow *_devtools; + + QTimer _resize_timer; + QTimer _move_timer; + + int _x; + int _y; + int _w; + int _h; + bool _must_close; public slots: void processJsEvents(); @@ -22,14 +31,31 @@ protected: void closeEvent(QCloseEvent *evt); public: - void addView(WebViewQt *v, Rktwebview_qt *c); + void closeView(); +public: + void addView(WebViewQt *v, Rktwebview_qt *c); WebViewQt *view(); +public: + void runJs(const QString &js); + void openDevTools(); + public: explicit WebviewWindow(QWidget *parent = nullptr); +private slots: + void triggerResize(); + void triggerMove(); + signals: + + // QWidget interface +protected: + void moveEvent(QMoveEvent *event); + void resizeEvent(QResizeEvent *event); + void showEvent(QShowEvent *event); + void hideEvent(QHideEvent *event); }; #endif // WEBVIEWWINDOW_H