-
This commit is contained in:
7
Makefile
Normal file
7
Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
all:
|
||||
@echo "oke"
|
||||
|
||||
clean:
|
||||
rm -f *.rkt~
|
||||
(cd private;rm -f *.rkt~)
|
||||
1
rktwebview/.gitignore
vendored
1
rktwebview/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
*.user
|
||||
@@ -1,123 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(rktwebview LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(GIT_EXECUTABLE git)
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
|
||||
set(WEBVIEW_BUILD_STATIC_LIBRARY ON)
|
||||
set(WEBVIEW_WEBKITGTK_API "6.0")
|
||||
#set(WEBVIEW_WEBKITGTK_PREFERRED_API_LIST webkitgtk-6.0)
|
||||
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
set(LIBKIND "d")
|
||||
else()
|
||||
set(LIBKIND "r")
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(LIBEXT lib)
|
||||
set(LIBPRE )
|
||||
else()
|
||||
set(LIBEXT a)
|
||||
set(LIBPRE lib)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
# using Clang
|
||||
add_compile_options(-fPIC)
|
||||
set(CFLAGS_ENV "CFLAGS=-fPIC")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
# using GCC
|
||||
add_compile_options(-fPIC)
|
||||
set(CFLAGS_ENV "CFLAGS=-fPIC")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
# using Intel C++
|
||||
set(CFLAGS_ENV "")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(CFLAGS_ENV "")
|
||||
endif()
|
||||
|
||||
if(NOT(EXISTS ./deps))
|
||||
file(MAKE_DIRECTORY ./deps)
|
||||
endif()
|
||||
|
||||
function(git_dep dir dep)
|
||||
if(EXISTS ${rktwebview_SOURCE_DIR}/deps/${dir})
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} pull
|
||||
COMMAND_ECHO STDOUT
|
||||
WORKING_DIRECTORY ${rktwebview_SOURCE_DIR}/deps/${dir}
|
||||
)
|
||||
else()
|
||||
message("Executing git clone...")
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} clone ${dep} ${rktwebview_SOURCE_DIR}/deps/${dir}
|
||||
COMMAND_ECHO STDOUT
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
git_dep(webview https://github.com/webview/webview.git)
|
||||
add_subdirectory(deps/webview)
|
||||
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(GTK REQUIRED gtk+-3.0)
|
||||
|
||||
include_directories(${GTK_INCLUDE_DIRS})
|
||||
message("${GTK_INCLUDE_DIRS}")
|
||||
link_directories(${GTK_LIBRARY_DIRS})
|
||||
|
||||
pkg_check_modules(GTKWEBVIEW REQUIRED webkit2gtk-4.1)
|
||||
include_directories(${GTKWEBVIEW_INCLUDE_DIRS})
|
||||
message("${GTKWEBVIEW_INCLUDE_DIRS}")
|
||||
link_directories(${GTKWEBVIEW_LIBRARY_DIRS})
|
||||
endif()
|
||||
|
||||
include_directories(deps/webview/core/include)
|
||||
include_directories(deps/webview/build/Release/_deps/microsoft_web_webview2-src/build/native/include)
|
||||
link_directories(build/Release/deps/webview/core)
|
||||
link_directories(build/Release)
|
||||
|
||||
add_library(rktwebview SHARED
|
||||
rktwebview_global.h
|
||||
rktwebview.cpp
|
||||
rktwebview.h
|
||||
|
||||
json.h
|
||||
json.cpp
|
||||
)
|
||||
|
||||
add_executable(rktwebview_test
|
||||
main.cpp
|
||||
|
||||
rktwebview_global.h
|
||||
rktwebview.cpp
|
||||
rktwebview.h
|
||||
|
||||
json.h
|
||||
json.cpp
|
||||
)
|
||||
|
||||
#add_dependencies(rktwebview webview)
|
||||
|
||||
target_link_libraries(rktwebview webview_core_static)
|
||||
#target_link_libraries(rktwebview_test rktwebview)
|
||||
target_link_libraries(rktwebview_test webview_core_static)
|
||||
|
||||
target_compile_definitions(rktwebview PRIVATE RKTWEBVIEW_LIBRARY)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
target_link_libraries(rktwebview ${GTK_LIBRARIES} ${GTKWEBVIEW_LIBRARIES})
|
||||
target_link_libraries(rktwebview_test ${GTK_LIBRARIES} ${GTKWEBVIEW_LIBRARIES})
|
||||
endif()
|
||||
|
||||
@@ -1,505 +0,0 @@
|
||||
#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 ) );
|
||||
}
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
#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 );
|
||||
|
||||
#ifdef Bool
|
||||
#undef Bool
|
||||
#endif
|
||||
|
||||
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,37 +0,0 @@
|
||||
#include "rktwebview.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
rkt_webview_t *wv = rkt_create_webview();
|
||||
result_t r = rkt_webview_navigate(wv, "https://wikipedia.org");
|
||||
|
||||
rkt_webview_t *wv1 = nullptr;
|
||||
//result_t r = rkt_set_html(wv, "<html><head><title>He daar!</title></head><body><h1>He daar!</h1></body>");
|
||||
printf("Navigate: result = %d\n", r);
|
||||
int i = 0;
|
||||
while(rkt_webview_valid(wv)) {
|
||||
printf("Waiting...%d\n", i);
|
||||
#ifdef USE_WIN_THREADS
|
||||
Sleep(1000);
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
usleep(1000 * 1000);
|
||||
#endif
|
||||
i += 1;
|
||||
if (i > 5) {
|
||||
item_t item = rkt_webview_call_js(wv, "{ window.location = 'https://dijkewijk.nl'; return 42; }");
|
||||
printf("%d, %s\n", item.context, item.data);
|
||||
rkt_webview_destroy_item(item);
|
||||
item_t item1 = rkt_webview_call_js(wv, "{ return stuffwrong + 5 }");
|
||||
printf("%d, %s\n", item1.context, item1.data);
|
||||
rkt_webview_destroy_item(item1);
|
||||
}
|
||||
if (i == 16) {
|
||||
wv1 = rkt_create_webview();
|
||||
result_t r = rkt_webview_navigate(wv, "https://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html");
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,549 +0,0 @@
|
||||
#include "rktwebview.h"
|
||||
|
||||
#include <webview/webview.h>
|
||||
#include "json.h"
|
||||
|
||||
static void queue_init(queue_t *q);
|
||||
static void enqueue(queue_t *q, item_t item);
|
||||
static bool dequeue(queue_t *q, item_t *item);
|
||||
static int queue_length(queue_t *q);
|
||||
static void queue_destroy(queue_t *q);
|
||||
static void free_item(item_t i);
|
||||
|
||||
static void mutex_lock(rkt_webview_t *);
|
||||
static void mutex_unlock(rkt_webview_t *);
|
||||
static void thread_sleep_ms(rkt_webview_t *, int ms);
|
||||
|
||||
static void handle_event(const char *id, const char *data, void *_wv);
|
||||
static void handle_js_call(const char *id, const char *data, void *_wv);
|
||||
|
||||
static void dispatcher(webview_t w, void *args);
|
||||
static result_t do_dispatch(rkt_webview_t *, item_t item);
|
||||
|
||||
#ifdef USE_WIN_THREADS
|
||||
static DWORD webviewThread(LPVOID args)
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
static void *webviewThread(void *args)
|
||||
#endif
|
||||
{
|
||||
rkt_webview_t *wv = (rkt_webview_t *) args;
|
||||
mutex_lock(wv);
|
||||
webview_t w = webview_create(0, NULL);
|
||||
wv->webview_handle = w;
|
||||
wv->handle_set = true;
|
||||
webview_bind(w, "web_ui_wire_handle_event", handle_event, wv);
|
||||
webview_bind(w, "rkt_webview_call_js_result", handle_js_call, wv);
|
||||
mutex_unlock(wv);
|
||||
webview_run(w);
|
||||
webview_destroy(w);
|
||||
mutex_lock(wv);
|
||||
wv->webview_handle = NULL;
|
||||
wv->handle_destroyed = true;
|
||||
mutex_unlock(wv);
|
||||
#ifdef USE_WIN_THREADS
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_WIN_THREADS
|
||||
static DWORD queueGuardThread(LPVOID args)
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
static void *queueGuardThread(void *args)
|
||||
#endif
|
||||
{
|
||||
rkt_webview_t *wv = (rkt_webview_t *) args;
|
||||
|
||||
auto handle_ok = [](rkt_webview_t *wv) {
|
||||
mutex_lock(wv);
|
||||
bool ok = !wv->handle_destroyed;
|
||||
mutex_unlock(wv);
|
||||
return ok;
|
||||
};
|
||||
|
||||
while(handle_ok(wv)) {
|
||||
mutex_lock(wv);
|
||||
if (wv->queue_callback != NULL) {
|
||||
while(queue_length(&wv->from_webview) > 0) {
|
||||
item_t item;
|
||||
dequeue(&wv->from_webview, &item);
|
||||
wv->queue_callback(wv->queue_callback_id, item);
|
||||
}
|
||||
}
|
||||
mutex_unlock(wv);
|
||||
thread_sleep_ms(wv, 10);
|
||||
}
|
||||
|
||||
#ifdef USE_WIN_THREADS
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
RKTWEBVIEW_EXPORT rkt_webview_t *rkt_create_webview()
|
||||
{
|
||||
rkt_webview_t *wv = (rkt_webview_t *) malloc(sizeof(rkt_webview_t));
|
||||
if (wv == NULL) { return NULL; }
|
||||
|
||||
#ifdef USE_WIN_THREADS
|
||||
wv->mutex = CreateMutex(NULL, FALSE, NULL);
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
wv->mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
wv->handle_set = false;
|
||||
wv->handle_destroyed = false;
|
||||
queue_init(&wv->to_webview);
|
||||
queue_init(&wv->from_webview);
|
||||
wv->webview_handle = NULL;
|
||||
wv->queue_callback = NULL;
|
||||
wv->js_call_nr = 0;
|
||||
wv->js_evaluated = new std::map<int, std::string>();
|
||||
|
||||
#ifdef USE_WIN_THREADS
|
||||
wv->webview_thread = CreateThread(
|
||||
NULL,
|
||||
0,
|
||||
webviewThread,
|
||||
wv,
|
||||
0,
|
||||
&wv->webview_thread_id
|
||||
);
|
||||
wv->queue_guard_thread = CreateThread(
|
||||
NULL,
|
||||
0,
|
||||
queueGuardThread,
|
||||
wv,
|
||||
0,
|
||||
&wv->queue_guard_thread_id
|
||||
);
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
wv->webview_thread_id = pthread_create(&wv->webview_thread, NULL, webviewThread, wv);
|
||||
wv->queue_guard_thread_id = pthread_create(&wv->queue_guard_thread, NULL, queueGuardThread, wv);
|
||||
#endif
|
||||
bool go_on = true;
|
||||
while(go_on) {
|
||||
mutex_lock(wv);
|
||||
go_on = (wv->handle_set == false);
|
||||
mutex_unlock(wv);
|
||||
if (go_on) {
|
||||
thread_sleep_ms(wv, 10);
|
||||
}
|
||||
}
|
||||
printf("handle_set = %d\n", wv->handle_set);
|
||||
return wv;
|
||||
}
|
||||
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_navigate(rkt_webview_t *wv, const char *url)
|
||||
{
|
||||
item_t item = { CONTEXT_NAVIGATE, const_cast<char *>(url) };
|
||||
return do_dispatch(wv, item);
|
||||
}
|
||||
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_set_html(rkt_webview_t *wv, const char *html)
|
||||
{
|
||||
item_t item = { CONTEXT_SET_HTML, const_cast<char *>(html) };
|
||||
return do_dispatch(wv, item);
|
||||
}
|
||||
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_run_js(rkt_webview_t *wv, const char *js)
|
||||
{
|
||||
item_t item = { CONTEXT_EVAL_JS, const_cast<char *>(js) };
|
||||
return do_dispatch(wv, item);
|
||||
}
|
||||
|
||||
RKTWEBVIEW_EXPORT item_t rkt_webview_call_js(rkt_webview_t *wv, const char *js)
|
||||
{
|
||||
mutex_lock(wv);
|
||||
wv->js_call_nr += 1;
|
||||
int call_nr = wv->js_call_nr;
|
||||
mutex_unlock(wv);
|
||||
char buf[30];
|
||||
sprintf(buf, "%d", call_nr);
|
||||
|
||||
std::string _js = std::string("{ let f = function() { ") + js + " };" +
|
||||
" let call_nr = " + buf + ";" +
|
||||
" try { let r = { result: f() };" +
|
||||
" rkt_webview_call_js_result(call_nr, true, JSON.stringify(r)); " +
|
||||
" } catch(e) {" +
|
||||
" rkt_webview_call_js_result(call_nr, false, e.message); " +
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
|
||||
item_t item = { CONTEXT_CALL_JS, strdup(_js.c_str()) };
|
||||
result_t r = do_dispatch(wv, item);
|
||||
if (r == error) {
|
||||
item_t item = { CONTEXT_INVALID , NULL };
|
||||
return item;
|
||||
}
|
||||
|
||||
auto has_result = [](rkt_webview_t *wv, int call_nr) {
|
||||
mutex_lock(wv);
|
||||
bool result = false;
|
||||
if (wv->js_evaluated->find(call_nr) != wv->js_evaluated->end()) {
|
||||
mutex_unlock(wv);
|
||||
return true;
|
||||
} else {
|
||||
mutex_unlock(wv);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
while(!has_result(wv, call_nr)) {
|
||||
thread_sleep_ms(wv, 2);
|
||||
}
|
||||
|
||||
free_item(item);
|
||||
|
||||
mutex_lock(wv);
|
||||
JSON j = JSON::Load(wv->js_evaluated->at(call_nr), [](std::string) { });
|
||||
bool result_oke = j[1].toBool();
|
||||
std::string data = j[2].toString();
|
||||
|
||||
item_t result_item;
|
||||
if (result_oke) {
|
||||
result_item = { CONTEXT_CALL_JS, strdup(data.c_str()) };
|
||||
} else {
|
||||
result_item = { CONTEXT_INVALID, strdup(data.c_str()) };
|
||||
}
|
||||
wv->js_evaluated->erase(call_nr);
|
||||
mutex_unlock(wv);
|
||||
|
||||
return result_item;
|
||||
}
|
||||
|
||||
RKTWEBVIEW_EXPORT bool rkt_webview_valid(rkt_webview_t *handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return false;
|
||||
} else {
|
||||
bool valid;
|
||||
mutex_lock(handle);
|
||||
valid = (!handle->handle_destroyed && handle->handle_set);
|
||||
mutex_unlock(handle);
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
RKTWEBVIEW_EXPORT result_t rkt_destroy_webview(rkt_webview_t *wv)
|
||||
{
|
||||
if (rkt_webview_valid(wv)) {
|
||||
webview_error_t e = webview_terminate(WEBVIEW_HANDLE(wv));
|
||||
result_t r = (e >= 0) ? oke : error;
|
||||
if (r == oke) {
|
||||
queue_destroy(&wv->to_webview);
|
||||
queue_destroy(&wv->from_webview);
|
||||
#ifdef USE_WIN_THREADS
|
||||
WaitForSingleObject(wv->webview_thread, 2000); // Give up after 2s.
|
||||
CloseHandle(wv->webview_thread);
|
||||
WaitForSingleObject(wv->queue_guard_thread, 2000); // Give up after 2s.
|
||||
CloseHandle(wv->queue_guard_thread);
|
||||
CloseHandle(wv->mutex);
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
pthread_join(wv->webview_thread, NULL);
|
||||
pthread_join(wv->queue_guard_thread, NULL);
|
||||
#endif
|
||||
delete wv->js_evaluated;
|
||||
free(wv);
|
||||
}
|
||||
return r;
|
||||
} else {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
RKTWEBVIEW_EXPORT int rkt_webview_pending_events(rkt_webview_t *wv)
|
||||
{
|
||||
mutex_lock(wv);
|
||||
int len = queue_length(&wv->from_webview);
|
||||
mutex_unlock(wv);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
RKTWEBVIEW_EXPORT item_t rkt_webview_get_event(rkt_webview_t *wv)
|
||||
{
|
||||
item_t i;
|
||||
mutex_lock(wv);
|
||||
if (queue_length(&wv->from_webview) > 0) {
|
||||
dequeue(&wv->from_webview, &i);
|
||||
} else {
|
||||
i.context = CONTEXT_INVALID;
|
||||
i.data = NULL;
|
||||
}
|
||||
mutex_unlock(wv);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
RKTWEBVIEW_EXPORT void rkt_webview_destroy_item(item_t item)
|
||||
{
|
||||
free_item(item);
|
||||
}
|
||||
|
||||
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_devtools(rkt_webview_t *wv)
|
||||
{
|
||||
item_t item = { CONTEXT_OPEN_DEVTOOLS, const_cast<char *>("") };
|
||||
return do_dispatch(wv, item);
|
||||
}
|
||||
|
||||
RKTWEBVIEW_EXPORT reason_t rkt_webview_last_reason(rkt_webview_t *wv)
|
||||
{
|
||||
return wv->last_reason;
|
||||
}
|
||||
|
||||
RKTWEBVIEW_EXPORT void rkt_webview_register_queue_callback(rkt_webview_t *wv, int id, void (*cb)(int, item_t))
|
||||
{
|
||||
mutex_lock(wv);
|
||||
wv->queue_callback = cb;
|
||||
wv->queue_callback_id = id;
|
||||
mutex_unlock(wv);
|
||||
}
|
||||
|
||||
static void handle_event(const char *id, const char *data, void *_wv)
|
||||
{
|
||||
rkt_webview_t *wv = static_cast<rkt_webview_t *>(_wv);
|
||||
mutex_lock(wv);
|
||||
|
||||
JSON json;
|
||||
json["id"] = id;
|
||||
json["data"] = data;
|
||||
std::string s = json.dump();
|
||||
|
||||
item_t item;
|
||||
item.context = CONTEXT_BOUND_EVENT;
|
||||
item.data = const_cast<char *>(s.c_str());
|
||||
|
||||
enqueue(&wv->from_webview, item);
|
||||
mutex_unlock(wv);
|
||||
}
|
||||
|
||||
static void handle_js_call(const char *id, const char *data, void *_wv)
|
||||
{
|
||||
rkt_webview_t *wv = static_cast<rkt_webview_t *>(_wv);
|
||||
mutex_lock(wv);
|
||||
std::string d(data);
|
||||
JSON j = JSON::Load(d, [](std::string err) { });
|
||||
int call_nr = j[0].toInt();
|
||||
wv->js_evaluated->insert(std::pair<int, std::string>(call_nr, std::string(data)));
|
||||
mutex_unlock(wv);
|
||||
}
|
||||
|
||||
void dispatcher(webview_t w, void *args)
|
||||
{
|
||||
rkt_webview_t *wv = reinterpret_cast<rkt_webview_t *>(args);
|
||||
item_t item;
|
||||
mutex_lock(wv);
|
||||
if (dequeue(&wv->to_webview, &item)) {
|
||||
if (item.context == CONTEXT_SET_HTML) {
|
||||
webview_error_t e = webview_set_html(w, item.data);
|
||||
wv->wv_res = static_cast<int>(e);
|
||||
wv->last_result = (e >= 0) ? oke : error;
|
||||
wv->last_reason = (wv->last_result == oke) ? reason_oke : reason_set_html_failed;
|
||||
} else if (item.context == CONTEXT_NAVIGATE) {
|
||||
webview_error_t e = webview_navigate(w, item.data);
|
||||
wv->wv_res = static_cast<int>(e);
|
||||
wv->last_result = (e >= 0) ? oke : error;
|
||||
wv->last_reason = (wv->last_result == oke) ? reason_oke : reason_set_navigate_failed;
|
||||
} else if (item.context == CONTEXT_EVAL_JS || item.context == CONTEXT_CALL_JS) {
|
||||
webview_error_t e = webview_eval(w, item.data);
|
||||
wv->wv_res = static_cast<int>(e);
|
||||
wv->last_result = (e >= 0) ? oke : error;
|
||||
wv->last_reason = (wv->last_result == oke) ? reason_oke : reason_eval_js_failed;
|
||||
} else if (item.context == CONTEXT_OPEN_DEVTOOLS) {
|
||||
bool handled = false;
|
||||
#ifdef _WIN32
|
||||
void *handle = webview_get_native_handle(wv->webview_handle, WEBVIEW_NATIVE_HANDLE_KIND_BROWSER_CONTROLLER);
|
||||
ICoreWebView2Controller *c = static_cast<ICoreWebView2Controller *>(handle);
|
||||
ICoreWebView2 *cwv = nullptr;
|
||||
HRESULT r = c->get_CoreWebView2(&cwv);
|
||||
if (cwv != nullptr) {
|
||||
r = cwv->OpenDevToolsWindow();
|
||||
if (r == S_OK) {
|
||||
wv->last_result = oke;
|
||||
wv->last_reason = reason_oke;
|
||||
} else {
|
||||
wv->last_result = error;
|
||||
wv->last_reason = reason_no_devtools_on_platform;
|
||||
}
|
||||
} else {
|
||||
wv->last_result = error;
|
||||
wv->last_reason = reason_no_devtools_on_platform;
|
||||
}
|
||||
#endif
|
||||
if (!handled) {
|
||||
wv->last_result = error;
|
||||
wv->last_reason = reason_no_devtools_on_platform;
|
||||
}
|
||||
} else {
|
||||
wv->last_result = error;
|
||||
wv->last_reason = reason_no_delegate_for_context;
|
||||
}
|
||||
}
|
||||
mutex_unlock(wv);
|
||||
free_item(item);
|
||||
}
|
||||
|
||||
result_t do_dispatch(rkt_webview_t *wv, item_t item)
|
||||
{
|
||||
webview_t w = WEBVIEW_HANDLE(wv);
|
||||
|
||||
mutex_lock(wv);
|
||||
enqueue(&wv->to_webview, item);
|
||||
wv->last_reason = reason_no_result_yet;
|
||||
mutex_unlock(wv);
|
||||
|
||||
webview_error_t e = webview_dispatch(w, dispatcher, wv);
|
||||
|
||||
reason_t lr;
|
||||
result_t r;
|
||||
|
||||
if (e >= 0) {
|
||||
bool go_on = true;
|
||||
while(go_on) {
|
||||
mutex_lock(wv);
|
||||
r = wv->last_result;
|
||||
lr = wv->last_reason;
|
||||
mutex_unlock(wv);
|
||||
if (lr != reason_no_result_yet) {
|
||||
go_on = false;
|
||||
} else {
|
||||
thread_sleep_ms(wv, 10);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
} else {
|
||||
switch(e) {
|
||||
case WEBVIEW_ERROR_MISSING_DEPENDENCY: lr = reason_webview_missing_dependency;
|
||||
break;
|
||||
case WEBVIEW_ERROR_CANCELED: lr = reason_webview_canceled;
|
||||
break;
|
||||
case WEBVIEW_ERROR_INVALID_STATE: lr = reason_webview_invalid_state;
|
||||
break;
|
||||
case WEBVIEW_ERROR_INVALID_ARGUMENT: lr = reason_webview_invalid_argument;
|
||||
break;
|
||||
case WEBVIEW_ERROR_UNSPECIFIED: lr = reason_webview_unspecified;
|
||||
break;
|
||||
default:
|
||||
lr = reason_webview_dispatch_failed;
|
||||
}
|
||||
r = error;
|
||||
}
|
||||
|
||||
printf("error = %d, reason = %d\n", r, lr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Supporting functions
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
void queue_init(queue_t *q)
|
||||
{
|
||||
q->length = 0;
|
||||
q->first = NULL;
|
||||
q->last = NULL;
|
||||
}
|
||||
|
||||
void enqueue(queue_t *q, item_t item)
|
||||
{
|
||||
queue_item_t *itm = (queue_item_t *) malloc(sizeof(queue_item_t));
|
||||
itm->item.context = item.context;
|
||||
itm->item.data = strdup(item.data);
|
||||
if (q->first == NULL) {
|
||||
q->first = itm;
|
||||
q->last = itm;
|
||||
itm->prev = NULL;
|
||||
itm->next = NULL;
|
||||
q->length = 1;
|
||||
} else {
|
||||
itm->prev = q->last;
|
||||
itm->next = NULL;
|
||||
q->last->next = itm;
|
||||
q->last = itm;
|
||||
q->length += 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool dequeue(queue_t *q, item_t *item)
|
||||
{
|
||||
if (q->length == 0) {
|
||||
item->context = CONTEXT_INVALID;
|
||||
item->data = NULL;
|
||||
return false;
|
||||
} else {
|
||||
queue_item_t *itm = q->first;
|
||||
q->first = q->first->next;
|
||||
q->length -= 1;
|
||||
if (q->length == 0) {
|
||||
q->first = NULL;
|
||||
q->last = NULL;
|
||||
}
|
||||
item->context = itm->item.context;
|
||||
item->data = itm->item.data;
|
||||
free(itm);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int queue_length(queue_t *q)
|
||||
{
|
||||
return q->length;
|
||||
}
|
||||
|
||||
void queue_destroy(queue_t *q)
|
||||
{
|
||||
item_t i;
|
||||
while(dequeue(q, &i)) {
|
||||
free(i.data);
|
||||
}
|
||||
}
|
||||
|
||||
void free_item(item_t item)
|
||||
{
|
||||
free(item.data);
|
||||
}
|
||||
|
||||
|
||||
void mutex_lock(rkt_webview_t *wv)
|
||||
{
|
||||
#ifdef USE_WIN_THREADS
|
||||
WaitForSingleObject(wv->mutex, INFINITE);
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
pthread_mutex_lock(&wv->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void mutex_unlock(rkt_webview_t *wv)
|
||||
{
|
||||
#ifdef USE_WIN_THREADS
|
||||
ReleaseMutex(wv->mutex);
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
pthread_mutex_unlock(&wv->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void thread_sleep_ms(rkt_webview_t *wv, int ms)
|
||||
{
|
||||
#ifdef USE_WIN_THREADS
|
||||
Sleep(ms);
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
usleep(ms * 1000);
|
||||
#endif
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
#ifndef RKTWEBVIEW_H
|
||||
#define RKTWEBVIEW_H
|
||||
|
||||
#include "rktwebview_global.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
typedef HANDLE mutex_t;
|
||||
typedef HANDLE thread_t;
|
||||
typedef DWORD thread_id_t;
|
||||
#define USE_WIN_THREADS
|
||||
#endif
|
||||
|
||||
#ifdef __linux
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
typedef pthread_t thread_t;
|
||||
typedef pthread_mutex_t mutex_t;
|
||||
typedef int thread_id_t;
|
||||
#define USE_PTHREADS
|
||||
#endif
|
||||
|
||||
#define CONTEXT_INVALID 0
|
||||
#define CONTEXT_BOUND_EVENT 1
|
||||
#define CONTEXT_WINDOW_RESIZE 2
|
||||
#define CONTEXT_WINDOW_MOVE 3
|
||||
#define CONTEXT_WINDOW_CAN_CLOSE 4
|
||||
#define CONTEXT_WINDOW_CLOSED 5
|
||||
#define CONTEXT_SET_HTML 6
|
||||
#define CONTEXT_NAVIGATE 7
|
||||
#define CONTEXT_EVAL_JS 8
|
||||
#define CONTEXT_OPEN_DEVTOOLS 9
|
||||
#define CONTEXT_CALL_JS 10
|
||||
|
||||
typedef enum {
|
||||
oke = 0,
|
||||
error = 1
|
||||
} result_t;
|
||||
|
||||
typedef enum {
|
||||
reason_no_result_yet = -1,
|
||||
reason_oke = 0,
|
||||
reason_set_html_failed = 1,
|
||||
reason_set_navigate_failed = 2,
|
||||
reason_eval_js_failed = 3,
|
||||
reason_no_devtools_on_platform = 4,
|
||||
reason_no_delegate_for_context = 5,
|
||||
reason_webview_missing_dependency = 6,
|
||||
reason_webview_canceled = 7,
|
||||
reason_webview_invalid_state = 8,
|
||||
reason_webview_invalid_argument = 9,
|
||||
reason_webview_unspecified = 10,
|
||||
reason_webview_dispatch_failed = 11
|
||||
} reason_t;
|
||||
|
||||
typedef struct {
|
||||
int context;
|
||||
char *data;
|
||||
} item_t;
|
||||
|
||||
typedef struct _item {
|
||||
item_t item;
|
||||
struct _item *next;
|
||||
struct _item *prev;
|
||||
} queue_item_t;
|
||||
|
||||
typedef struct {
|
||||
queue_item_t *first;
|
||||
queue_item_t *last;
|
||||
int length;
|
||||
} queue_t;
|
||||
|
||||
typedef struct {
|
||||
void *webview_handle;
|
||||
mutex_t mutex;
|
||||
thread_t webview_thread;
|
||||
thread_id_t webview_thread_id;
|
||||
queue_t to_webview;
|
||||
queue_t from_webview;
|
||||
int wv_res;
|
||||
result_t last_result;
|
||||
reason_t last_reason;
|
||||
bool handle_set;
|
||||
bool handle_destroyed;
|
||||
void (*queue_callback)(int id, item_t data);
|
||||
int queue_callback_id;
|
||||
thread_t queue_guard_thread;
|
||||
thread_id_t queue_guard_thread_id;
|
||||
std::map<int, std::string> *js_evaluated;
|
||||
int js_call_nr;
|
||||
} rkt_webview_t;
|
||||
|
||||
#define WEBVIEW_HANDLE(wv) reinterpret_cast<webview_t>(wv->webview_handle)
|
||||
|
||||
extern "C" {
|
||||
|
||||
RKTWEBVIEW_EXPORT rkt_webview_t *rkt_create_webview();
|
||||
RKTWEBVIEW_EXPORT result_t rkt_destroy_webview(rkt_webview_t *wv);
|
||||
|
||||
RKTWEBVIEW_EXPORT result_t rkt_close_webview(rkt_webview_t *handle);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_navigate(rkt_webview_t *handle, const char *url);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_set_html(rkt_webview_t *handle, const char *html);
|
||||
|
||||
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_run_js(rkt_webview_t *handle, const char *js);
|
||||
RKTWEBVIEW_EXPORT item_t rkt_webview_call_js(rkt_webview_t *handle, const char *js);
|
||||
|
||||
//RKTWEBVIEW_EXPORT result_t rkt_bind(rkt_webview_t *handle, const char *selector, const char *event);
|
||||
//RKTWEBVIEW_EXPORT result_t rkt_unbind(rkt_webview_t *handle, const char *selector, const char *event);
|
||||
|
||||
RKTWEBVIEW_EXPORT bool rkt_webview_valid(rkt_webview_t *handle);
|
||||
|
||||
RKTWEBVIEW_EXPORT int rkt_webview_pending_events(rkt_webview_t *wv);
|
||||
RKTWEBVIEW_EXPORT item_t rkt_webview_get_event(rkt_webview_t *wv);
|
||||
RKTWEBVIEW_EXPORT void rkt_webview_register_queue_callback(rkt_webview_t *wv, int id, void(*cb)(int id, item_t item));
|
||||
RKTWEBVIEW_EXPORT void rkt_webview_destroy_item(item_t item);
|
||||
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_move(rkt_webview_t *wv, int x, int y);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_resize(rkt_webview_t *wv, int w, int h);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_set_title(rkt_webview_t *wv, const char *title);
|
||||
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_devtools(rkt_webview_t *wv);
|
||||
|
||||
RKTWEBVIEW_EXPORT reason_t rkt_webview_last_reason(rkt_webview_t *wv);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // RKTWEBVIEW_H
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef RKTWEBVIEW_GLOBAL_H
|
||||
#define RKTWEBVIEW_GLOBAL_H
|
||||
|
||||
#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) \
|
||||
|| defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||
#define Q_DECL_EXPORT __declspec(dllexport)
|
||||
#define Q_DECL_IMPORT __declspec(dllimport)
|
||||
#else
|
||||
#define Q_DECL_EXPORT __attribute__((visibility("default")))
|
||||
#define Q_DECL_IMPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#if defined(RKTWEBVIEW_LIBRARY)
|
||||
#define RKTWEBVIEW_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
#define RKTWEBVIEW_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // RKTWEBVIEW_GLOBAL_H
|
||||
Reference in New Issue
Block a user