-
This commit is contained in:
@@ -1 +0,0 @@
|
||||
QtWebEngineProcess
|
||||
BIN
private/lib/linux/x86_64/librktwebview.so
Executable file
BIN
private/lib/linux/x86_64/librktwebview.so
Executable file
Binary file not shown.
Binary file not shown.
BIN
private/lib/linux/x86_64/rktwebview_prg
Executable file
BIN
private/lib/linux/x86_64/rktwebview_prg
Executable file
Binary file not shown.
@@ -60,6 +60,7 @@
|
||||
|
||||
(define-runtime-path lib-dir "lib")
|
||||
|
||||
#|
|
||||
(define libraries-to-preload
|
||||
(cond
|
||||
([eq? os 'windows]
|
||||
@@ -105,11 +106,12 @@
|
||||
))
|
||||
)
|
||||
)
|
||||
|#
|
||||
|
||||
(define ffi-library
|
||||
(cond
|
||||
([eq? os 'windows] 'rktwebview_qt.dll)
|
||||
([eq? os 'linux] 'librktwebview_qt.so)
|
||||
([eq? os 'windows] 'rktwebview.dll)
|
||||
([eq? os 'linux] 'librktwebview.so)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -121,16 +123,26 @@
|
||||
; c:\qt\6.10.2\msvc2022_64\bin\windeployqt.exe rktwebview_qt_test.exe
|
||||
(define quiet-call #t)
|
||||
|
||||
(define rktwebview-prg (if (eq? os 'windows)
|
||||
"rktwebview_prg.exe"
|
||||
"rktwebview_prg"))
|
||||
|
||||
(define webengine-process (if (eq? os 'windows)
|
||||
"QtWebEngineProcess.exe"
|
||||
"QtWebEngineProcess"))
|
||||
|
||||
(set! quiet-call
|
||||
(when (or (eq? os 'windows) (eq? os 'linux))
|
||||
(putenv "QT_PLUGIN_PATH"
|
||||
(path->string (build-path os-lib-dir)))
|
||||
(putenv "QTWEBENGINEPROCESS_PATH"
|
||||
(path->string (build-path os-lib-dir "QtWebEngineProcess.exe")))
|
||||
(path->string (build-path os-lib-dir webengine-process)))
|
||||
(putenv "QTWEBENGINE_RESOURCES_PATH"
|
||||
(path->string (build-path os-lib-dir "resources")))
|
||||
(putenv "QTWEBENGINE_LOCALES_PATH"
|
||||
(path->string (build-path os-lib-dir "translations" "qtwebengine_locales")))
|
||||
(putenv "RKT_WEBVIEW_PRG"
|
||||
(path->string (build-path os-lib-dir rktwebview-prg)))
|
||||
(when (eq? os 'linux)
|
||||
(putenv "QT_QPA_PLATFORM" "xcb")
|
||||
(putenv "LD_LIBRARY_PATH"
|
||||
@@ -145,6 +157,7 @@
|
||||
|
||||
;;; Preload libraries
|
||||
|
||||
#|
|
||||
(for-each (λ (lib-symbol)
|
||||
(let* ((libn (if (list? lib-symbol) (car lib-symbol) lib-symbol))
|
||||
(versions (if (list? lib-symbol) (cons (cadr lib-symbol) '(#f)) (list #f)))
|
||||
@@ -160,6 +173,7 @@
|
||||
)
|
||||
)
|
||||
libraries-to-preload)
|
||||
|#
|
||||
|
||||
;;; Actual FFI integration
|
||||
|
||||
@@ -192,9 +206,9 @@
|
||||
|
||||
;;; Callbacks from the OS library
|
||||
|
||||
(define callback-box (box '()))
|
||||
(define (applier thunk)
|
||||
(thunk))
|
||||
;(define callback-box (box '()))
|
||||
;(define (applier thunk)
|
||||
; (thunk))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Types / Functions
|
||||
@@ -279,14 +293,23 @@
|
||||
(define-rktwebview rkt_webview_cleanup
|
||||
(_fun -> _void))
|
||||
|
||||
|
||||
;RKTWEBVIEW_EXPORT int rkt_webview_events_waiting();
|
||||
(define-rktwebview rkt_webview_events_waiting
|
||||
(_fun -> _int))
|
||||
|
||||
;RKTWEBVIEW_EXPORT rkt_data_t *rkt_webview_get_event();
|
||||
(define-rktwebview rkt_webview_get_event
|
||||
(_fun -> _rkt_data_t-pointer/null))
|
||||
|
||||
;RKTWEBVIEW_QT_EXPORT rkt_wv_context_t rkt_webview_new_context(const char *boilerplate_js,
|
||||
; const char *optional_server_cert_pem);
|
||||
(define-rktwebview rkt_webview_new_context
|
||||
(_fun _string/utf-8 _bytes -> _int))
|
||||
|
||||
;RKTWEBVIEW_QT_EXPORT void rkt_webview_process_events(int for_ms);
|
||||
(define-rktwebview rkt_webview_process_events
|
||||
(_fun _int -> _void))
|
||||
;(define-rktwebview rkt_webview_process_events
|
||||
; (_fun _int -> _void))
|
||||
|
||||
;RKTWEBVIEW_QT_EXPORT void rkt_webview_free_data(rkt_data_t *d);
|
||||
(define-rktwebview rkt_webview_free_data
|
||||
@@ -297,13 +320,9 @@
|
||||
(_fun -> _rkt_data_t-pointer))
|
||||
|
||||
; RKTWEBVIEW_QT_EXPORT int rkt_webview_create(rkt_wv_context_t context,
|
||||
; rktwebview_t parent,
|
||||
; event_cb_t js_event_cb);
|
||||
; rktwebview_t parent)
|
||||
(define-rktwebview rkt_webview_create
|
||||
(_fun _int _int
|
||||
(_fun #:keep callback-box #:async-apply applier
|
||||
_rkt_data_t-pointer -> _void)
|
||||
-> _int))
|
||||
(_fun _int _int -> _int))
|
||||
|
||||
;RKTWEBVIEW_QT_EXPORT void rkt_webview_close(int wv);
|
||||
(define-rktwebview rkt_webview_close
|
||||
@@ -403,28 +422,72 @@
|
||||
;; Initialize and start library
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define process-events 'process)
|
||||
;(define process-events 'process)
|
||||
|
||||
(define (stop-event-processing)
|
||||
(set! process-events 'stop)
|
||||
(while (eq? process-events 'stop)
|
||||
(sleep 0.001)))
|
||||
;(define (stop-event-processing)
|
||||
; (set! process-events 'stop)
|
||||
; (while (eq? process-events 'stop)
|
||||
; (sleep 0.001)))
|
||||
|
||||
;(define (start-event-processing)
|
||||
; (thread (λ ()
|
||||
; (letrec ((f (λ ()
|
||||
; (rkt_webview_process_events 1)
|
||||
; (sleep 0.001)
|
||||
; (if (eq? process-events 'process)
|
||||
; (f)
|
||||
; (begin
|
||||
; (displayln "Stopping event processing")
|
||||
; (set! process-events 'stopped)
|
||||
; 'done)))))
|
||||
; (f)))))
|
||||
|
||||
(rkt_webview_init)
|
||||
|
||||
|
||||
;(set! quiet-call (start-event-processing))
|
||||
(define evt-cb-hash (make-hash))
|
||||
|
||||
(define (start-event-processing)
|
||||
(thread (λ ()
|
||||
(letrec ((f (λ ()
|
||||
(rkt_webview_process_events 1)
|
||||
(let ((waiting (rkt_webview_events_waiting)))
|
||||
;(displayln (format "Events waiting: ~a" waiting))
|
||||
(while (> waiting 0)
|
||||
(let* ((rkt-evt (rkt_webview_get_event)))
|
||||
;(displayln rkt-evt)
|
||||
(if (eq? rkt-evt #f)
|
||||
(displayln (format "Unexpected: event = nullptr"))
|
||||
(let ((data (rkt_data_t-data rkt-evt)))
|
||||
;(displayln data)
|
||||
(let ((e (union-ref data 1)))
|
||||
; (displayln e)
|
||||
(let ((wv (rkt_evt_t-w e)))
|
||||
;(displayln wv)
|
||||
(let ((evt (cast (rkt_evt_t-evt e) _pointer _string*/utf-8)))
|
||||
; (displayln evt)
|
||||
(rkt_webview_free_data rkt-evt)
|
||||
(let ((cb (hash-ref evt-cb-hash wv #f)))
|
||||
(unless (eq? cb #f)
|
||||
(cb evt)))))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(set! waiting (- waiting 1))
|
||||
)
|
||||
)
|
||||
(sleep 0.001)
|
||||
(if (eq? process-events 'process)
|
||||
(f)
|
||||
(begin
|
||||
(displayln "Stopping event processing")
|
||||
(set! process-events 'stopped)
|
||||
'done)))))
|
||||
(f)))))
|
||||
(f))
|
||||
))
|
||||
(f)))
|
||||
)
|
||||
)
|
||||
|
||||
(rkt_webview_init)
|
||||
(set! quiet-call (start-event-processing))
|
||||
(define evt-processing-thread (start-event-processing))
|
||||
|
||||
(define (stop-event-processing)
|
||||
(kill-thread evt-processing-thread))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Provided features
|
||||
@@ -459,18 +522,18 @@
|
||||
(define (rkt-webview-new-context boilerplate-js server-cert)
|
||||
(rkt_webview_new_context boilerplate-js server-cert))
|
||||
|
||||
|
||||
(define (rkt-webview-create context parent evt-callback close-callback)
|
||||
(let* ((evt-queue (make-queue))
|
||||
(parent-win (if (eq? parent #f) 0 (rkt-wv-win parent)))
|
||||
)
|
||||
(let ((wv (rkt_webview_create context parent-win
|
||||
(λ (rkt-evt)
|
||||
(let* ((e (union-ref (rkt_data_t-data rkt-evt) 1))
|
||||
(evt (cast (rkt_evt_t-evt e) _pointer _string*/utf-8)))
|
||||
(rkt_webview_free_data rkt-evt) ; Free event data ASAP
|
||||
(enqueue! evt-queue evt)
|
||||
)))))
|
||||
(let ((wv (rkt_webview_create context parent-win)))
|
||||
(hash-set! evt-cb-hash wv (λ (evt) (enqueue! evt-queue evt)))
|
||||
; (λ (rkt-evt)
|
||||
; (let* ((e (union-ref (rkt_data_t-data rkt-evt) 1))
|
||||
; (evt (cast (rkt_evt_t-evt e) _pointer _string*/utf-8)))
|
||||
; (rkt_webview_free_data rkt-evt) ; Free event data ASAP
|
||||
; (enqueue! evt-queue evt)
|
||||
; )))))
|
||||
(let ((handle (make-rkt-wv wv evt-queue evt-callback #t close-callback)))
|
||||
(thread (λ ()
|
||||
(sleep 1)
|
||||
@@ -492,6 +555,7 @@
|
||||
(define (rkt-webview-close handle)
|
||||
(rkt_webview_close (rkt-wv-win handle))
|
||||
(enqueue! (rkt-wv-evt-queue handle) 'quit)
|
||||
(hash-remove! evt-cb-hash (rkt-wv-win handle))
|
||||
((rkt-wv-close-callback handle))
|
||||
#t)
|
||||
|
||||
@@ -608,8 +672,8 @@
|
||||
(handle (cdr kv)))
|
||||
(rkt-webview-close handle)))
|
||||
open-windows))
|
||||
(stop-event-processing)
|
||||
(rkt_webview_cleanup)
|
||||
(stop-event-processing)
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@@ -655,6 +655,7 @@
|
||||
(define (webview-call-js wv js)
|
||||
(-> wv-win? string? (or/c string? list? boolean? hash?))
|
||||
(let ((result (rkt-webview-call-js (wv-win-handle wv) js)))
|
||||
(displayln result)
|
||||
(if (webview-call-js-result? result)
|
||||
(if (eq? (car result) 'oke)
|
||||
(hash-ref (fromJson (cadr result)) 'result #f)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(rktwebview_qt LANGUAGES CXX)
|
||||
project(rktwebview LANGUAGES CXX)
|
||||
|
||||
set(QT_DEBUG_FIND_PACKAGE ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
@@ -12,14 +12,24 @@ 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
|
||||
add_library(rktwebview SHARED
|
||||
rktwebview_global.h
|
||||
rktwebview.h
|
||||
rktwebview.cpp
|
||||
shm.h shm.cpp
|
||||
shmqueue.h shmqueue.cpp
|
||||
rkt_protocol.h
|
||||
rktwebview_types.h
|
||||
json.cpp json.h
|
||||
)
|
||||
|
||||
add_executable(rktwebview_prg
|
||||
main.cpp
|
||||
|
||||
rktwebview_qt.cpp
|
||||
rktwebview_qt.h
|
||||
|
||||
webviewqt.h webviewqt.cpp
|
||||
rktwebview_internal.h
|
||||
webviewwindow.h webviewwindow.cpp
|
||||
|
||||
rktutils.h rktutils.cpp
|
||||
@@ -27,19 +37,18 @@ add_library(rktwebview_qt SHARED
|
||||
shm.h shm.cpp
|
||||
shmqueue.h shmqueue.cpp
|
||||
|
||||
rkt_protocol.h
|
||||
rktwebview_types.h
|
||||
)
|
||||
|
||||
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
|
||||
add_executable(rktwebview_test
|
||||
rktwebview_test.cpp
|
||||
)
|
||||
|
||||
target_compile_definitions(rktwebview_qt_test PRIVATE RKTWEBVIEW_QT_LIBRARY)
|
||||
target_link_libraries(rktwebview_prg PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
target_link_libraries(rktwebview_prg PRIVATE Qt${QT_VERSION_MAJOR}::WebEngineWidgets)
|
||||
|
||||
target_compile_definitions(rktwebview PRIVATE RKTWEBVIEW_LIBRARY)
|
||||
|
||||
target_link_Libraries(rktwebview_test PRIVATE rktwebview)
|
||||
|
||||
target_link_libraries(rktwebview_qt_test PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
target_link_libraries(rktwebview_qt_test PRIVATE Qt${QT_VERSION_MAJOR}::WebEngineWidgets)
|
||||
target_link_libraries(rktwebview_qt_test PRIVATE rktwebview_qt)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define COMMAND_FILE_OPEN 20
|
||||
#define COMMAND_FILE_SAVE 21
|
||||
#define COMMAND_SET_OU_TOKEN 22
|
||||
#define COMMAND_NEW_CONTEXT 23
|
||||
|
||||
class Command
|
||||
{
|
||||
|
||||
@@ -7,14 +7,15 @@ LIB="../private/lib/linux/$ARCH"
|
||||
mkdir -p $LIB
|
||||
rm -f $LIB/*.so*
|
||||
cp build/Release/*.so $LIB
|
||||
cp build/Release/rktwebview_prg $LIB
|
||||
|
||||
QT_PATH=`ldd build/Release/*.so | grep Qt | awk '{print $3}' | head -1 | sed -e 's%[/]lib[/].*%%'`
|
||||
QT_PATH=`ldd build/Release/rktwebview_prg | grep Qt | awk '{print $3}' | head -1 | sed -e 's%[/]lib[/].*%%'`
|
||||
echo "QT_PATH=$QT_PATH"
|
||||
|
||||
QT_PLUGINS="$QT_PATH/plugins"
|
||||
PLUGINS="platforms position generic iconengines imageformats qmltooling tls xcbglintegrations"
|
||||
|
||||
EXTRA_LIBS_SO=`ldd build/Release/*.so | grep Qt | awk '{ print $3 }'`
|
||||
EXTRA_LIBS_SO=`ldd build/Release/rktwebview_prg | grep Qt | awk '{ print $3 }'`
|
||||
EXTRA_LIBS_PLATFORM_PLUGIN_XCB=`ldd $QT_PATH/plugins/platforms/libqxcb.so | grep Qt | awk '{print $3}'`
|
||||
|
||||
for pl in $PLUGINS
|
||||
|
||||
505
rktwebview_qt/json.cpp
Normal file
505
rktwebview_qt/json.cpp
Normal file
@@ -0,0 +1,505 @@
|
||||
#include "json.h"
|
||||
|
||||
using std::map;
|
||||
using std::deque;
|
||||
using std::string;
|
||||
using std::enable_if;
|
||||
using std::initializer_list;
|
||||
using std::is_same;
|
||||
using std::is_convertible;
|
||||
using std::is_integral;
|
||||
using std::is_floating_point;
|
||||
|
||||
std::string json_escape(const string &str) {
|
||||
string output;
|
||||
for( unsigned i = 0; i < str.length(); ++i )
|
||||
switch( str[i] ) {
|
||||
case '\"': output += "\\\""; break;
|
||||
case '\\': output += "\\\\"; break;
|
||||
case '\b': output += "\\b"; break;
|
||||
case '\f': output += "\\f"; break;
|
||||
case '\n': output += "\\n"; break;
|
||||
case '\r': output += "\\r"; break;
|
||||
case '\t': output += "\\t"; break;
|
||||
default : output += str[i]; break;
|
||||
}
|
||||
return std::move( output );
|
||||
}
|
||||
|
||||
JSON::JSON() : Internal(), Type( Class::Null ){}
|
||||
|
||||
JSON::JSON(std::initializer_list<JSON> list)
|
||||
: JSON()
|
||||
{
|
||||
SetType( Class::Object );
|
||||
for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i )
|
||||
operator[]( i->toString() ) = *std::next( i );
|
||||
}
|
||||
|
||||
JSON::JSON(JSON &&other)
|
||||
: Internal( other.Internal )
|
||||
, Type( other.Type )
|
||||
{ other.Type = Class::Null; other.Internal.Map = nullptr; }
|
||||
|
||||
JSON::JSON(const JSON &other) {
|
||||
switch( other.Type ) {
|
||||
case Class::Object:
|
||||
Internal.Map =
|
||||
new map<string,JSON>( other.Internal.Map->begin(),
|
||||
other.Internal.Map->end() );
|
||||
break;
|
||||
case Class::Array:
|
||||
Internal.List =
|
||||
new deque<JSON>( other.Internal.List->begin(),
|
||||
other.Internal.List->end() );
|
||||
break;
|
||||
case Class::String:
|
||||
Internal.String =
|
||||
new string( *other.Internal.String );
|
||||
break;
|
||||
default:
|
||||
Internal = other.Internal;
|
||||
}
|
||||
Type = other.Type;
|
||||
}
|
||||
|
||||
JSON JSON::Make(Class type) {
|
||||
JSON ret; ret.SetType( type );
|
||||
return ret;
|
||||
}
|
||||
|
||||
JSON &JSON::operator[](unsigned int index) {
|
||||
SetType( Class::Array );
|
||||
if( index >= Internal.List->size() ) Internal.List->resize( index + 1 );
|
||||
return Internal.List->operator[]( index );
|
||||
}
|
||||
|
||||
JSON &JSON::at(const std::string &key) {
|
||||
return operator[]( key );
|
||||
}
|
||||
|
||||
const JSON &JSON::at(const std::string &key) const {
|
||||
return Internal.Map->at( key );
|
||||
}
|
||||
|
||||
JSON &JSON::at(unsigned int index) {
|
||||
return operator[]( index );
|
||||
}
|
||||
|
||||
const JSON &JSON::at(unsigned int index) const {
|
||||
return Internal.List->at( index );
|
||||
}
|
||||
|
||||
int JSON::length() const {
|
||||
if( Type == Class::Array )
|
||||
return Internal.List->size();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool JSON::hasKey(const std::string &key) const {
|
||||
if( Type == Class::Object )
|
||||
return Internal.Map->find( key ) != Internal.Map->end();
|
||||
return false;
|
||||
}
|
||||
|
||||
int JSON::size() const {
|
||||
if( Type == Class::Object )
|
||||
return Internal.Map->size();
|
||||
else if( Type == Class::Array )
|
||||
return Internal.List->size();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
JSON::Class JSON::JSONType() const { return Type; }
|
||||
|
||||
bool JSON::IsNull() const { return Type == Class::Null; }
|
||||
|
||||
string JSON::toString() const { bool b; return std::move( toString( b ) ); }
|
||||
|
||||
string JSON::toString(bool &ok) const {
|
||||
ok = (Type == Class::String);
|
||||
return ok ? std::move( json_escape( *Internal.String ) ): string("");
|
||||
}
|
||||
|
||||
double JSON::toFloat() const { bool b; return toFloat( b ); }
|
||||
|
||||
double JSON::toFloat(bool &ok) const {
|
||||
ok = (Type == Class::Floating);
|
||||
return ok ? Internal.Float : 0.0;
|
||||
}
|
||||
|
||||
long JSON::toInt() const { bool b; return toInt( b ); }
|
||||
|
||||
long JSON::toInt(bool &ok) const {
|
||||
ok = (Type == Class::Integral);
|
||||
return ok ? Internal.Int : 0;
|
||||
}
|
||||
|
||||
bool JSON::toBool() const { bool b; return toBool( b ); }
|
||||
|
||||
bool JSON::toBool(bool &ok) const {
|
||||
ok = (Type == Class::Boolean);
|
||||
return ok ? Internal.Bool : false;
|
||||
}
|
||||
|
||||
JSON::JSONWrapper<std::map<string, JSON> > JSON::ObjectRange() {
|
||||
if( Type == Class::Object )
|
||||
return JSONWrapper<std::map<std::string,JSON>>( Internal.Map );
|
||||
return JSONWrapper<std::map<std::string,JSON>>( nullptr );
|
||||
}
|
||||
|
||||
JSON::JSONWrapper<std::deque<JSON> > JSON::ArrayRange() {
|
||||
if( Type == Class::Array )
|
||||
return JSONWrapper<std::deque<JSON>>( Internal.List );
|
||||
return JSONWrapper<std::deque<JSON>>( nullptr );
|
||||
}
|
||||
|
||||
JSON::JSONConstWrapper<std::map<string, JSON> > JSON::ObjectRange() const {
|
||||
if( Type == Class::Object )
|
||||
return JSONConstWrapper<std::map<std::string,JSON>>( Internal.Map );
|
||||
return JSONConstWrapper<std::map<std::string,JSON>>( nullptr );
|
||||
}
|
||||
|
||||
JSON::JSONConstWrapper<std::deque<JSON> > JSON::ArrayRange() const {
|
||||
if( Type == Class::Array )
|
||||
return JSONConstWrapper<std::deque<JSON>>( Internal.List );
|
||||
return JSONConstWrapper<std::deque<JSON>>( nullptr );
|
||||
}
|
||||
|
||||
string JSON::dump(int depth, const std::string &tab) const {
|
||||
std::string pad = "";
|
||||
for( int i = 0; i < depth; ++i, pad += tab );
|
||||
|
||||
switch( Type ) {
|
||||
case Class::Null:
|
||||
return "null";
|
||||
case Class::Object: {
|
||||
std::string s = "{ ";
|
||||
bool skip = true;
|
||||
for( auto &p : *Internal.Map ) {
|
||||
if( !skip ) s += ", ";
|
||||
s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
|
||||
skip = false;
|
||||
}
|
||||
s += ( " " + pad.erase( 0, 2 ) + "}" ) ;
|
||||
return s;
|
||||
}
|
||||
case Class::Array: {
|
||||
std::string s = "[";
|
||||
bool skip = true;
|
||||
for( auto &p : *Internal.List ) {
|
||||
if( !skip ) s += ", ";
|
||||
s += p.dump( depth + 1, tab );
|
||||
skip = false;
|
||||
}
|
||||
s += "]";
|
||||
return s;
|
||||
}
|
||||
case Class::String:
|
||||
return "\"" + json_escape( *Internal.String ) + "\"";
|
||||
case Class::Floating:
|
||||
return std::to_string( Internal.Float );
|
||||
case Class::Integral:
|
||||
return std::to_string( Internal.Int );
|
||||
case Class::Boolean:
|
||||
return Internal.Bool ? "true" : "false";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void JSON::SetType(Class type) {
|
||||
if( type == Type )
|
||||
return;
|
||||
|
||||
ClearInternal();
|
||||
|
||||
switch( type ) {
|
||||
case Class::Null: Internal.Map = nullptr; break;
|
||||
case Class::Object: Internal.Map = new std::map<std::string,JSON>(); break;
|
||||
case Class::Array: Internal.List = new std::deque<JSON>(); break;
|
||||
case Class::String: Internal.String = new std::string(); break;
|
||||
case Class::Floating: Internal.Float = 0.0; break;
|
||||
case Class::Integral: Internal.Int = 0; break;
|
||||
case Class::Boolean: Internal.Bool = false; break;
|
||||
}
|
||||
|
||||
Type = type;
|
||||
}
|
||||
|
||||
void JSON::ClearInternal() {
|
||||
switch( Type ) {
|
||||
case Class::Object: delete Internal.Map; break;
|
||||
case Class::Array: delete Internal.List; break;
|
||||
case Class::String: delete Internal.String; break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
JSON &JSON::operator[](const std::string &key) {
|
||||
SetType( Class::Object ); return Internal.Map->operator[]( key );
|
||||
}
|
||||
|
||||
JSON &JSON::operator=(const JSON &other) {
|
||||
|
||||
if (&other == this) { return *this; }
|
||||
|
||||
ClearInternal();
|
||||
switch( other.Type ) {
|
||||
case Class::Object:
|
||||
Internal.Map =
|
||||
new map<string,JSON>( other.Internal.Map->begin(),
|
||||
other.Internal.Map->end() );
|
||||
break;
|
||||
case Class::Array:
|
||||
Internal.List =
|
||||
new deque<JSON>( other.Internal.List->begin(),
|
||||
other.Internal.List->end() );
|
||||
break;
|
||||
case Class::String:
|
||||
Internal.String =
|
||||
new string( *other.Internal.String );
|
||||
break;
|
||||
default:
|
||||
Internal = other.Internal;
|
||||
}
|
||||
Type = other.Type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
JSON &JSON::operator=(JSON &&other) {
|
||||
ClearInternal();
|
||||
Internal = other.Internal;
|
||||
Type = other.Type;
|
||||
other.Internal.Map = nullptr;
|
||||
other.Type = Class::Null;
|
||||
return *this;
|
||||
}
|
||||
|
||||
JSON Array() {
|
||||
return std::move( JSON::Make( JSON::Class::Array ) );
|
||||
}
|
||||
|
||||
//JSON Object() { return std::move(JSON::Make(JSON::Class::Object)); }
|
||||
|
||||
JSON Object() {
|
||||
return std::move( JSON::Make( JSON::Class::Object ) );
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const JSON &json) {
|
||||
os << json.dump();
|
||||
return os;
|
||||
}
|
||||
|
||||
// Private functions.
|
||||
|
||||
static JSON parse_next( const std::string &, size_t &, std::function<void(const std::string &err)> );
|
||||
|
||||
|
||||
static void consume_ws( const std::string &str, size_t &offset ) {
|
||||
while( isspace( str[offset] ) ) ++offset;
|
||||
}
|
||||
|
||||
static JSON parse_object( const string &str, size_t &offset, std::function<void(const std::string &err)> on_error ) {
|
||||
JSON Object = JSON::Make( JSON::Class::Object );
|
||||
|
||||
++offset;
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] == '}' ) {
|
||||
++offset; return std::move( Object );
|
||||
}
|
||||
|
||||
while( true ) {
|
||||
JSON Key = parse_next( str, offset, on_error );
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] != ':' ) {
|
||||
on_error(std::string("Error: Object: Expected colon, found '") + str[offset] + "'");
|
||||
break;
|
||||
}
|
||||
consume_ws( str, ++offset );
|
||||
JSON Value = parse_next( str, offset, on_error );
|
||||
Object[Key.toString()] = Value;
|
||||
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] == ',' ) {
|
||||
++offset; continue;
|
||||
}
|
||||
else if( str[offset] == '}' ) {
|
||||
++offset; break;
|
||||
}
|
||||
else {
|
||||
on_error(std::string("ERROR: Object: Expected comma, found '") + str[offset] + "'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return std::move( Object );
|
||||
}
|
||||
|
||||
static JSON parse_array( const string &str, size_t &offset, std::function<void(const std::string &err)> on_error ) {
|
||||
JSON Array = JSON::Make( JSON::Class::Array );
|
||||
unsigned index = 0;
|
||||
|
||||
++offset;
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] == ']' ) {
|
||||
++offset; return std::move( Array );
|
||||
}
|
||||
|
||||
while( true ) {
|
||||
Array[index++] = parse_next( str, offset, on_error );
|
||||
consume_ws( str, offset );
|
||||
|
||||
if( str[offset] == ',' ) {
|
||||
++offset; continue;
|
||||
}
|
||||
else if( str[offset] == ']' ) {
|
||||
++offset; break;
|
||||
}
|
||||
else {
|
||||
on_error(std::string("ERROR: Array: Expected ',' or ']', found '") + str[offset] + "'");
|
||||
return std::move( JSON::Make( JSON::Class::Array ) );
|
||||
}
|
||||
}
|
||||
|
||||
return std::move( Array );
|
||||
}
|
||||
|
||||
static JSON parse_string( const string &str, size_t &offset, std::function<void(const std::string &err)> on_error ) {
|
||||
JSON String;
|
||||
string val;
|
||||
for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) {
|
||||
if( c == '\\' ) {
|
||||
switch( str[ ++offset ] ) {
|
||||
case '\"': val += '\"'; break;
|
||||
case '\\': val += '\\'; break;
|
||||
case '/' : val += '/' ; break;
|
||||
case 'b' : val += '\b'; break;
|
||||
case 'f' : val += '\f'; break;
|
||||
case 'n' : val += '\n'; break;
|
||||
case 'r' : val += '\r'; break;
|
||||
case 't' : val += '\t'; break;
|
||||
case 'u' : {
|
||||
val += "\\u" ;
|
||||
for( unsigned i = 1; i <= 4; ++i ) {
|
||||
c = str[offset+i];
|
||||
if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
|
||||
val += c;
|
||||
else {
|
||||
on_error(std::string("ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
|
||||
return std::move( JSON::Make( JSON::Class::String ) );
|
||||
}
|
||||
}
|
||||
offset += 4;
|
||||
} break;
|
||||
default : val += '\\'; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
val += c;
|
||||
}
|
||||
++offset;
|
||||
String = val;
|
||||
return std::move( String );
|
||||
}
|
||||
|
||||
static JSON parse_number( const string &str, size_t &offset, std::function<void(const std::string &err)> on_error ) {
|
||||
JSON Number;
|
||||
string val, exp_str;
|
||||
char c;
|
||||
bool isDouble = false;
|
||||
long exp = 0;
|
||||
while( true ) {
|
||||
c = str[offset++];
|
||||
if( (c == '-') || (c >= '0' && c <= '9') )
|
||||
val += c;
|
||||
else if( c == '.' ) {
|
||||
val += c;
|
||||
isDouble = true;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if( c == 'E' || c == 'e' ) {
|
||||
c = str[ offset++ ];
|
||||
if( c == '-' ){ ++offset; exp_str += '-';}
|
||||
while( true ) {
|
||||
c = str[ offset++ ];
|
||||
if( c >= '0' && c <= '9' )
|
||||
exp_str += c;
|
||||
else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
|
||||
on_error(std::string("ERROR: Number: Expected a number for exponent, found '") + c + "'");
|
||||
return std::move( JSON::Make( JSON::Class::Null ) );
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
exp = std::stol( exp_str );
|
||||
}
|
||||
else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
|
||||
on_error(std::string("ERROR: Number: unexpected character '") + c + "'");
|
||||
return std::move( JSON::Make( JSON::Class::Null ) );
|
||||
}
|
||||
--offset;
|
||||
|
||||
if( isDouble )
|
||||
Number = std::stod( val ) * std::pow( 10, exp );
|
||||
else {
|
||||
if( !exp_str.empty() )
|
||||
Number = std::stol( val ) * std::pow( 10, exp );
|
||||
else
|
||||
Number = std::stol( val );
|
||||
}
|
||||
return std::move( Number );
|
||||
}
|
||||
|
||||
static JSON parse_bool( const string &str, size_t &offset, std::function<void(const std::string &err)> on_error ) {
|
||||
JSON Bool;
|
||||
if( str.substr( offset, 4 ) == "true" )
|
||||
Bool = true;
|
||||
else if( str.substr( offset, 5 ) == "false" )
|
||||
Bool = false;
|
||||
else {
|
||||
on_error(std::string("ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'");
|
||||
return std::move( JSON::Make( JSON::Class::Null ) );
|
||||
}
|
||||
offset += (Bool.toBool() ? 4 : 5);
|
||||
return std::move( Bool );
|
||||
}
|
||||
|
||||
static JSON parse_null( const string &str, size_t &offset, std::function<void(const std::string &err)> on_error ) {
|
||||
JSON Null;
|
||||
if( str.substr( offset, 4 ) != "null" ) {
|
||||
on_error(std::string("ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'" );
|
||||
return std::move( JSON::Make( JSON::Class::Null ) );
|
||||
}
|
||||
offset += 4;
|
||||
return std::move( Null );
|
||||
}
|
||||
|
||||
static JSON parse_next( const string &str, size_t &offset, std::function<void(const std::string &err)> on_error ) {
|
||||
char value;
|
||||
consume_ws( str, offset );
|
||||
value = str[offset];
|
||||
switch( value ) {
|
||||
case '[' : return std::move( parse_array( str, offset, on_error ) );
|
||||
case '{' : return std::move( parse_object( str, offset, on_error ) );
|
||||
case '\"': return std::move( parse_string( str, offset, on_error ) );
|
||||
case 't' :
|
||||
case 'f' : return std::move( parse_bool( str, offset, on_error ) );
|
||||
case 'n' : return std::move( parse_null( str, offset, on_error ) );
|
||||
default : if( ( value <= '9' && value >= '0' ) || value == '-' )
|
||||
return std::move( parse_number( str, offset, on_error ) );
|
||||
}
|
||||
on_error(std::string("ERROR: Parse: Unknown starting character '") + value + "'");
|
||||
return JSON();
|
||||
}
|
||||
|
||||
JSON JSON::Load( const string &str, std::function<void(const std::string &err)> on_error) {
|
||||
size_t offset = 0;
|
||||
return std::move( parse_next( str, offset, on_error ) );
|
||||
}
|
||||
|
||||
217
rktwebview_qt/json.h
Normal file
217
rktwebview_qt/json.h
Normal file
@@ -0,0 +1,217 @@
|
||||
#ifndef JSON_H
|
||||
#define JSON_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <initializer_list>
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
|
||||
std::string json_escape( const std::string &str );
|
||||
|
||||
class JSON
|
||||
{
|
||||
union BackingData {
|
||||
BackingData( double d ) : Float( d ){}
|
||||
BackingData( long l ) : Int( l ){}
|
||||
BackingData( bool b ) : Bool( b ){}
|
||||
BackingData( std::string s ) : String( new std::string( s ) ){}
|
||||
BackingData() : Int( 0 ){}
|
||||
|
||||
std::deque<JSON> *List;
|
||||
std::map<std::string,JSON> *Map;
|
||||
std::string *String;
|
||||
double Float;
|
||||
long Int;
|
||||
bool Bool;
|
||||
} Internal;
|
||||
|
||||
public:
|
||||
enum class Class {
|
||||
Null,
|
||||
Object,
|
||||
Array,
|
||||
String,
|
||||
Floating,
|
||||
Integral,
|
||||
Boolean
|
||||
};
|
||||
|
||||
template <typename Container>
|
||||
class JSONWrapper {
|
||||
Container *object;
|
||||
|
||||
public:
|
||||
JSONWrapper( Container *val ) : object( val ) {}
|
||||
JSONWrapper( std::nullptr_t ) : object( nullptr ) {}
|
||||
|
||||
typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
|
||||
typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
|
||||
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); }
|
||||
typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
|
||||
};
|
||||
|
||||
template <typename Container>
|
||||
class JSONConstWrapper {
|
||||
const Container *object;
|
||||
|
||||
public:
|
||||
JSONConstWrapper( const Container *val ) : object( val ) {}
|
||||
JSONConstWrapper( std::nullptr_t ) : object( nullptr ) {}
|
||||
|
||||
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); }
|
||||
typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); }
|
||||
};
|
||||
|
||||
JSON();
|
||||
JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){}
|
||||
JSON( std::initializer_list<JSON> list );
|
||||
JSON( JSON&& other );
|
||||
JSON( const JSON &other );
|
||||
|
||||
JSON& operator=( const JSON &other );
|
||||
JSON& operator=( JSON&& other );
|
||||
|
||||
// Template T constructors
|
||||
template <typename T>
|
||||
JSON( T b, typename std::enable_if<std::is_same<T,bool>::value>::type* = 0 );
|
||||
|
||||
template <typename T>
|
||||
JSON( T i, typename std::enable_if<std::is_integral<T>::value && !std::is_same<T,bool>::value>::type* = 0 );
|
||||
|
||||
template <typename T>
|
||||
JSON( T f, typename std::enable_if<std::is_floating_point<T>::value>::type* = 0 );
|
||||
|
||||
template <typename T>
|
||||
JSON( T s, typename std::enable_if<std::is_convertible<T, std::string>::value>::type* = 0 );
|
||||
|
||||
~JSON() {
|
||||
switch( Type ) {
|
||||
case Class::Array:
|
||||
delete Internal.List;
|
||||
break;
|
||||
case Class::Object:
|
||||
delete Internal.Map;
|
||||
break;
|
||||
case Class::String:
|
||||
delete Internal.String;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
static JSON Make( Class type );
|
||||
static JSON Load( const std::string &, std::function<void(const std::string &err)> );
|
||||
|
||||
// Appending things.
|
||||
|
||||
template <typename T>
|
||||
void append( T arg ) {
|
||||
SetType( Class::Array ); Internal.List->emplace_back( arg );
|
||||
}
|
||||
|
||||
template <typename T, typename... U>
|
||||
void append( T arg, U... args ) {
|
||||
append( arg ); append( args... );
|
||||
}
|
||||
|
||||
// Assignments (template T).
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_same<T,bool>::value, JSON&>::type operator=( T b ) {
|
||||
SetType( Class::Boolean ); Internal.Bool = b; return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value && !std::is_same<T,bool>::value, JSON&>::type operator=( T i ) {
|
||||
SetType( Class::Integral ); Internal.Int = i; return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, JSON&>::type operator=( T f ) {
|
||||
SetType( Class::Floating ); Internal.Float = f; return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_convertible<T, std::string>::value, JSON&>::type operator=( T s ) {
|
||||
SetType( Class::String ); *Internal.String = std::string( s ); return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Indexing.
|
||||
JSON& operator[]( const std::string &key );
|
||||
JSON& operator[]( unsigned index );
|
||||
|
||||
JSON &at( const std::string &key );
|
||||
const JSON &at( const std::string &key ) const;
|
||||
JSON &at( unsigned index );
|
||||
const JSON &at( unsigned index ) const;
|
||||
|
||||
int length() const;
|
||||
int size() const;
|
||||
|
||||
bool hasKey( const std::string &key ) const;
|
||||
|
||||
Class JSONType() const;
|
||||
|
||||
/// Functions for getting primitives from the JSON object.
|
||||
bool IsNull() const;
|
||||
|
||||
std::string toString() const;
|
||||
std::string toString( bool &ok ) const;
|
||||
|
||||
double toFloat() const;
|
||||
double toFloat( bool &ok ) const;
|
||||
|
||||
long toInt() const;
|
||||
long toInt( bool &ok ) const;
|
||||
|
||||
bool toBool() const;
|
||||
bool toBool( bool &ok ) const;
|
||||
|
||||
JSONWrapper<std::map<std::string,JSON>> ObjectRange();
|
||||
JSONWrapper<std::deque<JSON>> ArrayRange();
|
||||
JSONConstWrapper<std::map<std::string,JSON>> ObjectRange() const;
|
||||
JSONConstWrapper<std::deque<JSON>> ArrayRange() const;
|
||||
|
||||
std::string dump( int depth = 1, const std::string &tab = std::string(" ")) const;
|
||||
|
||||
friend std::ostream& operator<<( std::ostream&, const JSON & );
|
||||
|
||||
private:
|
||||
void SetType( Class type );
|
||||
|
||||
private:
|
||||
/* beware: only call if YOU know that Internal is allocated. No checks performed here.
|
||||
This function should be called in a constructed JSON just before you are going to
|
||||
overwrite Internal...
|
||||
*/
|
||||
void ClearInternal();
|
||||
|
||||
private:
|
||||
|
||||
Class Type = Class::Null;
|
||||
};
|
||||
|
||||
JSON Array();
|
||||
|
||||
template <typename... T>
|
||||
JSON Array( T... args ) {
|
||||
JSON arr = JSON::Make( JSON::Class::Array );
|
||||
arr.append( args... );
|
||||
return std::move( arr );
|
||||
}
|
||||
|
||||
JSON Object();
|
||||
|
||||
std::ostream& operator<<( std::ostream &os, const JSON &json );
|
||||
|
||||
|
||||
#endif // JSON_H
|
||||
@@ -1,94 +1,325 @@
|
||||
#include "rktwebview.h"
|
||||
|
||||
#include <QThread>
|
||||
#include <QFile>
|
||||
#include <QApplication>
|
||||
|
||||
static int _argc;
|
||||
static char **_argv;
|
||||
#include "rkt_protocol.h"
|
||||
#include "shm.h"
|
||||
#include "shmqueue.h"
|
||||
#include "command.h"
|
||||
|
||||
void eventCb(rkt_data_t *e)
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "rktwebview_qt.h"
|
||||
|
||||
static void free_data(rkt_data_t *d)
|
||||
{
|
||||
printf("event: %s\n", e->data.event.event);
|
||||
rkt_webview_free_data(e);
|
||||
if (d->kind == version) {
|
||||
free(d);
|
||||
} else if (d->kind == event) {
|
||||
free(d->data.event.event);
|
||||
free(d);
|
||||
} else if (d->kind == js_result) {
|
||||
free(d->data.js_result.value);
|
||||
free(d);
|
||||
} else {
|
||||
fprintf(stderr, "UNEXPECTED: data kind %d cannot be freed\n", d->kind);
|
||||
}
|
||||
}
|
||||
|
||||
class Handler : public QThread
|
||||
{
|
||||
public:
|
||||
Shm *shm;
|
||||
ShmQueue *command_queue;
|
||||
ShmQueue *result_queue;
|
||||
ShmQueue *event_queue;
|
||||
Rktwebview_qt *webview_handler;
|
||||
|
||||
// QThread interface
|
||||
protected:
|
||||
void run();
|
||||
};
|
||||
|
||||
static Handler *_handler;
|
||||
|
||||
static void event_cb(rkt_data_t *data)
|
||||
{
|
||||
if (data->kind != rkt_data_kind_t::event) {
|
||||
return;
|
||||
}
|
||||
|
||||
int wv = data->data.event.wv;
|
||||
char *evt = data->data.event.event;
|
||||
|
||||
std::string evt_d(evt);
|
||||
_handler->event_queue->enqueue(wv, evt_d);
|
||||
|
||||
free_data(data);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int wv1;
|
||||
int wv2;
|
||||
const char *me = argv[0];
|
||||
|
||||
_argc = argc;
|
||||
_argv = argv;
|
||||
|
||||
int k = 0;
|
||||
while(k < 2) {
|
||||
rkt_webview_init();
|
||||
|
||||
int context = rkt_webview_new_context("console.log('boilerplate!');", nullptr);
|
||||
|
||||
wv1 = rkt_webview_create(context, 0, eventCb);
|
||||
|
||||
rkt_webview_move(wv1, 200, 300);
|
||||
rkt_webview_resize(wv1, 800, 600);
|
||||
rkt_webview_set_url(wv1, "https://wikipedia.org"); //"http://127.0.0.1:8083");
|
||||
|
||||
k += 1;
|
||||
int i = 0;
|
||||
while(i < 10) {
|
||||
printf("Waiting...%d\n", i);
|
||||
rkt_webview_process_events(1000);
|
||||
|
||||
if (i == 6) {
|
||||
rkt_webview_open_devtools(wv1);
|
||||
if (argc < 6) {
|
||||
fprintf(stderr, "%s: wrong number of arguments\n", me);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (i == 3) {
|
||||
rkt_data_t *r = rkt_webview_call_js(wv1, "{ let a = 7 * 6; console.log('a = ' + a); return a; }");
|
||||
printf("rkt_js_result: %d: %s\n", r->data.js_result.result, r->data.js_result.value);
|
||||
rkt_webview_free_data(r);
|
||||
const char *shm_name = argv[1];
|
||||
const char *shm_size_str = argv[2];
|
||||
const char *cmd_slot_str = argv[3];
|
||||
const char *res_slot_str = argv[4];
|
||||
const char *evt_slot_str = argv[5];
|
||||
|
||||
size_t shm_size = atoi(shm_size_str);
|
||||
int cmd_slot = atoi(cmd_slot_str);
|
||||
int res_slot = atoi(res_slot_str);
|
||||
int evt_slot = atoi(evt_slot_str);
|
||||
|
||||
fprintf(stderr, "%s %s %s %s %s %s\n", me, shm_name, shm_size_str, cmd_slot_str, res_slot_str, evt_slot_str);
|
||||
fprintf(stderr, "%s %s %ld %d %d %d\n", me, shm_name, shm_size, cmd_slot, res_slot, evt_slot);
|
||||
|
||||
if (!(shm_size > 0 && cmd_slot > 0 && res_slot > 0 && evt_slot > 0)) {
|
||||
fprintf(stderr, "%s: Invalid shm size or slots\n", me);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (i == 4) {
|
||||
rkt_data_t *r = rkt_webview_call_js(wv1, "let el = document.getElementById('hi');el.value = '10';");
|
||||
printf("rkt_js_result: %d: %s\n", r->data.js_result.result, r->data.js_result.value);
|
||||
rkt_webview_free_data(r);
|
||||
Handler *handler = new Handler();
|
||||
_handler = handler;
|
||||
handler->shm = new Shm(shm_name, shm_size, false);
|
||||
handler->command_queue = new ShmQueue(handler->shm, cmd_slot, false);
|
||||
handler->result_queue = new ShmQueue(handler->shm, res_slot, false);
|
||||
handler->event_queue = new ShmQueue(handler->shm, evt_slot, false);
|
||||
handler->webview_handler = new Rktwebview_qt(argc, argv);
|
||||
handler->start();
|
||||
|
||||
handler->webview_handler->initApp();
|
||||
handler->webview_handler->execApp();
|
||||
|
||||
fprintf(stderr, "waiting for thread to end\n");
|
||||
handler->wait();
|
||||
|
||||
fprintf(stderr, "cleaning up shm\n");
|
||||
|
||||
delete handler->webview_handler;
|
||||
delete handler->command_queue;
|
||||
delete handler->result_queue;
|
||||
delete handler->event_queue;
|
||||
delete handler->shm;
|
||||
delete handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i == 6) {
|
||||
//rkt_data_t *r = rkt_webview_call_js(wv1, "document.body.innerHTML = '<h1>Hi!</h1>'; return document.body.innerHTML;");
|
||||
//printf("rkt_js_result: %d: %s\n", r->data.js_result.result, r->data.js_result.value);
|
||||
//rkt_webview_free_data(r);
|
||||
}
|
||||
void Handler::run()
|
||||
{
|
||||
bool quit = false;
|
||||
while (!quit) {
|
||||
int cmd;
|
||||
std::string data;
|
||||
command_queue->dequeue(cmd, data, true);
|
||||
QJsonObject data_obj = QJsonDocument::fromJson(data.c_str()).object();
|
||||
|
||||
if (i == 7) {
|
||||
result_t r = rkt_webview_message_box(wv1, "This is a title", "This is my message", "This is my submessage", rkt_messagetype_t::yes_no);
|
||||
switch(cmd) {
|
||||
case CMD_QUIT: {
|
||||
fprintf(stderr, "Got quit message\n");
|
||||
webview_handler->rktQuit();
|
||||
fprintf(stderr, "Enqueing RESULT_QUIT to result queue\n");
|
||||
result_queue->enqueue(RESULT_QUIT);
|
||||
quit = true;
|
||||
}
|
||||
break;
|
||||
case CMD_HANDLE_IS_VALID: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
bool oke = webview_handler->rktValid(wv);
|
||||
result_queue->enqueue(oke);
|
||||
}
|
||||
break;
|
||||
case CMD_CONTEXT_NEW: {
|
||||
QString boilerplate_js = data_obj["boilerplate_js"].toString();
|
||||
bool has_pem_cert = data_obj["has_pem_cert"].toBool();
|
||||
QString pem_cert = data_obj["pem_cert"].toString();
|
||||
int context = webview_handler->newContext(boilerplate_js, has_pem_cert, pem_cert);
|
||||
result_queue->enqueue(context);
|
||||
}
|
||||
break;
|
||||
case CMD_CREATE_WV: {
|
||||
int context = data_obj["context"].toInt();
|
||||
int parent = data_obj["parent"].toInt();
|
||||
|
||||
|
||||
if (i == 10) {
|
||||
wv2 = rkt_webview_create(context, wv1, eventCb);
|
||||
rkt_webview_move(wv2, 400, 200);
|
||||
rkt_webview_resize(wv2, 800, 600);
|
||||
rkt_webview_set_url(wv2, "https://127.0.0.1");
|
||||
int wv = webview_handler->rktWebViewCreate(context, parent, event_cb);
|
||||
result_queue->enqueue(wv);
|
||||
}
|
||||
|
||||
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);
|
||||
break;
|
||||
case CMD_CLOSE_WV: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
webview_handler->rktWebViewClose(wv);
|
||||
}
|
||||
|
||||
if (i == 15) {
|
||||
rkt_webview_close(wv2);
|
||||
break;
|
||||
case CMD_SET_URL: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
QString url = data_obj["url"].toString();
|
||||
result_t r = webview_handler->rktSetUrl(wv, url.toUtf8().constData());
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_SET_HTML: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
QString html = data_obj["html"].toString();
|
||||
result_t r = webview_handler->rktSetHtml(wv, html.toUtf8().constData());
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_RUN_JS: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
QString js = data_obj["js"].toString();
|
||||
result_t r = webview_handler->rktRunJs(wv, js);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_CALL_JS: {
|
||||
fprintf(stderr, "Calljs\n");
|
||||
int wv = data_obj["wv"].toInt();
|
||||
QString js = data_obj["js"].toString();
|
||||
rkt_data_t *res = webview_handler->rktCallJs(wv, js.toUtf8().constData());
|
||||
result_queue->enqueue(res->data.js_result.result, res->data.js_result.value);
|
||||
free_data(res);
|
||||
}
|
||||
break;
|
||||
case CMD_OPEN_DEVTOOLS: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
result_t r = webview_handler->rktOpenDevtools(wv);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_MOVE: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
int x = data_obj["x"].toInt();
|
||||
int y = data_obj["y"].toInt();
|
||||
result_t r = webview_handler->rktMove(wv, x, y);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_RESIZE: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
int w = data_obj["w"].toInt();
|
||||
int h = data_obj["h"].toInt();
|
||||
result_t r = webview_handler->rktResize(wv, w, h);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_HIDE: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
result_t r = webview_handler->rktHideWindow(wv);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_SHOW: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
result_t r = webview_handler->rktShowWindow(wv);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_PRESENT: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
result_t r = webview_handler->rktPresentWindow(wv);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_MAXIMIZE: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
result_t r = webview_handler->rktMaximizeWindow(wv);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_MINIMIZE: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
result_t r = webview_handler->rktMinimizeWindow(wv);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_SHOW_NORMAL: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
result_t r = webview_handler->rktShowNormalWindow(wv);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_WINDOW_STATE: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
window_state_t r = webview_handler->rktWindowState(wv);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_SET_TITLE: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
QString title = data_obj["title"].toString();
|
||||
result_t r = webview_handler->rktWindowSetTitle(wv, title.toUtf8().constData());
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_CHOOSE_DIR: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
QString title = data_obj["title"].toString();
|
||||
QString base_dir = data_obj["base_dir"].toString();
|
||||
result_t r = webview_handler->rktChooseDir(wv,
|
||||
title.toUtf8().constData(),
|
||||
base_dir.toUtf8().constData()
|
||||
);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_FILE_OPEN: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
QString title = data_obj["title"].toString();
|
||||
QString base_dir = data_obj["base_dir"].toString();
|
||||
QString permitted_exts = data_obj["permitted_exts"].toString();
|
||||
result_t r = webview_handler->rktFileOpen(wv,
|
||||
title.toUtf8().constData(),
|
||||
base_dir.toUtf8().constData(),
|
||||
permitted_exts.toUtf8().constData()
|
||||
);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_FILE_SAVE: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
QString title = data_obj["title"].toString();
|
||||
QString base_dir = data_obj["base_dir"].toString();
|
||||
QString permitted_exts = data_obj["permitted_exts"].toString();
|
||||
result_t r = webview_handler->rktFileSave(wv,
|
||||
title.toUtf8().constData(),
|
||||
base_dir.toUtf8().constData(),
|
||||
permitted_exts.toUtf8().constData()
|
||||
);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_SET_OU_TOKEN: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
QString token = data_obj["token"].toString();
|
||||
webview_handler->rktSetOUToken(wv, token.toUtf8().constData());
|
||||
}
|
||||
break;
|
||||
case CMD_MSG_BOX: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
QString title = data_obj["title"].toString();
|
||||
QString message = data_obj["message"].toString();
|
||||
QString submsg = data_obj["submessage"].toString();
|
||||
int type = data_obj["type"].toInt();
|
||||
result_t r = webview_handler->rktMessageBox(wv,
|
||||
title.toUtf8().constData(),
|
||||
message.toUtf8().constData(),
|
||||
submsg.toUtf8().constData(),
|
||||
static_cast<rkt_messagetype_t>(type)
|
||||
);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
fprintf(stderr, "Unknown command: %d\n", cmd);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
rkt_webview_close(wv1);
|
||||
rkt_webview_cleanup();
|
||||
}
|
||||
QCoreApplication *app = QApplication::instance();
|
||||
delete app;
|
||||
printf("%p\n", QApplication::instance());
|
||||
}
|
||||
|
||||
33
rktwebview_qt/rkt_protocol.h
Normal file
33
rktwebview_qt/rkt_protocol.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef RKT_PROTOCOL_H
|
||||
#define RKT_PROTOCOL_H
|
||||
|
||||
#define CMD_HANDLE_IS_VALID 1
|
||||
#define CMD_QUIT 2
|
||||
#define CMD_CONTEXT_NEW 3 // arguments: boilerplate_js: string, has_cert: bool, cert_pem: string -> context: int
|
||||
#define CMD_CREATE_WV 4 // arguments: context: int, parent: int -> wv: int
|
||||
#define CMD_CLOSE_WV 5 // arguments: wv: int -> void
|
||||
#define CMD_SET_URL 6 // arguments: wv: int, url: string -> result_t: int
|
||||
#define CMD_SET_HTML 7 // arguments: wv: int, html: string -> result_t: int
|
||||
#define CMD_RUN_JS 8 // arguments: wv: int, js: string -> result_t: int
|
||||
#define CMD_CALL_JS 9 // arguments: wv: int, js: string -> result_t: int
|
||||
#define CMD_OPEN_DEVTOOLS 10 // arguments: wv: int -> result_t: int
|
||||
#define CMD_MOVE 11 // arguments: wv: int, x: int, y: int -> result_t: int
|
||||
#define CMD_RESIZE 12 // arguments: wv: int, w: int, h: int -> result_t: int
|
||||
#define CMD_HIDE 13 // arguments: wv: int -> result_t: int
|
||||
#define CMD_SHOW 14 // arguments: wv: int -> result_t: int
|
||||
#define CMD_PRESENT 15 // arguments: wv: int -> result_t: int
|
||||
#define CMD_MAXIMIZE 16 // arguments: wv: int -> result_t: int
|
||||
#define CMD_MINIMIZE 17 // arguments: wv: int -> result_t: int
|
||||
#define CMD_SHOW_NORMAL 18 // arguments: wv: int -> result_t: int
|
||||
#define CMD_WINDOW_STATE 19 // arguments: wv: int -> window_state_t: int
|
||||
#define CMD_SET_TITLE 20 // arguments: wv: int, title: string -> result_t: int
|
||||
#define CMD_CHOOSE_DIR 21 // arguments: wv: int, title: string, base_dir: string -> result_t: int
|
||||
#define CMD_FILE_OPEN 22 // arguments: wv: int, title: string, base_dir: string, permitted_exts: string -> result_t: int
|
||||
#define CMD_FILE_SAVE 23 // arguments: wv: int, title: string, base_dir: string, permitted_exts: string -> result_t: int
|
||||
#define CMD_SET_OU_TOKEN 24 // arguments: wv: int, token: string -> result_t: int
|
||||
#define CMD_MSG_BOX 25 // arguments: wv: int, title:string, message: string, submessage: string, type:int -> result_t: int
|
||||
|
||||
#define RESULT_QUIT 36379
|
||||
|
||||
|
||||
#endif // RKT_PROTOCOL_H
|
||||
@@ -1,31 +1,85 @@
|
||||
#include "rktwebview_internal.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <chrono>
|
||||
#include <stdint.h>
|
||||
//#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "rktwebview_qt.h"
|
||||
#include "rktwebview.h"
|
||||
#include "rkt_protocol.h"
|
||||
#include <spawn.h>
|
||||
#include "shmqueue.h"
|
||||
#include "json.h"
|
||||
|
||||
#define SHM_SIZE (10 * 1024 * 1024) // 10MB
|
||||
#define COMMAND_SLOT 1
|
||||
#define COMMAND_RESULT_SLOT 2
|
||||
#define EVENT_SLOT 3
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Utility functions
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct {
|
||||
std::string name;
|
||||
size_t shm_size;
|
||||
Shm *shm;
|
||||
ShmQueue *command_queue;
|
||||
ShmQueue *command_result_queue;
|
||||
ShmQueue *event_queue;
|
||||
pid_t rkt_webview_prg_pid;
|
||||
bool rkt_webview_prg_started;
|
||||
} Handle_t;
|
||||
|
||||
Handle_t *handler = nullptr;
|
||||
|
||||
static bool fileExists(const char *filename) {
|
||||
return access(filename, X_OK) != -1;
|
||||
}
|
||||
|
||||
uint64_t current_ms() {
|
||||
using namespace std::chrono;
|
||||
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
bool runRktWebview(Handle_t *handler)
|
||||
{
|
||||
// run rktwebview_prg using the environment variable RKT_WEBVIEW_PRG
|
||||
#ifdef _WIN32
|
||||
#else
|
||||
char *rkt_webview_prg_path = getenv("RKT_WEBVIEW_PRG");
|
||||
if (rkt_webview_prg_path == nullptr) {
|
||||
fprintf(stderr, "RKT_WEBVIEW_PRG environment variable not set, cannot start webview program\n");
|
||||
return false;
|
||||
}
|
||||
if (!fileExists(rkt_webview_prg_path)) {
|
||||
fprintf(stderr, "%s does not exist or is not executable\n", rkt_webview_prg_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
char shm_size_str[30];
|
||||
char command_slot[10];
|
||||
char command_result_slot[10];
|
||||
char event_slot[10];
|
||||
|
||||
sprintf(shm_size_str, "%ld", handler->shm_size);
|
||||
sprintf(command_slot, "%d", COMMAND_SLOT);
|
||||
sprintf(command_result_slot, "%d", COMMAND_RESULT_SLOT);
|
||||
sprintf(event_slot, "%d", EVENT_SLOT);
|
||||
|
||||
char *argv[] = { rkt_webview_prg_path, const_cast<char *>(handler->name.c_str()), shm_size_str, command_slot, command_result_slot, event_slot, nullptr };
|
||||
|
||||
int r = posix_spawn(&handler->rkt_webview_prg_pid, rkt_webview_prg_path, nullptr, nullptr, argv, environ);
|
||||
|
||||
return (r == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Main C Interface
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct {
|
||||
Shm *shm;
|
||||
ShmQueue *command_queue;
|
||||
ShmQueue *event_queue;
|
||||
Rktwebview_qt *rkt;
|
||||
} Handle_t;
|
||||
|
||||
Handle_t *handler = nullptr;
|
||||
|
||||
void rkt_webview_cleanup()
|
||||
{
|
||||
@@ -54,76 +108,190 @@ void rkt_webview_cleanup()
|
||||
handler = nullptr;
|
||||
}
|
||||
*/
|
||||
fprintf(stderr, "Sending quit message\n");
|
||||
handler->command_queue->enqueue(CMD_QUIT);
|
||||
fprintf(stderr, "Message sent\n");
|
||||
bool stopped = false;
|
||||
while(!stopped) {
|
||||
int cmd;
|
||||
std::string s;
|
||||
fprintf(stderr, "Getting result of quit message\n");
|
||||
handler->command_result_queue->dequeue(cmd, s, true);
|
||||
fprintf(stderr, "got %d\n", cmd);
|
||||
if (cmd == RESULT_QUIT) {
|
||||
stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
delete handler->event_queue;
|
||||
delete handler->command_result_queue;
|
||||
delete handler->command_queue;
|
||||
delete handler->shm;
|
||||
delete handler;
|
||||
handler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void rkt_webview_init()
|
||||
{
|
||||
if (handler == nullptr) {
|
||||
handler = new Rktwebview_qt();
|
||||
// Create shared memory and communication queues
|
||||
|
||||
char buf[1024];
|
||||
#ifdef DEBUG
|
||||
sprintf(buf, "rktwebview-dbg");
|
||||
#else
|
||||
pid_t p = getpid();
|
||||
sprintf(buf, "rktwebview-%x", p);
|
||||
#endif
|
||||
|
||||
handler = new Handle_t;
|
||||
handler->name = buf;
|
||||
|
||||
handler->shm_size = SHM_SIZE;
|
||||
handler->shm = new Shm(handler->name.data(), handler->shm_size, true);
|
||||
handler->command_queue = new ShmQueue(handler->shm, COMMAND_SLOT, true);
|
||||
handler->command_result_queue = new ShmQueue(handler->shm, COMMAND_RESULT_SLOT, true);
|
||||
handler->event_queue = new ShmQueue(handler->shm, EVENT_SLOT, true);
|
||||
|
||||
// Start rktwebview_prg application with the right information
|
||||
#ifndef DEBUG
|
||||
handler->rkt_webview_prg_started = runRktWebview(handler);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (handler->app() == nullptr) {
|
||||
handler->initApp();
|
||||
bool rkt_webview_valid(rktwebview_t wv)
|
||||
{
|
||||
rkt_webview_init();
|
||||
if (handler != nullptr && handler->rkt_webview_prg_started) {
|
||||
handler->command_queue->enqueue(CMD_HANDLE_IS_VALID);
|
||||
int result;
|
||||
std::string json_result;
|
||||
handler->command_result_queue->dequeue(result, json_result, true);
|
||||
return result == 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
rkt_wv_context_t rkt_webview_new_context(const char *boilerplate_js, const char *optional_server_cert_pem)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->newContext(boilerplate_js, optional_server_cert_pem);
|
||||
|
||||
JSON j;
|
||||
|
||||
std::string bpj(boilerplate_js);
|
||||
bool has_pem_cert = optional_server_cert_pem != nullptr;
|
||||
std::string osc(has_pem_cert ? optional_server_cert_pem : "");
|
||||
|
||||
j["boilerplate_js"] = bpj;
|
||||
j["has_pem_cert"] = has_pem_cert;
|
||||
j["pem_cert"] = osc;
|
||||
|
||||
handler->command_queue->enqueue(CMD_CONTEXT_NEW, j.dump());
|
||||
|
||||
int result;
|
||||
std::string json_result;
|
||||
handler->command_result_queue->dequeue(result, json_result, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
int rkt_webview_create(rkt_wv_context_t context, rktwebview_t parent, event_cb_t js_event_cb)
|
||||
int rkt_webview_create(rkt_wv_context_t context, rktwebview_t parent)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktWebViewCreate(context, parent, js_event_cb);
|
||||
JSON j;
|
||||
j["context"] = context;
|
||||
j["parent"] = parent;
|
||||
|
||||
handler->command_queue->enqueue(CMD_CREATE_WV, j.dump());
|
||||
|
||||
int result;
|
||||
std::string json_result;
|
||||
handler->command_result_queue->dequeue(result, json_result, true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void rkt_webview_close(rktwebview_t wv)
|
||||
{
|
||||
rkt_webview_init();
|
||||
handler->rktWebViewClose(wv);
|
||||
|
||||
JSON j;
|
||||
j["wv"] = wv;
|
||||
handler->command_queue->enqueue(CMD_CLOSE_WV, j.dump());
|
||||
}
|
||||
|
||||
#define CMDRES4(cmd, wv, key, val, key2, val2, key3, val3, key4, val4) \
|
||||
rkt_webview_init(); \
|
||||
JSON j; \
|
||||
j["wv"] = wv; \
|
||||
j[key] = val; \
|
||||
j[key2] = val2; \
|
||||
j[key3] = val3; \
|
||||
j[key4] = val4; \
|
||||
handler->command_queue->enqueue(cmd, j.dump()); \
|
||||
int result; \
|
||||
std::string json_result; \
|
||||
handler->command_result_queue->dequeue(result, json_result, true); \
|
||||
result_t r = static_cast<result_t>(result); \
|
||||
return r;
|
||||
|
||||
#define CMDRES3(cmd, wv, key, val, key2, val2, key3, val3) \
|
||||
CMDRES4(cmd, wv, key, val, key2, val2, key3, val3, "nil3", "none")
|
||||
|
||||
#define CMDRES2(cmd, wv, key, val, key2, val2) \
|
||||
CMDRES3(cmd, wv, key, val, key2, val2, "nil2", "none")
|
||||
|
||||
#define CMDRES(cmd, wv, key, val) \
|
||||
CMDRES2(cmd, wv, key, val, "nil1", "none")
|
||||
|
||||
#define CMDRES0(cmd, wv) \
|
||||
CMDRES(cmd, wv, "nil0", "none")
|
||||
|
||||
result_t rkt_webview_set_url(rktwebview_t wv, const char *url)
|
||||
{
|
||||
rkt_webview_init();
|
||||
result_t r = handler->rktSetUrl(wv, url);
|
||||
return r;
|
||||
CMDRES(CMD_SET_URL, wv, "url", url)
|
||||
}
|
||||
|
||||
result_t rkt_webview_set_html(rktwebview_t wv, const char *url)
|
||||
result_t rkt_webview_set_html(rktwebview_t wv, const char *html)
|
||||
{
|
||||
rkt_webview_init();
|
||||
result_t r = handler->rktSetHtml(wv, url);
|
||||
return r;
|
||||
CMDRES(CMD_SET_HTML, wv, "html", html)
|
||||
}
|
||||
|
||||
|
||||
result_t rkt_webview_run_js(rktwebview_t wv, const char *js)
|
||||
{
|
||||
rkt_webview_init();
|
||||
result_t r = handler->rktRunJs(wv, js);
|
||||
return r;
|
||||
CMDRES(CMD_RUN_JS, wv, "js", js)
|
||||
}
|
||||
|
||||
rkt_data_t *rkt_webview_call_js(rktwebview_t wv, const char *js)
|
||||
{
|
||||
rkt_webview_init();
|
||||
rkt_data_t *r = handler->rktCallJs(wv, js);
|
||||
|
||||
JSON j;
|
||||
j["wv"] = wv;
|
||||
j["js"] = std::string(js);
|
||||
handler->command_queue->enqueue(CMD_CALL_JS, j.dump());
|
||||
|
||||
int result;
|
||||
std::string json_result;
|
||||
handler->command_result_queue->dequeue(result, json_result, true);
|
||||
|
||||
rkt_data_t *r = new rkt_data_t();
|
||||
r->kind = rkt_data_kind_t::js_result;
|
||||
r->data.js_result.result = static_cast<result_t>(result);
|
||||
r->data.js_result.value = strdup(json_result.c_str());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
result_t rkt_webview_open_devtools(rktwebview_t wv)
|
||||
{
|
||||
rkt_webview_init();
|
||||
result_t r = handler->rktOpenDevtools(wv);
|
||||
return r;
|
||||
CMDRES(CMD_OPEN_DEVTOOLS, wv, "nil", "none")
|
||||
}
|
||||
|
||||
/*
|
||||
void rkt_webview_process_events(int for_ms)
|
||||
{
|
||||
rkt_webview_init();
|
||||
@@ -136,106 +304,94 @@ void rkt_webview_process_events(int for_ms)
|
||||
handler->doEvents();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
result_t rkt_webview_move(rktwebview_t wv, int x, int y)
|
||||
{
|
||||
rkt_webview_init();
|
||||
|
||||
result_t r = handler->rktMove(wv, x, y);
|
||||
return r;
|
||||
CMDRES2(CMD_MOVE, wv, "x", x, "y", y)
|
||||
}
|
||||
|
||||
|
||||
result_t rkt_webview_resize(rktwebview_t wv, int width, int height)
|
||||
{
|
||||
rkt_webview_init();
|
||||
|
||||
result_t r = handler->rktResize(wv, width, height);
|
||||
return r;
|
||||
CMDRES2(CMD_RESIZE, wv, "w", width, "h", height)
|
||||
}
|
||||
|
||||
|
||||
bool rkt_webview_valid(rktwebview_t wv)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktValid(wv);
|
||||
}
|
||||
|
||||
result_t rkt_webview_hide(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktHideWindow(w);
|
||||
|
||||
CMDRES0(CMD_HIDE, w)
|
||||
}
|
||||
|
||||
result_t rkt_webview_show(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktShowWindow(w);
|
||||
CMDRES0(CMD_SHOW, w)
|
||||
}
|
||||
|
||||
result_t rkt_webview_present(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktPresentWindow(w);
|
||||
CMDRES0(CMD_PRESENT, w)
|
||||
}
|
||||
|
||||
result_t rkt_webview_maximize(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktMaximizeWindow(w);
|
||||
CMDRES0(CMD_MAXIMIZE, w)
|
||||
}
|
||||
|
||||
result_t rkt_webview_minimize(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktMinimizeWindow(w);
|
||||
CMDRES0(CMD_MINIMIZE, w)
|
||||
}
|
||||
|
||||
result_t rkt_webview_show_normal(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktShowNormalWindow(w);
|
||||
CMDRES0(CMD_SHOW_NORMAL, w)
|
||||
}
|
||||
|
||||
window_state_t rkt_webview_window_state(rktwebview_t w)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktWindowState(w);
|
||||
auto f = [w]() {
|
||||
CMDRES0(CMD_WINDOW_STATE, w)
|
||||
};
|
||||
int r = f();
|
||||
return static_cast<window_state_t>(r);
|
||||
}
|
||||
|
||||
result_t rkt_webview_set_title(rktwebview_t wv, const char *title)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktWindowSetTitle(wv, title);
|
||||
CMDRES(CMD_SET_TITLE, wv, "title", title)
|
||||
}
|
||||
|
||||
result_t rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktChooseDir(w, title, base_dir);
|
||||
CMDRES2(CMD_CHOOSE_DIR, w, "title", title, "base_dir", base_dir)
|
||||
}
|
||||
|
||||
result_t rkt_webview_file_open(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktFileOpen(w, title, base_dir, permitted_exts);
|
||||
CMDRES3(CMD_FILE_OPEN, w, "title", title, "base_dir", base_dir, "permitted_exts", permitted_exts)
|
||||
}
|
||||
|
||||
result_t rkt_webview_file_save(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktFileSave(w, title, base_dir, permitted_exts);
|
||||
CMDRES3(CMD_FILE_SAVE, w, "title", title, "base_dir", base_dir, "permitted_exts", permitted_exts)
|
||||
}
|
||||
|
||||
void rkt_webview_set_ou_token(rktwebview_t wv, const char *token)
|
||||
{
|
||||
rkt_webview_init();
|
||||
handler->rktSetOUToken(wv, token);
|
||||
|
||||
JSON j;
|
||||
j["wv"] = wv;
|
||||
j["token"] = std::string(token);
|
||||
|
||||
handler->command_queue->enqueue(CMD_SET_OU_TOKEN, j.dump());
|
||||
}
|
||||
|
||||
void rkt_webview_free_data(rkt_data_t *d)
|
||||
{
|
||||
if (d == nullptr) { return; }
|
||||
|
||||
if (d->kind == version) {
|
||||
free(d);
|
||||
} else if (d->kind == event) {
|
||||
@@ -256,14 +412,37 @@ rkt_data_t *rkt_webview_version()
|
||||
d->data.version.api_major = RKT_WEBVIEW_API_MAJOR;
|
||||
d->data.version.api_minor = RKT_WEBVIEW_API_MINOR;
|
||||
d->data.version.api_patch = RKT_WEBVIEW_API_PATCH;
|
||||
d->data.version.qt_major = QT_VERSION_MAJOR;
|
||||
d->data.version.qt_minor = QT_VERSION_MINOR;
|
||||
d->data.version.qt_patch = QT_VERSION_PATCH;
|
||||
return d;
|
||||
}
|
||||
|
||||
result_t rkt_webview_message_box(rktwebview_t w, const char *title, const char *message, const char *submessage, rkt_messagetype_t type)
|
||||
{
|
||||
rkt_webview_init();
|
||||
return handler->rktMessageBox(w, title, message, submessage, type);
|
||||
CMDRES4(CMD_MSG_BOX, w, "title", title, "message", message, "submessage", submessage, "type", static_cast<int>(type))
|
||||
}
|
||||
|
||||
int rkt_webview_events_waiting()
|
||||
{
|
||||
return handler->event_queue->depth();
|
||||
}
|
||||
|
||||
rkt_data_t *rkt_webview_get_event()
|
||||
{
|
||||
//fprintf(stderr, "rkt_webview_get_event\n");
|
||||
int wv;
|
||||
std::string data;
|
||||
if (handler->event_queue->dequeue(wv, data, false)) {
|
||||
//fprintf(stderr, "got event %d %s\n", wv, data.c_str());
|
||||
rkt_data_t *d = reinterpret_cast<rkt_data_t *>(malloc(sizeof(rkt_data_t)));
|
||||
d->kind = rkt_data_kind_t::event;
|
||||
|
||||
size_t ds = data.size();
|
||||
d->data.event.event = reinterpret_cast<char *>(malloc(ds + 1));
|
||||
memcpy(d->data.event.event, data.c_str(), ds);
|
||||
d->data.event.event[ds] = '\0';
|
||||
d->data.event.wv = wv;
|
||||
fprintf(stderr, "event: %d - '%s'\n", d->data.event.wv, d->data.event.event);
|
||||
return d;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef RKTWEBVIEW_H
|
||||
#define RKTWEBVIEW_H
|
||||
|
||||
#include "rktwebview_qt_global.h"
|
||||
#include "rktwebview_global.h"
|
||||
#include "rktwebview_types.h"
|
||||
|
||||
#define RKT_WEBVIEW_API_MAJOR 0
|
||||
#define RKT_WEBVIEW_API_MINOR 1
|
||||
@@ -9,122 +10,47 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
typedef int rktwebview_t;
|
||||
typedef int rkt_wv_context_t;
|
||||
RKTWEBVIEW_EXPORT void rkt_webview_init();
|
||||
RKTWEBVIEW_EXPORT void rkt_webview_cleanup();
|
||||
//RKTWEBVIEW_EXPORT void rkt_webview_process_events(int for_ms);
|
||||
|
||||
typedef struct {
|
||||
rktwebview_t wv;
|
||||
char *event;
|
||||
} rkt_event_t;
|
||||
RKTWEBVIEW_EXPORT void rkt_webview_free_data(rkt_data_t *d);
|
||||
RKTWEBVIEW_EXPORT rkt_data_t *rkt_webview_version();
|
||||
|
||||
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,
|
||||
move_failed = 12,
|
||||
resize_failed = 13,
|
||||
choose_dir_failed = 14,
|
||||
open_file_failed = 15,
|
||||
save_file_failed = 16,
|
||||
failed = 17
|
||||
} result_t;
|
||||
RKTWEBVIEW_EXPORT int rkt_webview_events_waiting();
|
||||
RKTWEBVIEW_EXPORT rkt_data_t *rkt_webview_get_event();
|
||||
|
||||
typedef struct {
|
||||
result_t result;
|
||||
char *value;
|
||||
} rkt_js_result_t;
|
||||
RKTWEBVIEW_EXPORT rkt_wv_context_t rkt_webview_new_context(const char *boilerplate_js, const char *optional_server_cert_pem);
|
||||
RKTWEBVIEW_EXPORT int rkt_webview_create(rkt_wv_context_t context, rktwebview_t parent);
|
||||
|
||||
typedef enum {
|
||||
invalid = -1,
|
||||
normal = 0,
|
||||
minimized = 1,
|
||||
maximized = 2,
|
||||
hidden = 3,
|
||||
normal_active = 16,
|
||||
maximized_active = 18
|
||||
} window_state_t;
|
||||
RKTWEBVIEW_EXPORT void rkt_webview_close(rktwebview_t wv);
|
||||
RKTWEBVIEW_EXPORT bool rkt_webview_valid(rktwebview_t wv);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_set_title(rktwebview_t wv, const char *title);
|
||||
RKTWEBVIEW_EXPORT void rkt_webview_set_ou_token(rktwebview_t wv, const char *token);
|
||||
|
||||
typedef enum {
|
||||
info = 1,
|
||||
error = 2,
|
||||
warning = 3,
|
||||
yes_no = 4,
|
||||
oke_cancel = 5
|
||||
} rkt_messagetype_t;
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_set_url(rktwebview_t wv, const char *url);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_set_html(rktwebview_t wv, const char *html);
|
||||
|
||||
typedef struct {
|
||||
int qt_major;
|
||||
int qt_minor;
|
||||
int qt_patch;
|
||||
int api_major;
|
||||
int api_minor;
|
||||
int api_patch;
|
||||
} rkt_version_t;
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_run_js(rktwebview_t wv, const char *js);
|
||||
RKTWEBVIEW_EXPORT rkt_data_t *rkt_webview_call_js(rktwebview_t wv, const char *js);
|
||||
|
||||
typedef enum {
|
||||
version = 1,
|
||||
event = 2,
|
||||
js_result = 3
|
||||
} rkt_data_kind_t;
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_open_devtools(rktwebview_t wv);
|
||||
|
||||
typedef struct {
|
||||
rkt_data_kind_t kind;
|
||||
union {
|
||||
rkt_version_t version;
|
||||
rkt_event_t event;
|
||||
rkt_js_result_t js_result;
|
||||
} data;
|
||||
} rkt_data_t;
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_move(rktwebview_t w, int x, int y);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_resize(rktwebview_t w, int width, int height);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_hide(rktwebview_t w);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_show(rktwebview_t w);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_show_normal(rktwebview_t w);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_present(rktwebview_t w);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_maximize(rktwebview_t w);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_minimize(rktwebview_t w);
|
||||
RKTWEBVIEW_EXPORT window_state_t rkt_webview_window_state(rktwebview_t w);
|
||||
|
||||
typedef void (*event_cb_t)(rkt_data_t *);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_file_open(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_file_save(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts);
|
||||
|
||||
RKTWEBVIEW_QT_EXPORT void rkt_webview_init();
|
||||
RKTWEBVIEW_QT_EXPORT void rkt_webview_cleanup();
|
||||
RKTWEBVIEW_QT_EXPORT void rkt_webview_process_events(int for_ms);
|
||||
RKTWEBVIEW_QT_EXPORT void rkt_webview_free_data(rkt_data_t *d);
|
||||
RKTWEBVIEW_QT_EXPORT rkt_data_t *rkt_webview_version();
|
||||
|
||||
RKTWEBVIEW_QT_EXPORT rkt_wv_context_t rkt_webview_new_context(const char *boilerplate_js, const char *optional_server_cert_pem);
|
||||
|
||||
RKTWEBVIEW_QT_EXPORT int rkt_webview_create(rkt_wv_context_t context, 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_title(rktwebview_t wv, const char *title);
|
||||
RKTWEBVIEW_QT_EXPORT void rkt_webview_set_ou_token(rktwebview_t wv, const char *token);
|
||||
|
||||
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 rkt_data_t *rkt_webview_call_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_move(rktwebview_t w, int x, int y);
|
||||
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_resize(rktwebview_t w, int width, int height);
|
||||
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_hide(rktwebview_t w);
|
||||
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_show(rktwebview_t w);
|
||||
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_show_normal(rktwebview_t w);
|
||||
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_present(rktwebview_t w);
|
||||
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 result_t rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir);
|
||||
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_file_open(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts);
|
||||
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_file_save(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts);
|
||||
|
||||
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_message_box(rktwebview_t w, const char *title, const char *message, const char *submessage, rkt_messagetype_t type);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_message_box(rktwebview_t w, const char *title, const char *message, const char *submessage, rkt_messagetype_t type);
|
||||
|
||||
}
|
||||
|
||||
|
||||
18
rktwebview_qt/rktwebview_global.h
Normal file
18
rktwebview_qt/rktwebview_global.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef RKTWEBVIEW_GLOBAL_H
|
||||
#define RKTWEBVIEW_GLOBAL_H
|
||||
|
||||
#if defined(RKTWEBVIEW_LIBRARY)
|
||||
#ifdef _WIN32
|
||||
#define RKTWEBVIEW_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define RKTWEBVIEW_EXPORT
|
||||
#endif
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
#define RKTWEBVIEW_EXPORT __declspec(dllimport)
|
||||
#else
|
||||
#define RKTWEBVIEW_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // RKTWEBVIEW_GLOBAL_H
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef RKTWEBVIEW_INTERNAL_H
|
||||
#define RKTWEBVIEW_INTERNAL_H
|
||||
|
||||
#include "rktwebview.h"
|
||||
|
||||
#endif // RKTWEBVIEW_INTERNAL_H
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "rktwebview_qt.h"
|
||||
#include "webviewqt.h"
|
||||
#include "rktwebview.h"
|
||||
#include "rktwebview_types.h"
|
||||
#include "webviewwindow.h"
|
||||
#include "rktutils.h"
|
||||
#include <QApplication>
|
||||
@@ -29,6 +29,92 @@ static inline char *copyString(const char *s)
|
||||
void Rktwebview_qt::processCommand(Command *cmd)
|
||||
{
|
||||
switch(cmd->cmd) {
|
||||
case COMMAND_QUIT: { // Quit application
|
||||
_app->quit();
|
||||
}
|
||||
break;
|
||||
case COMMAND_NEW_CONTEXT: {
|
||||
QString boilerplate_js = cmd->args[0].toString();
|
||||
bool has_pem = cmd->args[1].toBool();
|
||||
QString optional_server_cert_pem = cmd->args[2].toString();
|
||||
|
||||
fprintf(stderr, "bjs: %s\n", boilerplate_js.toUtf8().constData());
|
||||
fprintf(stderr, "oscp: %s\n", optional_server_cert_pem.toUtf8().constData());
|
||||
|
||||
QWebEngineProfileBuilder b;
|
||||
if (has_pem) {
|
||||
QByteArray scp = optional_server_cert_pem.toUtf8();
|
||||
fprintf(stderr, "Installing cert: %s\n", scp.constData());
|
||||
QList<QSslCertificate> certs;
|
||||
QSslCertificate cert(scp);
|
||||
certs.append(cert);
|
||||
b.setAdditionalTrustedCertificates(certs);
|
||||
}
|
||||
_context_counter += 1;
|
||||
QString name = QString::asprintf("profile-%d", _context_counter);
|
||||
|
||||
QString code = "if (window.rkt_event_queue === undefined) { window.rkt_event_queue = []; }\n"
|
||||
"window.rkt_evt_frame_el = null;\n"
|
||||
"window.rkt_evt_frame_win = null;\n"
|
||||
"window.rkt_send_event = function(obj) {\n"
|
||||
" //console.log('Sending event: ' + obj);\n"
|
||||
" window.rkt_event_queue.push(obj);\n"
|
||||
" if (window.rkt_evt_frame_el) {\n"
|
||||
" window.rkt_evt_frame_win.print();\n"
|
||||
" }\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"
|
||||
"// add hidden hover element to body if necessary\n"
|
||||
"setInterval(function () {\n"
|
||||
" if (window.rkt_evt_frame_el === null || window.rkt_evt_frame_el === undefined) {\n"
|
||||
" window.rkt_evt_frame_el = document.createElement('iframe');\n"
|
||||
" window.rkt_evt_frame_el.style.display = 'none';\n"
|
||||
" window.rkt_evt_frame_el.setAttribute('id', 'rkt-evt-frame');\n"
|
||||
" window.rkt_evt_frame_el.setAttribute('name', 'rkt-evt-frame');\n"
|
||||
" document.body.append(window.rkt_evt_frame_el);\n"
|
||||
" window.rkt_evt_frame_win = window.rkt_evt_frame_el.contentWindow;\n"
|
||||
" } else {"
|
||||
" if (window.rkt_event_queue.length > 0) {\n"
|
||||
" window.rkt_evt_frame_win.print();\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"},\n"
|
||||
"10);\n"
|
||||
"";
|
||||
|
||||
QList<QWebEngineScript> scripts;
|
||||
QWebEngineProfile *p = b.createProfile(name);
|
||||
QWebEngineScriptCollection *col = p->scripts();
|
||||
QWebEngineScript s1;
|
||||
s1.setInjectionPoint(QWebEngineScript::InjectionPoint::DocumentReady);
|
||||
s1.setName("eventing");
|
||||
s1.setSourceCode(code);
|
||||
s1.setWorldId(QWebEngineScript::MainWorld);
|
||||
scripts.append(s1);
|
||||
|
||||
QWebEngineScript s2;
|
||||
s2.setInjectionPoint(QWebEngineScript::InjectionPoint::DocumentReady);
|
||||
s2.setName("boilerplate");
|
||||
s2.setSourceCode(boilerplate_js);
|
||||
s2.setWorldId(QWebEngineScript::MainWorld);
|
||||
scripts.append(s2);
|
||||
|
||||
col->insert(scripts);
|
||||
|
||||
QWebEngineScriptCollection *c = p->scripts();
|
||||
QList<QWebEngineScript> l = c->toList();
|
||||
|
||||
_contexts[_context_counter] = p;
|
||||
|
||||
cmd->result = _context_counter;
|
||||
cmd->done = true;
|
||||
}
|
||||
break;
|
||||
case COMMAND_CREATE: {
|
||||
rkt_wv_context_t context = cmd->args[0].toInt();
|
||||
rktwebview_t parent = cmd->args[1].toInt();
|
||||
@@ -151,6 +237,7 @@ void Rktwebview_qt::processCommand(Command *cmd)
|
||||
QString js = cmd->args[1].toString();
|
||||
if (_views.contains(wv)) {
|
||||
WebviewWindow *w = _views[wv];
|
||||
fprintf(stderr, "Running %s\n", js.toUtf8().constData());
|
||||
w->runJs(js);
|
||||
cmd->result = true;
|
||||
} else {
|
||||
@@ -367,78 +454,20 @@ int Rktwebview_qt::nextHandle()
|
||||
return h;
|
||||
}
|
||||
|
||||
rkt_wv_context_t Rktwebview_qt::newContext(const char *boilerplate_js, const char *optional_server_cert_pem)
|
||||
rkt_wv_context_t Rktwebview_qt::newContext(const QString &boilerplate_js, bool has_pem, const QString &optional_server_cert_pem)
|
||||
{
|
||||
QWebEngineProfileBuilder b;
|
||||
if (optional_server_cert_pem != nullptr) {
|
||||
QByteArray scp = QByteArray(optional_server_cert_pem);
|
||||
QList<QSslCertificate> certs;
|
||||
QSslCertificate cert(scp);
|
||||
certs.append(cert);
|
||||
b.setAdditionalTrustedCertificates(certs);
|
||||
}
|
||||
_context_counter += 1;
|
||||
QString name = QString::asprintf("profile-%d", _context_counter);
|
||||
Command c(COMMAND_NEW_CONTEXT);
|
||||
|
||||
QString code = "if (window.rkt_event_queue === undefined) { window.rkt_event_queue = []; }\n"
|
||||
"window.rkt_evt_frame_el = null;\n"
|
||||
"window.rkt_evt_frame_win = null;\n"
|
||||
"window.rkt_send_event = function(obj) {\n"
|
||||
" //console.log('Sending event: ' + obj);\n"
|
||||
" window.rkt_event_queue.push(obj);\n"
|
||||
" if (window.rkt_evt_frame_el) {\n"
|
||||
" window.rkt_evt_frame_win.print();\n"
|
||||
" }\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"
|
||||
"// add hidden hover element to body if necessary\n"
|
||||
"setInterval(function () {\n"
|
||||
" if (window.rkt_evt_frame_el === null || window.rkt_evt_frame_el === undefined) {\n"
|
||||
" window.rkt_evt_frame_el = document.createElement('iframe');\n"
|
||||
" window.rkt_evt_frame_el.style.display = 'none';\n"
|
||||
" window.rkt_evt_frame_el.setAttribute('id', 'rkt-evt-frame');\n"
|
||||
" window.rkt_evt_frame_el.setAttribute('name', 'rkt-evt-frame');\n"
|
||||
" document.body.append(window.rkt_evt_frame_el);\n"
|
||||
" window.rkt_evt_frame_win = window.rkt_evt_frame_el.contentWindow;\n"
|
||||
" } else {"
|
||||
" if (window.rkt_event_queue.length > 0) {\n"
|
||||
" window.rkt_evt_frame_win.print();\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"},\n"
|
||||
"10);\n"
|
||||
"";
|
||||
c.args.push_back(boilerplate_js);
|
||||
c.args.push_back(has_pem);
|
||||
c.args.push_back(optional_server_cert_pem);
|
||||
|
||||
QList<QWebEngineScript> scripts;
|
||||
QWebEngineProfile *p = b.createProfile(name);
|
||||
QWebEngineScriptCollection *col = p->scripts();
|
||||
QWebEngineScript s1;
|
||||
s1.setInjectionPoint(QWebEngineScript::InjectionPoint::DocumentReady);
|
||||
s1.setName("eventing");
|
||||
s1.setSourceCode(code);
|
||||
s1.setWorldId(QWebEngineScript::MainWorld);
|
||||
scripts.append(s1);
|
||||
postCommand(&c);
|
||||
|
||||
QWebEngineScript s2;
|
||||
s2.setInjectionPoint(QWebEngineScript::InjectionPoint::DocumentReady);
|
||||
s2.setName("boilerplate");
|
||||
s2.setSourceCode(boilerplate_js);
|
||||
s2.setWorldId(QWebEngineScript::MainWorld);
|
||||
scripts.append(s2);
|
||||
while(!c.done) { doEvents(); }
|
||||
|
||||
col->insert(scripts);
|
||||
|
||||
QWebEngineScriptCollection *c = p->scripts();
|
||||
QList<QWebEngineScript> l = c->toList();
|
||||
|
||||
_contexts[_context_counter] = p;
|
||||
|
||||
return _context_counter;
|
||||
int id = c.result.toInt();
|
||||
return id;
|
||||
}
|
||||
|
||||
int Rktwebview_qt::rktWebViewCreate(rkt_wv_context_t context, rktwebview_t parent, event_cb_t js_evt_cb)
|
||||
@@ -512,6 +541,8 @@ result_t Rktwebview_qt::rktSetHtml(rktwebview_t wv, const char *html)
|
||||
|
||||
rkt_data_t *Rktwebview_qt::rktCallJs(rktwebview_t wv, const char *js)
|
||||
{
|
||||
fprintf(stderr, "calljs: %s\n", js);
|
||||
|
||||
Command c(COMMAND_CALL_JS);
|
||||
QString _js(js);
|
||||
c.args.push_back(wv);
|
||||
@@ -523,16 +554,17 @@ rkt_data_t *Rktwebview_qt::rktCallJs(rktwebview_t wv, const char *js)
|
||||
r->kind = js_result;
|
||||
r->data.js_result.result = c.js_result_ok ? result_t::oke : result_t::eval_js_failed;
|
||||
r->data.js_result.value = copyString(c.result.toString().toUtf8());
|
||||
fprintf(stderr, "js-result: %s\n", r->data.js_result.value);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
result_t Rktwebview_qt::rktRunJs(rktwebview_t wv, const char *js)
|
||||
result_t Rktwebview_qt::rktRunJs(rktwebview_t wv, const QString &js)
|
||||
{
|
||||
fprintf(stderr, "rktRunJs: %s\n", js.toUtf8().constData());
|
||||
Command c(COMMAND_RUN_JS);
|
||||
QString _js(js);
|
||||
c.args.push_back(wv);
|
||||
c.args.push_back(_js);
|
||||
c.args.push_back(js);
|
||||
postCommand(&c);
|
||||
while(!c.done) { doEvents(); }
|
||||
bool r = c.result.toBool();
|
||||
@@ -604,6 +636,12 @@ window_state_t Rktwebview_qt::rktWindowState(rktwebview_t w)
|
||||
return ws;
|
||||
}
|
||||
|
||||
void Rktwebview_qt::rktQuit()
|
||||
{
|
||||
Command c(COMMAND_QUIT);
|
||||
postCommand(&c);
|
||||
}
|
||||
|
||||
result_t Rktwebview_qt::fileDlg(rktwebview_t w, const char *title, const char *base, const char *filters,QFileDialog::FileMode mode, QFileDialog::AcceptMode am, QString evt_ok, QString evt_cancel)
|
||||
{
|
||||
if (_views.contains(w)) {
|
||||
@@ -836,6 +874,7 @@ void Rktwebview_qt::deleteApp()
|
||||
void Rktwebview_qt::initApp()
|
||||
{
|
||||
_app = new QApplication(_argc, _argv);
|
||||
_app->setQuitOnLastWindowClosed(false);
|
||||
|
||||
// See Qt 6.10 remark at doEvents.
|
||||
//connect(&_evt_loop_timer, &QTimer::timeout, this, &Rktwebview_qt::stopEventloop);
|
||||
@@ -843,17 +882,17 @@ void Rktwebview_qt::initApp()
|
||||
// Because we are using processEvents only (Qt 6.10), we need this dispatcher to
|
||||
// handle deferred Deletes.
|
||||
|
||||
const auto *eventDispatcher = QThread::currentThread()->eventDispatcher();
|
||||
/*const auto *eventDispatcher = QThread::currentThread()->eventDispatcher();
|
||||
QObject::connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock,
|
||||
QThread::currentThread(), []{
|
||||
if (QThread::currentThread()->loopLevel() == 0)
|
||||
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void Rktwebview_qt::runJs(rktwebview_t wv, const char *js)
|
||||
{
|
||||
if (_views.contains(wv)) {
|
||||
@@ -888,7 +927,7 @@ void Rktwebview_qt::doEvents()
|
||||
//QTime ct = QTime::currentTime();
|
||||
//QTime expire = QTime::currentTime().addMSecs(2);
|
||||
//while(QTime::currentTime() <= expire) {
|
||||
_app->processEvents();
|
||||
//_app->processEvents();
|
||||
//}
|
||||
|
||||
// Qt 6.10 --> this leads to a core dump
|
||||
@@ -901,6 +940,7 @@ void Rktwebview_qt::doEvents()
|
||||
//_evt_loop.exec();
|
||||
_app->exec();
|
||||
}*/
|
||||
QThread::usleep(500);
|
||||
}
|
||||
|
||||
void Rktwebview_qt::stopEventloop()
|
||||
@@ -912,15 +952,15 @@ void Rktwebview_qt::stopEventloop()
|
||||
|
||||
|
||||
|
||||
Rktwebview_qt::Rktwebview_qt() : QObject()
|
||||
Rktwebview_qt::Rktwebview_qt(int argc, char *argv[]) : QObject()
|
||||
{
|
||||
_argc = 1;
|
||||
_argv[0] = const_cast<char *>("Rktwebview_qt");
|
||||
|
||||
_context_counter = 0;
|
||||
_current_handle = 0;
|
||||
_evt_loop_depth = 0;
|
||||
|
||||
_argc = argc;
|
||||
_argv = argv;
|
||||
|
||||
_app = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#ifndef RKTWEBVIEW_QT_H
|
||||
#define RKTWEBVIEW_QT_H
|
||||
|
||||
#include "rktwebview_qt_global.h"
|
||||
#include "rktwebview_internal.h"
|
||||
#include "rktutils.h"
|
||||
#include "rktwebview_types.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QWebEngineView>
|
||||
@@ -21,7 +20,7 @@ class WebviewWindow;
|
||||
class Command;
|
||||
class CommandEvent;
|
||||
|
||||
class RKTWEBVIEW_QT_EXPORT Rktwebview_qt : public QObject
|
||||
class Rktwebview_qt : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
@@ -39,7 +38,7 @@ private:
|
||||
QTimer _evt_loop_timer;
|
||||
|
||||
int _argc;
|
||||
char *_argv[1];
|
||||
char **_argv;
|
||||
|
||||
private:
|
||||
void runJs(rktwebview_t wv, const char *js);
|
||||
@@ -71,7 +70,7 @@ public:
|
||||
int nextHandle();
|
||||
|
||||
public:
|
||||
rkt_wv_context_t newContext(const char *boilerplate_js, const char *optional_server_cert_pem);
|
||||
rkt_wv_context_t newContext(const QString &boilerplate_js, bool has_pem, const QString &optional_server_cert_pem);
|
||||
int rktWebViewCreate(rkt_wv_context_t context, rktwebview_t parent, event_cb_t js_evt_cb);
|
||||
void rktWebViewClose(int wv);
|
||||
void rktSetOUToken(rktwebview_t wv, const char *ou_token);
|
||||
@@ -79,7 +78,7 @@ public:
|
||||
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 rktRunJs(rktwebview_t wv, const QString &js);
|
||||
rkt_data_t *rktCallJs(rktwebview_t wv, const char *js);
|
||||
|
||||
result_t rktMove(rktwebview_t wv, int x, int y);
|
||||
@@ -92,6 +91,8 @@ public:
|
||||
result_t rktShowNormalWindow(rktwebview_t w);
|
||||
window_state_t rktWindowState(rktwebview_t w);
|
||||
|
||||
void rktQuit();
|
||||
|
||||
result_t rktChooseDir(rktwebview_t w, const char *title, const char *base_dir);
|
||||
result_t rktFileOpen(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts);
|
||||
result_t rktFileSave(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts);
|
||||
@@ -117,7 +118,7 @@ public:
|
||||
void runCommandThread();
|
||||
|
||||
public:
|
||||
Rktwebview_qt();
|
||||
Rktwebview_qt(int argc, char *argv[]);
|
||||
~Rktwebview_qt();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#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
|
||||
32
rktwebview_qt/rktwebview_test.cpp
Normal file
32
rktwebview_qt/rktwebview_test.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "rktwebview.h"
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{std::string me = argv[0];
|
||||
int idx = me.rfind("/");
|
||||
|
||||
std::string loc = me.substr(0, idx);
|
||||
std::string prg = loc + "/rktwebview_prg";
|
||||
|
||||
setenv("RKT_WEBVIEW_PRG", prg.c_str(), true);
|
||||
setenv("LD_LIBRARY_PATH", loc.c_str(), true);
|
||||
|
||||
int context = rkt_webview_new_context("", nullptr);
|
||||
|
||||
int wv = rkt_webview_create(context, 0);
|
||||
|
||||
rkt_webview_move(wv, 100, 200);
|
||||
rkt_webview_resize(wv, 800, 600);
|
||||
rkt_webview_set_url(wv, "https://wikipedia.org");
|
||||
|
||||
while(rkt_webview_events_waiting() > 0) {
|
||||
rkt_data_t *d = rkt_webview_get_event();
|
||||
rkt_webview_free_data(d);
|
||||
}
|
||||
sleep(10);
|
||||
|
||||
rkt_webview_close(wv);
|
||||
|
||||
rkt_webview_cleanup();
|
||||
}
|
||||
84
rktwebview_qt/rktwebview_types.h
Normal file
84
rktwebview_qt/rktwebview_types.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#ifndef RKTWEBVIEW_TYPES_H
|
||||
#define RKTWEBVIEW_TYPES_H
|
||||
|
||||
extern "C" {
|
||||
|
||||
typedef int rktwebview_t;
|
||||
typedef int rkt_wv_context_t;
|
||||
|
||||
typedef struct {
|
||||
rktwebview_t wv;
|
||||
char *event;
|
||||
} rkt_event_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,
|
||||
move_failed = 12,
|
||||
resize_failed = 13,
|
||||
choose_dir_failed = 14,
|
||||
open_file_failed = 15,
|
||||
save_file_failed = 16,
|
||||
failed = 17
|
||||
} result_t;
|
||||
|
||||
typedef struct {
|
||||
result_t result;
|
||||
char *value;
|
||||
} rkt_js_result_t;
|
||||
|
||||
typedef enum {
|
||||
invalid = -1,
|
||||
normal = 0,
|
||||
minimized = 1,
|
||||
maximized = 2,
|
||||
hidden = 3,
|
||||
normal_active = 16,
|
||||
maximized_active = 18
|
||||
} window_state_t;
|
||||
|
||||
typedef enum {
|
||||
info = 1,
|
||||
error = 2,
|
||||
warning = 3,
|
||||
yes_no = 4,
|
||||
oke_cancel = 5
|
||||
} rkt_messagetype_t;
|
||||
|
||||
typedef struct {
|
||||
int api_major;
|
||||
int api_minor;
|
||||
int api_patch;
|
||||
} rkt_version_t;
|
||||
|
||||
typedef enum {
|
||||
version = 1,
|
||||
event = 2,
|
||||
js_result = 3
|
||||
} rkt_data_kind_t;
|
||||
|
||||
typedef struct {
|
||||
rkt_data_kind_t kind;
|
||||
union {
|
||||
rkt_version_t version;
|
||||
rkt_event_t event;
|
||||
rkt_js_result_t js_result;
|
||||
} data;
|
||||
} rkt_data_t;
|
||||
|
||||
typedef void (*event_cb_t)(rkt_data_t *);
|
||||
|
||||
}
|
||||
|
||||
#endif // RKTWEBVIEW_TYPES_H
|
||||
@@ -10,12 +10,13 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
typedef struct __shm_item__ {
|
||||
|
||||
struct __shm_item__ *next;
|
||||
struct __shm_item__ *prev;
|
||||
ShmPlace next;
|
||||
ShmPlace prev;
|
||||
size_t size;
|
||||
|
||||
} ShmItem;
|
||||
@@ -34,10 +35,9 @@ private:
|
||||
char *_sem_name;
|
||||
|
||||
size_t *_used;
|
||||
ShmItem **__first;
|
||||
ShmItem **__free_list;
|
||||
|
||||
ShmPlace *_slots;
|
||||
ShmPlace *_first;
|
||||
ShmPlace *_free_list;
|
||||
|
||||
int _in_critical;
|
||||
|
||||
@@ -66,57 +66,82 @@ public:
|
||||
return _mem_name;
|
||||
}
|
||||
|
||||
public:
|
||||
template <class T> void ref(int place, T** p) {
|
||||
if (place == SHM_NULL) {
|
||||
*p = nullptr;
|
||||
} else {
|
||||
*p = reinterpret_cast<T *>(reinterpret_cast<char *>(_mem) + place);
|
||||
}
|
||||
}
|
||||
|
||||
inline void *ref(int place)
|
||||
{
|
||||
if (place == SHM_NULL) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<char *>(_mem) + place;
|
||||
}
|
||||
|
||||
public:
|
||||
int alloc(size_t bytes) {
|
||||
enterCritical();
|
||||
|
||||
ShmItem *_free_list = *__free_list;
|
||||
ShmItem *_first = *__first;
|
||||
|
||||
ShmItem *i = _free_list;
|
||||
ShmPlace p_i = *_free_list;
|
||||
ShmItem *i;
|
||||
ref(p_i, &i);
|
||||
|
||||
while (i != nullptr && i->size < bytes) {
|
||||
i = i->next;
|
||||
p_i = i->next;
|
||||
ref(p_i, &i);
|
||||
}
|
||||
|
||||
int place;
|
||||
if (i != nullptr) {
|
||||
if (i->prev != nullptr) {
|
||||
i->prev->next = i->next;
|
||||
if (i->prev != SHM_NULL) {
|
||||
ShmItem *prev_i;
|
||||
ref(i->prev, &prev_i);
|
||||
prev_i->next = i->next;
|
||||
}
|
||||
if (i->next != nullptr) {
|
||||
i->next->prev = i->prev;
|
||||
if (i->next != SHM_NULL) {
|
||||
ShmItem *next_i;
|
||||
ref(i->next, &next_i);
|
||||
next_i->prev = i->prev;
|
||||
}
|
||||
if (i->prev == nullptr) {
|
||||
_free_list = i->next;
|
||||
if (i->prev == SHM_NULL) {
|
||||
*_free_list = i->next;
|
||||
}
|
||||
i->next = _first;
|
||||
if (_first != nullptr) {
|
||||
_first->prev = i;
|
||||
i->next = *_first;
|
||||
if (*_first != SHM_NULL) {
|
||||
ShmItem *first_i;
|
||||
ref(*_first, &first_i);
|
||||
first_i->prev = p_i;
|
||||
}
|
||||
i->prev = nullptr;
|
||||
i->prev = SHM_NULL;
|
||||
|
||||
_first = i;
|
||||
*__first = _first;
|
||||
*__free_list = _free_list;
|
||||
|
||||
place = (reinterpret_cast<char *>(i) + sizeof(ShmItem)) - reinterpret_cast<char *>(_mem);
|
||||
*_first = p_i;
|
||||
place = p_i + sizeof(ShmItem);
|
||||
} else {
|
||||
i = reinterpret_cast<ShmItem *>(reinterpret_cast<char *>(_mem) + *_used);
|
||||
ShmPlace p_i = *_used;
|
||||
i = reinterpret_cast<ShmItem *>(reinterpret_cast<char *>(_mem) + p_i);
|
||||
size_t u = *_used + sizeof(ShmItem) + bytes;
|
||||
|
||||
if (u >= _size) {
|
||||
place = -1;
|
||||
place = SHM_NULL;
|
||||
} else {
|
||||
*_used = u;
|
||||
i->prev = nullptr;
|
||||
i->prev = SHM_NULL;
|
||||
i->size = bytes;
|
||||
i->next = _first;
|
||||
i->next = *_first;
|
||||
if (*_first != SHM_NULL) {
|
||||
ShmItem *first_i;
|
||||
ref(*_first, &first_i);
|
||||
first_i->prev = p_i;
|
||||
}
|
||||
|
||||
_first = i;
|
||||
*__first = _first;
|
||||
|
||||
place = (reinterpret_cast<char *>(i) + sizeof(ShmItem)) - reinterpret_cast<char *>(_mem);
|
||||
*_first = p_i;
|
||||
place = p_i + sizeof(ShmItem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,39 +149,42 @@ public:
|
||||
return place;
|
||||
}
|
||||
|
||||
void free(int place) {
|
||||
void free(ShmPlace place) {
|
||||
if (place == SHM_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
enterCritical();
|
||||
ShmItem *i = reinterpret_cast<ShmItem *>(reinterpret_cast<char *>(_mem) + place - sizeof(ShmItem));
|
||||
|
||||
ShmItem *_free_list = *__free_list;
|
||||
ShmItem *_first = *__first;
|
||||
ShmPlace p_i = place - sizeof(ShmItem);
|
||||
ShmItem *i;
|
||||
ref(p_i, &i);
|
||||
|
||||
if (i->prev != nullptr) {
|
||||
i->prev->next = i->next;
|
||||
if (i->prev != SHM_NULL) {
|
||||
ShmItem *prev_i;
|
||||
ref(i->prev, &prev_i);
|
||||
prev_i->next = i->next;
|
||||
}
|
||||
if (i->next != nullptr) {
|
||||
i->next->prev = i->prev;
|
||||
if (i->next != SHM_NULL) {
|
||||
ShmItem *next_i;
|
||||
ref(i->next, &next_i);
|
||||
next_i->prev = i->prev;
|
||||
}
|
||||
if (i->prev == nullptr) {
|
||||
_first = i->next;
|
||||
if (i->prev == SHM_NULL) {
|
||||
*_first = i->next;
|
||||
}
|
||||
i->next = _free_list;
|
||||
if (_free_list != nullptr) {
|
||||
_free_list->prev = i;
|
||||
i->next = *_free_list;
|
||||
if (*_free_list != SHM_NULL) {
|
||||
ShmItem *fl;
|
||||
ref(*_free_list, &fl);
|
||||
fl->prev = p_i;
|
||||
}
|
||||
i->prev = nullptr;
|
||||
_free_list = i;
|
||||
i->prev = SHM_NULL;
|
||||
*_free_list = p_i;
|
||||
|
||||
*__first = _first;
|
||||
*__free_list = _free_list;
|
||||
leaveCritical();
|
||||
}
|
||||
|
||||
inline void *ref(int place)
|
||||
{
|
||||
return reinterpret_cast<char *>(_mem) + place;
|
||||
}
|
||||
|
||||
void enterCritical() {
|
||||
if (_in_critical > 0) {
|
||||
_in_critical++;
|
||||
@@ -188,25 +216,28 @@ public:
|
||||
size_t slots_size = sizeof(ShmPlace) * SHM_MAX_SLOTS;
|
||||
size += slots_size;
|
||||
|
||||
_sem = sem_open(_sem_name, O_CREAT);
|
||||
if (owner) {
|
||||
_sem = sem_open(_sem_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, 0);
|
||||
_shm_fd = shm_open(name, O_CREAT | O_RDWR, 0600);
|
||||
ftruncate(_shm_fd, size);
|
||||
} else {
|
||||
_sem = sem_open(_sem_name, O_RDWR, S_IRUSR | S_IWUSR, 0);
|
||||
_shm_fd = shm_open(name, O_RDWR, 0600);
|
||||
}
|
||||
_size = size;
|
||||
_mem = mmap(nullptr, _size, PROT_READ|PROT_WRITE, MAP_SHARED, _shm_fd, 0);
|
||||
|
||||
_slots = reinterpret_cast <ShmPlace *>(reinterpret_cast<char *>(_mem) + sizeof(size_t) + sizeof(ShmItem *) + sizeof(ShmItem *));
|
||||
|
||||
_slots = reinterpret_cast <ShmPlace *>(reinterpret_cast<char *>(_mem) + sizeof(size_t) + sizeof(ShmPlace) + sizeof(ShmPlace));
|
||||
_used = reinterpret_cast<size_t *>(_mem);
|
||||
|
||||
__first = reinterpret_cast<ShmItem **>(reinterpret_cast<char *>(_mem) + sizeof(size_t));
|
||||
|
||||
__free_list = reinterpret_cast<ShmItem **>(reinterpret_cast<char *>(_mem) + sizeof(size_t) + sizeof(ShmItem *));
|
||||
_first = reinterpret_cast<ShmPlace *>(reinterpret_cast<char *>(_mem) + sizeof(size_t));
|
||||
_free_list = reinterpret_cast<ShmPlace *>(reinterpret_cast<char *>(_mem) + sizeof(size_t) + sizeof(ShmPlace));
|
||||
|
||||
_owner = owner;
|
||||
|
||||
if (_owner) {
|
||||
*__first = nullptr;
|
||||
*__free_list = nullptr;
|
||||
*_first = SHM_NULL;
|
||||
*_free_list = SHM_NULL;
|
||||
*_used = sizeof(size_t) + sizeof(ShmItem *) + sizeof(ShmItem *) + slots_size;
|
||||
sem_post(_sem);
|
||||
}
|
||||
@@ -320,26 +351,38 @@ Shm::~Shm()
|
||||
delete _shm_api;
|
||||
}
|
||||
|
||||
template<class T> void ref(Shm *shm, int place, T **p)
|
||||
{
|
||||
*p = reinterpret_cast<T *>(shm->ref(place));
|
||||
}
|
||||
|
||||
|
||||
void ShmSem::post() {
|
||||
sem_post(reinterpret_cast<sem_t *>(_sem));
|
||||
}
|
||||
|
||||
void ShmSem::wait() {
|
||||
sem_wait(reinterpret_cast<sem_t *>(_sem));
|
||||
int r = sem_wait(reinterpret_cast<sem_t *>(_sem));
|
||||
if (r != 0) {
|
||||
fprintf(stderr, "sem_wait error: %d, %s\n", errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
bool ShmSem::trywait() {
|
||||
return sem_trywait(reinterpret_cast<sem_t *>(_sem)) == 0;
|
||||
int r = sem_trywait(reinterpret_cast<sem_t *>(_sem));
|
||||
if (r != 0 && r != EAGAIN) {
|
||||
fprintf(stderr, "sem_wait error: %d, %s\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
return (r == 0);
|
||||
}
|
||||
|
||||
ShmSem::ShmSem(const char *n, bool owner) {
|
||||
_name = strdup(n);
|
||||
_sem = reinterpret_cast<void *>(sem_open(n, O_CREAT));
|
||||
|
||||
sem_t *s;
|
||||
if (owner) {
|
||||
s = sem_open(n, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, 0);
|
||||
} else {
|
||||
s = sem_open(n, O_RDWR, S_IRUSR | S_IWUSR, 0);
|
||||
}
|
||||
_sem = reinterpret_cast<void *>(s);
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,9 @@ public:
|
||||
~Shm();
|
||||
};
|
||||
|
||||
template <class T> void ref(Shm *shm, int place, T **p);
|
||||
template <class T> inline void ref(Shm *shm, int place, T **p)
|
||||
{
|
||||
*p = reinterpret_cast<T *>(shm->ref(place));
|
||||
}
|
||||
|
||||
#endif // SHM_H
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "shmqueue.h"
|
||||
#include <string.h>
|
||||
|
||||
ShmQueue::ShmQueue(Shm *shm, ShmSlot slot, bool owner)
|
||||
{
|
||||
@@ -43,15 +44,15 @@ int ShmQueue::depth()
|
||||
return d;
|
||||
}
|
||||
|
||||
void ShmQueue::enqueue(int cmd, const QString &json_data)
|
||||
void ShmQueue::enqueue(int cmd, const std::string &json_data)
|
||||
{
|
||||
QByteArray b(json_data.toUtf8());
|
||||
size_t jd_size = json_data.size();
|
||||
int str_place = _shm->alloc(jd_size + 1);
|
||||
|
||||
int str_place = _shm->alloc(b.size() + 1);
|
||||
char *s;
|
||||
ref(_shm, str_place, &s);
|
||||
memcpy(s, b.constData(), b.size());
|
||||
s[b.size()] = '\0';
|
||||
memcpy(s, json_data.data(), jd_size);
|
||||
s[jd_size] = '\0';
|
||||
|
||||
int item_place = _shm->alloc(sizeof(ShmQueueItem));
|
||||
ShmQueueItem *item;
|
||||
@@ -60,6 +61,11 @@ void ShmQueue::enqueue(int cmd, const QString &json_data)
|
||||
item->data_place = str_place;
|
||||
item->prev = _queue->last;
|
||||
item->next = SHM_NULL;
|
||||
if (_queue->last != SHM_NULL) {
|
||||
ShmQueueItem *last_i;
|
||||
ref(_shm, _queue->last, &last_i);
|
||||
last_i->next = item_place;
|
||||
}
|
||||
|
||||
_shm->lock();
|
||||
_queue->last = item_place;
|
||||
@@ -71,7 +77,13 @@ void ShmQueue::enqueue(int cmd, const QString &json_data)
|
||||
_queue_sem->post();
|
||||
}
|
||||
|
||||
bool ShmQueue::dequeue(int &cmd, QString &json_data, bool wait)
|
||||
void ShmQueue::enqueue(int cmd)
|
||||
{
|
||||
std::string s;
|
||||
enqueue(cmd, s);
|
||||
}
|
||||
|
||||
bool ShmQueue::dequeue(int &cmd, std::string &json_data, bool wait)
|
||||
{
|
||||
if (wait) {
|
||||
_queue_sem->wait();
|
||||
@@ -96,7 +108,7 @@ bool ShmQueue::dequeue(int &cmd, QString &json_data, bool wait)
|
||||
ShmPlace data_place = item->data_place;
|
||||
char *data;
|
||||
ref(_shm, data_place, &data);
|
||||
json_data = QString::fromUtf8(data, strlen(data));
|
||||
json_data = data;
|
||||
|
||||
_shm->free(data_place);
|
||||
cmd = item->cmd;
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
#define SHMQUEUE_H
|
||||
|
||||
#include "shm.h"
|
||||
#include <QString>
|
||||
|
||||
#define COMMAND_SLOT 1
|
||||
#define EVENT_SLOT 2
|
||||
#include <string>
|
||||
|
||||
typedef struct __ShmQueueItem__
|
||||
{
|
||||
@@ -40,8 +37,9 @@ public:
|
||||
int depth();
|
||||
|
||||
public:
|
||||
bool dequeue(int &cmd, QString &json_data, bool wait = false);
|
||||
void enqueue(int cmd, const QString &json_data);
|
||||
bool dequeue(int &cmd, std::string &json_data, bool wait = false);
|
||||
void enqueue(int cmd, const std::string &json_data);
|
||||
void enqueue(int cmd);
|
||||
|
||||
public:
|
||||
ShmQueue(Shm *shm, ShmSlot slot, bool owner);
|
||||
|
||||
Reference in New Issue
Block a user