diff --git a/private/lib/linux/librktwebview_qt.so b/private/lib/linux/librktwebview_qt.so index a3a89a9..49165c4 100755 Binary files a/private/lib/linux/librktwebview_qt.so and b/private/lib/linux/librktwebview_qt.so differ diff --git a/private/racket-webview-qt.rkt b/private/racket-webview-qt.rkt index 47a5c6d..b360189 100644 --- a/private/racket-webview-qt.rkt +++ b/private/racket-webview-qt.rkt @@ -35,6 +35,7 @@ rkt-webview-exit rkt-webview-valid? rkt-webview-open-devtools + rkt-webview-choose-dir ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -265,6 +266,10 @@ (define-rktwebview rkt_webview_set_title (_fun _int _string/utf-8 -> _rkt_result_t)) +;RKTWEBVIEW_QT_EXPORT rkt_js_result_t *rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir); +(define-rktwebview rkt_webview_choose_dir + (_fun _int _string/utf-8 _string/utf-8 -> _rkt_js_result_t-pointer)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Initialize and start library ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -317,8 +322,10 @@ 'done)) (define (rkt-webview-create parent evt-callback) - (let ((evt-queue (make-queue))) - (let ((wv (rkt_webview_create parent + (let* ((evt-queue (make-queue)) + (parent-win (if (eq? parent #f) 0 (rkt-wv-win parent))) + ) + (let ((wv (rkt_webview_create parent-win (λ (rkt-evt) (enqueue! evt-queue rkt-evt))))) (let ((handle (make-rkt-wv wv evt-queue evt-callback #t))) @@ -386,6 +393,17 @@ (define (rkt-webview-open-devtools wv) (rkt_webview_open_devtools (rkt-wv-win wv))) +(define (rkt-webview-choose-dir wv title base-dir) + (let* ((r (rkt_webview_choose_dir (rkt-wv-win wv) title base-dir)) + (value (cast (rkt_js_result_t-value r) _pointer _string*/utf-8)) + (result (rkt_js_result_t-result r))) + (rkt_webview_destroy_js_result r) + (list result value))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Administration +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (define (rkt-webview-valid? wv) (if (eq? (rkt-wv-valid wv) #f) #f @@ -402,6 +420,9 @@ open-windows)) (stop-event-processing)) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Cleanup on exit +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (plumber-add-flush! (current-plumber) (λ (handle) diff --git a/private/racket-webview.rkt b/private/racket-webview.rkt index 259d7cd..74fff5f 100644 --- a/private/racket-webview.rkt +++ b/private/racket-webview.rkt @@ -21,9 +21,11 @@ (provide webview-create webview-devtools webview-close + webview-run-js webview-call-js webview-call-js-result? + webview-move webview-resize webview-show @@ -32,8 +34,12 @@ webview-maximize webview-minimize webview-window-state - webview-bind! webview-set-title! + + webview-choose-dir + + webview-bind! + webview-set-url! webview-set-html! @@ -192,14 +198,15 @@ (define (webview-create file-getter event-callback #:boilerplate-js [bj (default-boilerplate-js)] - #:parent [p 0]) + #:parent [p #f]) (let* ((h (make-wv #f current-servlet-port -1 file-getter bj #f)) (server (let ((s (start-web-server h))) (sleep 1) ;;; TODO: Check if web server is up. s)) (event-processor (λ (wv evt) (event-callback h (util-parse-event evt)))) - (wv (rkt-webview-create p event-processor)) + (ph (if (wv? p) (wv-handle p) #f)) + (wv (rkt-webview-create ph event-processor)) (base-req (format "http://127.0.0.1:~a" (wv-port h))) ) @@ -253,6 +260,25 @@ (def-win-func webview-present rkt-webview-present) (def-win-func webview-window-state rkt-webview-window-state) +(define/contract (webview-choose-dir wv title base-dir) + (-> wv? string? (or/c path? string?) (or/c hash? boolean?)) + (let ((bd (if (path? base-dir) (path->string base-dir) base-dir))) + (let ((res (rkt-webview-choose-dir (wv-handle wv) title bd))) + (if (eq? res #f) + #f + (cond ((eq? (car res) 'oke) + (let ((h (fromJson (cadr res)))) + (let ((r (make-hash))) + (hash-set! r 'dir (hash-ref h 'dir)) + (hash-set! r 'state (string->symbol + (hash-ref h 'state))) + r))) + (else #f)) + ) + ) + ) + ) + (define/contract (webview-set-title! wv title) (-> wv? string? symbol?) (rkt-webview-set-title! (wv-handle wv) title)) @@ -506,9 +532,6 @@ ) - - - #|(define/contract (webview-set-style! wv selector style-entries) (-> wv? (or/c symbol? string?) (or/c list? list-of-kv?) hash?) diff --git a/rktwebview_qt/command.h b/rktwebview_qt/command.h index 5a92ca3..9b09cba 100644 --- a/rktwebview_qt/command.h +++ b/rktwebview_qt/command.h @@ -22,6 +22,9 @@ #define COMMAND_SHOW_NORMAL_WIN 16 #define COMMAND_WINDOW_STATUS 17 #define COMMAND_SET_TITLE 18 +#define COMMAND_CHOOSE_DIR 19 +#define COMMAND_OPEN_FILE 20 +#define COMMAND_SAVE_FILE 21 class Command { diff --git a/rktwebview_qt/main.cpp b/rktwebview_qt/main.cpp index b0570a7..604e3d8 100644 --- a/rktwebview_qt/main.cpp +++ b/rktwebview_qt/main.cpp @@ -51,7 +51,7 @@ int main(int argc, char *argv[]) if (i == 10) { - wv2 = rkt_webview_create(0, eventCb); + wv2 = rkt_webview_create(wv1, eventCb); rkt_webview_move(wv2, 400, 200); rkt_webview_resize(wv2, 800, 600); rkt_webview_set_url(wv2, "https://127.0.0.1"); diff --git a/rktwebview_qt/rktwebview.cpp b/rktwebview_qt/rktwebview.cpp index 5931d65..aa2b1a4 100644 --- a/rktwebview_qt/rktwebview.cpp +++ b/rktwebview_qt/rktwebview.cpp @@ -184,3 +184,9 @@ result_t rkt_webview_set_title(rktwebview_t wv, const char *title) rkt_webview_init(); return handler->rktWindowSetTitle(wv, title); } + +rkt_js_result_t *rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir) +{ + rkt_webview_init(); + return handler->rktChooseDir(w, title, base_dir); +} diff --git a/rktwebview_qt/rktwebview.h b/rktwebview_qt/rktwebview.h index a9e0295..457147c 100644 --- a/rktwebview_qt/rktwebview.h +++ b/rktwebview_qt/rktwebview.h @@ -29,7 +29,10 @@ typedef enum { webview_unspecified = 10, webview_dispatch_failed = 11, move_failed = 12, - resize_failed = 13 + resize_failed = 13, + choose_dir_failed = 14, + open_file_failed = 15, + save_file_failed = 16 } result_t; typedef struct { @@ -77,6 +80,8 @@ RKTWEBVIEW_QT_EXPORT result_t rkt_webview_maximize(rktwebview_t w); RKTWEBVIEW_QT_EXPORT result_t rkt_webview_minimize(rktwebview_t w); RKTWEBVIEW_QT_EXPORT window_state_t rkt_webview_window_state(rktwebview_t w); +RKTWEBVIEW_QT_EXPORT rkt_js_result_t *rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir); + } #endif // RKTWEBVIEW_H diff --git a/rktwebview_qt/rktwebview_qt.cpp b/rktwebview_qt/rktwebview_qt.cpp index 63cd873..a0a973f 100644 --- a/rktwebview_qt/rktwebview_qt.cpp +++ b/rktwebview_qt/rktwebview_qt.cpp @@ -10,6 +10,7 @@ #include #include #include "command.h" +#include void Rktwebview_qt::processCommand(Command *cmd) { @@ -25,7 +26,7 @@ void Rktwebview_qt::processCommand(Command *cmd) void *f = cmd->args[1].value(); event_cb_t js_event_cb = reinterpret_cast (f); - QWidget *p; + WebviewWindow *p; if (_views.contains(parent)) { p = _views[parent]; } else { @@ -248,6 +249,31 @@ void Rktwebview_qt::processCommand(Command *cmd) cmd->done = true; } break; + case COMMAND_CHOOSE_DIR: { + int wv = cmd->args[0].toInt(); + QString title = cmd->args[1].toString(); + QString base_dir = cmd->args[2].toString(); + if (_views.contains(wv)) { + WebviewWindow *w = _views[wv]; + QString dir = QFileDialog::getExistingDirectory(w, title, base_dir, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + if (dir == "") { + QJsonObject obj; + obj["state"] = "canceled"; + obj["dir"] = base_dir; + cmd->result = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::JsonFormat::Compact)); + } else { + QJsonObject obj; + obj["state"] = "choosen"; + obj["dir"] = dir; + cmd->result = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::JsonFormat::Compact)); + } + } else { + cmd->js_result_ok = false; + cmd->result = false; + } + cmd->done = true; + } + break; default: { cmd->result = false; cmd->done = true; @@ -433,6 +459,31 @@ window_state_t Rktwebview_qt::rktWindowState(rktwebview_t w) return ws; } +rkt_js_result_t *Rktwebview_qt::rktChooseDir(rktwebview_t w, const char *title, const char *base_dir) +{ + Command c(COMMAND_CHOOSE_DIR); + c.args.push_back(w); + + QString t(title); + c.args.push_back(t); + + QString dir(base_dir); + c.args.push_back(dir); + + postCommand(&c); + + while(!c.done) { doEvents(); } + + bool oke = c.js_result_ok; + + rkt_js_result_t *r = static_cast(malloc(sizeof(rkt_js_result_t))); + r->result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed; + + r->value = strdup(c.result.toString().toUtf8()); + + return r; +} + result_t Rktwebview_qt::rktWindowSetTitle(rktwebview_t wv, const char *title) { Command c(COMMAND_SET_TITLE); diff --git a/rktwebview_qt/rktwebview_qt.h b/rktwebview_qt/rktwebview_qt.h index 398c4e7..0f7c4b0 100644 --- a/rktwebview_qt/rktwebview_qt.h +++ b/rktwebview_qt/rktwebview_qt.h @@ -84,6 +84,8 @@ public: result_t rktShowNormalWindow(rktwebview_t w); window_state_t rktWindowState(rktwebview_t w); + rkt_js_result_t *rktChooseDir(rktwebview_t w, const char *title, const char *base_dir); + result_t rktWindowSetTitle(rktwebview_t wv, const char *title); bool rktValid(rktwebview_t wv); diff --git a/rktwebview_qt/webviewwindow.cpp b/rktwebview_qt/webviewwindow.cpp index 62cbc35..93700af 100644 --- a/rktwebview_qt/webviewwindow.cpp +++ b/rktwebview_qt/webviewwindow.cpp @@ -11,20 +11,27 @@ #include #include #include +#include -WebviewWindow::WebviewWindow(QWidget *parent) +WebviewWindow::WebviewWindow(WebviewWindow *parent) : QMainWindow{parent} { _view = nullptr; _must_close = false; _devtools = nullptr; + _parent = parent; _window_created = false; _moved = 0; _resized = 0; + if (parent != nullptr) { + setWindowModality(Qt::WindowModality::WindowModal); + setWindowFlag(Qt::WindowType::Dialog, true); + } + connect(&_resize_timer, &QTimer::timeout, this, &WebviewWindow::triggerResize); connect(&_move_timer, &QTimer::timeout, this, &WebviewWindow::triggerMove); } @@ -227,6 +234,7 @@ void WebviewWindow::triggerResize() void WebviewWindow::showEvent(QShowEvent *event) { _window_created = true; + EventContainer show("show"); _container->triggerEvent(_view->id(), show); } diff --git a/rktwebview_qt/webviewwindow.h b/rktwebview_qt/webviewwindow.h index e6cf997..d03628e 100644 --- a/rktwebview_qt/webviewwindow.h +++ b/rktwebview_qt/webviewwindow.h @@ -15,6 +15,7 @@ private: Rktwebview_qt *_container; WebViewQt *_view; QMainWindow *_devtools; + WebviewWindow *_parent; QTimer _resize_timer; QTimer _move_timer; @@ -51,7 +52,7 @@ public: void openDevTools(); public: - explicit WebviewWindow(QWidget *parent = nullptr); + explicit WebviewWindow(WebviewWindow *parent = nullptr); private slots: void triggerResize();