├── Makefile ├── .gitignore ├── source ├── cl-webengine.pro ├── package.lisp ├── run.lisp ├── interface.h ├── interface.lisp └── interface.cpp ├── cl-webengine.asd ├── LICENSE ├── README.org └── ROADMAP.org /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: 3 | cd source && qmake 4 | make -C source 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.core 2 | *.fas 3 | *.fasl 4 | *.lib 5 | *.lis 6 | *.o 7 | build/ 8 | configure 9 | config.h.in* 10 | .qmake.stash 11 | *.app 12 | Makefile 13 | *.dylib 14 | *.so 15 | moc_* -------------------------------------------------------------------------------- /source/cl-webengine.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | TARGET = webengine 3 | INCLUDEPATH += . 4 | QT += core gui widgets webenginewidgets 5 | 6 | # Input 7 | HEADERS += interface.h 8 | SOURCES += interface.cpp 9 | -------------------------------------------------------------------------------- /cl-webengine.asd: -------------------------------------------------------------------------------- 1 | ;;; cl-webengine.asd 2 | 3 | #-(or sbcl) 4 | (warn "Unsupported implementation.") 5 | 6 | (asdf:defsystem :cl-webengine 7 | :description "An FFI binding to WebEngine in Qt." 8 | :author "Atlas Engineer LLC" 9 | :licence "BSD 3-Clause" 10 | :version "0.0" 11 | :serial t 12 | :components ((:module "source" 13 | :components 14 | ((:file "package") 15 | (:file "interface") 16 | (:file "run")))) 17 | :depends-on (:cffi)) 18 | -------------------------------------------------------------------------------- /source/package.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :cl-webengine 2 | (:nicknames :webengine :qt) 3 | (:use :common-lisp :cffi)) 4 | 5 | (in-package :cl-webengine) 6 | 7 | (define-foreign-library libwebengine 8 | (:darwin (:or 9 | "libwebengine.dylib" 10 | "libwebengine.1.dylib" 11 | "libwebengine.1.0.dylib" 12 | "libwebengine.1.0.0.dylib")) 13 | (:unix (:or "libwebengine.so" 14 | "libwebengine.so.1" 15 | "libwebengine.so.1.0" 16 | "libwebengine.so.1.0.0")) 17 | (t (:default "libwebengine"))) 18 | 19 | (use-foreign-library libwebengine) 20 | -------------------------------------------------------------------------------- /source/run.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-webengine) 2 | 3 | (defun run () 4 | (let ((application 5 | (new-q-application 1 (cffi:foreign-alloc :string 6 | :initial-contents (list "cl-webengine.lib") 7 | :null-terminated-p t))) 8 | (window (new-q-widget)) 9 | (layout (new-qv-box-layout)) 10 | (webview (new-q-web-engine-view))) 11 | (layout-add-widget layout webview) 12 | (widget-set-layout window layout) 13 | (web-engine-view-load webview "https://www.duckduckgo.com") 14 | (widget-show window) 15 | (application-exec application))) 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017-2019, Atlas Engineer LLC. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * cl-webengine - QtWebEngine binding for Common Lisp 2 | Bindings to Qt and WebEngine. 3 | 4 | * How it Works 5 | Common Lisp has a way to interact with C code via the so called CFFI 6 | (C Foreign Function Interface). This interface allows any C code to be 7 | called by Common Lisp. At this time, there is no universal foreign 8 | function interface for C++. This presents a problem when we wish to 9 | call Qt code (which is written in C++). 10 | 11 | In order to circumvent this problem, we can write functions in C that 12 | call the C++ code that we need. Concretely it looks like this: 13 | 14 | + =interface.h= we declare a function to wrap some C++ function we 15 | want to use. 16 | + =interface.cpp= we implement the C function declared in 17 | =interface.h= with the C++ code inside of it. 18 | + =interface.lisp= we implement a definition via CFFI so that Lisp 19 | code can call the function defined in =interface.cpp= 20 | 21 | In this way, we can now invoke C++ through Lisp. A concrete example is 22 | shown below for a single function: 23 | 24 | ** interface.h 25 | #+NAME: interface.h 26 | #+BEGIN_SRC C++ 27 | extern "C" void widgetShow(void* widget); 28 | #+END_SRC 29 | 30 | ** interface.cpp 31 | #+NAME: interface.cpp 32 | #+BEGIN_SRC cpp 33 | void widgetShow(void* widget) { 34 | QWidget *_widget = reinterpret_cast(widget); 35 | _widget->show(); 36 | } 37 | #+END_SRC 38 | 39 | ** interface.lisp 40 | #+NAME: interface.lisp 41 | #+BEGIN_SRC lisp 42 | (defcfun ("widgetShow" widget-show) :void 43 | (widget :pointer)) 44 | (export 'widget-show) 45 | #+END_SRC 46 | 47 | * Dependencies 48 | 49 | The library requires Qt5 and Qt5 Webengine. 50 | More specifically, you don't need all of Qt5, the following Qt5 components are 51 | enough: 52 | 53 | - qtbase 54 | - qtwebengine 55 | - qtwebchannel 56 | - qtdeclarative 57 | 58 | * Compilation 59 | #+NAME: compilation 60 | #+BEGIN_SRC shell 61 | make all 62 | #+END_SRC 63 | 64 | After compiling, you will need to copy the shared libraries to a 65 | location where CFFI can find them. If you need to append a location 66 | for CFFI, you can add the following lines to your Lisp initialization: 67 | 68 | #+NAME: sbclrc 69 | #+BEGIN_SRC lisp 70 | (ql:quickload :cffi) 71 | (pushnew "/opt/local/lib/" cffi:*foreign-library-directories* :test #'equal) 72 | #+END_SRC 73 | 74 | The above demonstrates an example in SBCL, where the location of the 75 | shared library will be in =/opt/local/lib=. 76 | 77 | * Running in SBCL on macOS: 78 | #+NAME: configuration 79 | #+BEGIN_SRC lisp 80 | (sb-int:with-float-traps-masked (:invalid :inexact :overflow) (cl-webengine::run)) 81 | #+END_SRC 82 | 83 | * Running from SLIME in SBCL on macOS: 84 | #+NAME: configuration 85 | #+BEGIN_SRC lisp 86 | (trivial-main-thread:call-in-main-thread 87 | (lambda () (sb-int:with-float-traps-masked (:invalid :inexact :overflow) (cl-webengine::run)))) 88 | #+END_SRC 89 | -------------------------------------------------------------------------------- /source/interface.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef void (*fpInt)(int arg); 12 | typedef void (*fpIntChar)(int arg, char* str); 13 | typedef void (*fpKeyPress)(int id, int keyCode, char* keyString, int modifierFlags); 14 | 15 | #define UNUSED(x) (void)(x) 16 | #ifdef __cplusplus 17 | #define EXTERNC extern "C" 18 | #else 19 | #define EXTERNC 20 | #endif 21 | 22 | EXTERNC void* newKeyPressFilter(int id, fpKeyPress callback); 23 | EXTERNC void widgetInstallKeyPressFilter(void* widget, void* keyPressFilter); 24 | EXTERNC int widgetIsActiveWindow(void* widget); 25 | EXTERNC QApplication* newQApplication(int argc, char** argv); 26 | EXTERNC void* newLoadFinishedListener(int id, fpInt callback); 27 | EXTERNC void loadFinishedListenerConnect(void* loadStartedListener, void* webEngineView); 28 | EXTERNC void* newLoadStartedListener(int id, fpInt callback); 29 | EXTERNC void loadStartedListenerConnect(void* loadStartedListener, void* webEngineView); 30 | EXTERNC int applicationExec(void* application); 31 | EXTERNC void applicationQuit(void* application); 32 | EXTERNC QPushButton* newQPushButton(char* label); 33 | EXTERNC QWindow* newQWindow(); 34 | EXTERNC QWidget* newQWidget(); 35 | EXTERNC QHBoxLayout* newQHBoxLayout(); 36 | EXTERNC QVBoxLayout* newQVBoxLayout(); 37 | EXTERNC QWebEngineView* newQWebEngineView(); 38 | EXTERNC char* webEngineViewUrl(void* webEngineView); 39 | EXTERNC void webEngineViewLoad(void* webEngineView, char* url); 40 | EXTERNC void* webEngineViewPage(void* webEngineView); 41 | EXTERNC void webEnginePageSetHtml(void* webEnginePage, char* html); 42 | EXTERNC void webEnginePageRunJavaScript(void* webEnginePage, char* javascript, int id, fpIntChar callback); 43 | EXTERNC void webEnginePageSetLivecycleState(void* webEnginePage, int state); 44 | EXTERNC int webEnginePageLivecycleState(void* webEnginePage); 45 | EXTERNC void webEnginePageTriggerAction(void* webEnginePage, int action, int checked); 46 | EXTERNC void* webEnginePageAction(void* webEnginePage, int action); 47 | EXTERNC void* webEnginePageHistory(void* webEnginePage); 48 | EXTERNC void webEnginePageSetUrlRequestInterceptor(void* webEnginePage, void* interceptor); 49 | EXTERNC char* webEnginePageUrl(void* webEnginePage); 50 | EXTERNC int webEnginePageIsAudioMuted(void* webEnginePage); 51 | EXTERNC void webEnginePageSetAudioMuted(void* webEnginePage, int muted); 52 | EXTERNC void layoutAddWidget(void* layout, void* widget); 53 | EXTERNC void windowShow(void* window); 54 | EXTERNC void windowPresent(void* window); 55 | EXTERNC void windowSetTitle(void* window, char* title); 56 | EXTERNC char* windowTitle(void* window); 57 | EXTERNC int windowIsActive(void* window); 58 | EXTERNC void widgetSetLayout(void* widget, void* layout); 59 | EXTERNC void widgetSetParent(void* widget, void* parent); 60 | EXTERNC void widgetShow(void* widget); 61 | EXTERNC void widgetHide(void* widget); 62 | EXTERNC void widgetDelete(void* object); 63 | EXTERNC void widgetResize(void* widget, int width, int height); 64 | EXTERNC void widgetSetFixedHeight(void* widget, int height); 65 | EXTERNC void widgetSetFixedSize(void* widget, int width, int height); 66 | EXTERNC void widgetSetWindowTitle(void* widget, char* title); 67 | EXTERNC void widgetShowFullScreen(void* widget); 68 | EXTERNC void widgetShowNormal(void* widget); 69 | EXTERNC void widgetPresent(void* widget); 70 | EXTERNC void layoutSetContentsMargins(void* layout, int left, int top, int right, int bottom); 71 | EXTERNC void layoutSetSpacing(void* layout, int spacing); 72 | EXTERNC void layoutInsertWidget(void* layout, int index, void* widget); 73 | 74 | #undef EXTERNC 75 | 76 | class Listener :public QObject { 77 | Q_OBJECT 78 | public: 79 | int id; 80 | fpInt callback; 81 | }; 82 | 83 | class LoadStartedListener :public Listener { 84 | Q_OBJECT 85 | public slots: 86 | void loadStarted(); 87 | }; 88 | 89 | class LoadFinishedListener :public Listener { 90 | Q_OBJECT 91 | public slots: 92 | void loadFinished(bool ok); 93 | }; 94 | 95 | class KeyPressFilter : public QObject 96 | { 97 | Q_OBJECT 98 | public: 99 | int id; 100 | fpKeyPress callback; 101 | protected: 102 | bool eventFilter(QObject *obj, QEvent *event); 103 | }; 104 | -------------------------------------------------------------------------------- /ROADMAP.org: -------------------------------------------------------------------------------- 1 | #+TITLE:Functions from Qt and QtWebEngine 2 | 3 | This is a list of Qt functions to be wrapped inside C functions for 4 | binding with Common Lisp FFI. 5 | 6 | - Headings are names of Qt classes that need to be wrapped or have 7 | already been wrapped inside C functions. 8 | 9 | Those Qt functions that are marked as done ([X]) already have some 10 | implementation. The name(s) of function(s) implementing these is in 11 | the sub-list. A heading is marked as "DONE" if all of its functions 12 | are marked as done. Otherwise, it is marked as "TODO." 13 | 14 | - The heading "Undefined functions for Nyxt" contains Common Lisp FFI 15 | methods for Nyxt Browser that need to rely on Qt wrappers but 16 | cannot be mapped to Qt classes at the moment. 17 | 18 | - FFI methods that have a question mark after them are the ones that 19 | have no obvious way to be implemented. 20 | 21 | * DONE QApplication 22 | - [X] QApplication::QApplication() 23 | - newQApplication() 24 | - [X] QApplication::quit() 25 | - applicationQuit() 26 | - [X] QApplication::exec() 27 | - applicationExec() 28 | 29 | * TODO QWidget 30 | - [X] delete QWidget 31 | - widgetDelete() 32 | - [ ] QWidget::destroy() 33 | - [X] QWidget::showFullScreen() 34 | - widgetShowFullScreen() 35 | - [X] QWidget::showNormal() 36 | - widgetShowNormal() 37 | - [X] QWidget::resize() 38 | - widgetResize() 39 | - [X] QWidget::QWidget() 40 | - newQWidget() 41 | - [X] QWidget::setLayout() 42 | - widgetSetLayout() 43 | - [X] QWidget::show() 44 | - widgetShow() 45 | - [ ] QWidget::keyPressEvent() 46 | - [ ] QWidget::keyReleaseEvent() 47 | - [ ] QWidget::MouseMoveEvent() 48 | - [ ] QWidget::MousePressEvent() 49 | - [ ] QWidget::MouseDoubleClickEvent() 50 | - [ ] QWidget::WheelEvent() 51 | - [ ] QWidget::inputMethodEvent() 52 | - [ ] QWidget::contextMenuEvent() 53 | - [X] QWidget::setWindowTitle() 54 | - widgetSetWindowTitle() 55 | - [ ] QWidget::height() 56 | - [X] QWidget::isActiveWindow() 57 | - widgetIsActiveWindow() 58 | - [X] QWidget::isActiveWindow() 59 | - widgetIsActiveWindow() 60 | - [X] QWidget::show(), QWindow::raise() 61 | - widgetPresent() 62 | - [X] QWidget::setParent(), QWindow::raise() 63 | - widgetSetParent() 64 | - [X] QWidget::setFixedHeight() 65 | - widgetSetFixedHeight() 66 | - [X] QWidget::setFixedSize() 67 | - widgetSetFixedSize() 68 | 69 | * TODO QWindow 70 | - [X] QWindow::QWindow() 71 | - newQWindow() 72 | - [X] QWindow::show() 73 | - windowShow() 74 | - [X] QWindow::show(), QWindow::raise() 75 | - windowPresent() 76 | - [X] QWindow::setTitle() 77 | - windowSetTitle() 78 | - [X] QWindow::title() 79 | - windowTitle() 80 | - [X] QWindow::isActive() 81 | - windowIsActive() 82 | 83 | * DONE QVBoxLayout 84 | - [X] QVBoxLayout::QVBoxLayout() 85 | - newQVBoxLayout() 86 | 87 | * DONE QHBoxLayout 88 | - [X] QHBoxLayout::QHBoxLayout() 89 | - newQHBoxLayout() 90 | 91 | * TODO QLayout 92 | - [X] QLayout::setWidget() 93 | - layoutAddWidget() 94 | - [X] QLayout::setContentMargins() 95 | - layoutSetContentsMargins() 96 | - [X] QLayout::setSpacing() 97 | - layoutSetSpacing() 98 | - [ ] QLayout::removeWidget() 99 | 100 | * DONE QPushButton 101 | - [X] QPushButton::QPushButton() 102 | - newQPushButton() 103 | 104 | * TODO QWebEngineView 105 | - [X] QWebEngineView::QWebEngineView() 106 | - newQWebEngineView() 107 | - [ ] QtWebEngineView::title() 108 | - [X] QtWebEngineView::url() 109 | - webEngineViewUrl() 110 | - [X] QWebEngineView::setUrl() 111 | - webEngineViewLoad() 112 | - [X] QWebEngineView::QWebEngineView() 113 | - newQWebEngineView() 114 | - [X] QWebEngineView::loadStarted() 115 | - newLoadStartedListener() 116 | - loadStartedListenerConnect() 117 | - LoadStartedListener::loadStarted() 118 | - [X] QWebEngineView::loadFinished() 119 | - newLoadFinishedListener() 120 | - loadFinishedListenerConnect() 121 | - LoadFinishedListener::loadFinished() 122 | - [X] QWebEngineView::page() 123 | - newQWebEngineViewPage() 124 | 125 | * TODO QWebEnginePage 126 | - [X] QWebEnginePage::livecycleState() 127 | - webEnginePageLivecycleState() 128 | - [X] QWebEnginePage::setLivecycleState() 129 | - webEnginePageSetLivecycleState() 130 | - [X] enum QWebEnginePage::LivecycleState 131 | - [X] QWebEnginePage::runJavaScript() 132 | - webEnginePageRunJavaScript() 133 | - [X] QWebEnginePage::setHtml() 134 | - webEnginePageSetHtml() 135 | - [X] enum QWebEnginePage::WebAction 136 | - [X] QWebEnginePage::action() 137 | - webEnginePageAction() 138 | - [X] QWebEnginePage::triggerAction() 139 | - webEnginePageTriggerAction() 140 | - [ ] enum QWebEnginePage::NavigationType 141 | - [ ] QWebEnginePage::acceptNavigationRequest() 142 | - [ ] QWebEnginePage::titleChanged() 143 | - [ ] QWebEnginePage::urlChanged() 144 | - [X] QWebEnginePage::setUrlRequestInterceptor() 145 | - webEnginePageSetUrlRequestInterceptor() 146 | - [ ] QWebEnginePage::certificateError() 147 | - [X] QWebEnginePage::history() 148 | - webEnginePageHistory() 149 | - [X] QWebEnginePage::runJavaScript(const QString &scriptSource, quint32 worldid, const QWebEngineCallback &resultCallback) 150 | - webEnginePageRunJavaScript() 151 | - [X] QWebEnginePage::url() 152 | - webEnginePageUrl() 153 | - [x] QWebEngineView::isAudioMuted() 154 | - webEnginePageIsAudioMuted() 155 | - [X] QWebEngineView::setAudioMuted() 156 | - webEnginePageSetAudioMuted() 157 | 158 | * TODO QWebEnginePageFullScreenRequest 159 | - [ ] QWebEnginePageFullScreenRequest::accept() 160 | - [ ] QWebEnginePageFullScreenRequest::origin() 161 | - [ ] QWebEnginePageFullScreenRequest::reject() 162 | - [ ] QWebEnginePageFullScreenRequest::toggleOn() 163 | 164 | * TODO QWebEngineContextMenuData 165 | - [ ] enum QWebEngineContextMenuData::EditFlags 166 | - [ ] QWebEngineContextMenuData::editFlags() 167 | - [ ] enum QWebEngineContextMenuData::MediaFlags 168 | - [ ] QWebEngineContextMenuData::mediaFlags() 169 | - [ ] enum QWebEngineContextMenuData::MediaType 170 | - [ ] QWebEngineContextMenuData::mediaType() 171 | - [ ] QWebEngineContextMenuData::misspelledWord() 172 | - [ ] QWebEngineContextMenuData::spellCheckerSuggestions() 173 | 174 | * TODO QWebEngineProfile 175 | - [ ] QWebEngineProfile::setUrlRequestInterceptor 176 | - [ ] QWebEngineProfile::setHttpUserAgent() 177 | - [ ] QWebEngineProfile::setHttpAcceptLanguage() 178 | 179 | * TODO QWebengnineUrlRequestInterceptor 180 | - [ ] QWebEngineUrlRequestInterceptor::QWebEngineUrlRequestInterceptor() 181 | - [ ] QWebEngineUrlRequestInterceptor::interceptRequest() 182 | 183 | * TODO QWebEngineUrlRequestInfo 184 | - [ ] enum QWebEngineUrlRequestInfo::NavigationType 185 | - [ ] enum QWebEngineUrlRequestInfo::ResourceType 186 | - [ ] QWebEngineUrlRequestInfo::block() 187 | - [ ] QWebEngineUrlRequestInfo::firstPartyUrl() 188 | - [ ] QWebEngineUrlRequestInfo::initiator() 189 | - [ ] QWebEngineUrlRequestInfo::navigationType() 190 | - [ ] QWebEngineUrlRequestInfo::redirect() 191 | - [ ] QWebEngineUrlRequestInfo::requestMethod() 192 | - [ ] QWebEngineUrlRequestInfo::requestUrl() 193 | - [ ] QWebEngineUrlRequestInfo::resourceType() 194 | - [ ] QWebEngineUrlRequestInfo::setHttpHeader() 195 | 196 | * TODO QWebEngineCertificateError 197 | - [ ] enum QWebEngineCertificateError::Error 198 | - [ ] QWebEngineCertificateError::url() 199 | - [ ] QWebEngineCertificateError::error() 200 | - [ ] QWebEngineCertificateError::errorDescription() 201 | - [ ] QWebEngineCertificateError::isOverridable() 202 | - [ ] QWebEngineCertificateError::ignoreCertificateError() 203 | - [ ] QWebEngineCertificateError::rejectCertificate() 204 | 205 | * TODO QWebengineHistory 206 | - [ ] QWebEngineHistory::count() 207 | - [ ] QWebEngineHistory::currentItem() 208 | - [ ] QWebEngineHistory::currentItemIndex() 209 | - [ ] QWebEngineHistory::itemAt() 210 | - [ ] QWebEngineHistory::goToItem() 211 | 212 | * TODO QWebEngineHistoryItem 213 | - [ ] QWebEngineHistoryItem::originalUrl() 214 | - [ ] QWebEngineHistoryItem::url() 215 | - [ ] QWebEngineHistoryItem::title() 216 | - [ ] QWebEngineHistoryItem::lastVisited() 217 | - [ ] QWebEngineHistoryItem::iconUrl() 218 | 219 | * TODO QWebEngineSettings 220 | - [ ] QWebEngineSettings::setAttribute() 221 | - [ ] QWebEngineSettings::resetAttribute() 222 | - [ ] enum QWebEngineSettings::WebAttribute 223 | - [ ] QWebEngineSettings::testAttribute() 224 | 225 | * TODO QWebEngineCookieStore 226 | - [ ] QWebEngineCookieStore::setCookieFilter() 227 | 228 | * TODO Undefined functions for Nyxt 229 | ** TODO ffi-generate-input-event - ? 230 | ** TODO ffi-generated-input-event-p - ? 231 | ** TODO ffi-display-uri - ? 232 | ** TODO ffi-buffer-enable-javascript-markup - ? 233 | ** TODO ffi-buffer-set-proxy - ? 234 | ** TODO ffi-buffer-get-proxy - ? 235 | -------------------------------------------------------------------------------- /source/interface.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-webengine) 2 | 3 | (defvar callback-counter 0) 4 | (defvar callbacks ()) 5 | (defstruct callback 6 | (id) 7 | (function)) 8 | 9 | (defclass event () 10 | ((qt-object :accessor qt-object :documentation "The pointer to the 11 | Qt event object.") 12 | (init-time :accessor init-time :initarg :init-time))) 13 | 14 | (defclass keypress-event (event) 15 | ((key-code :accessor key-code :initarg :key-code) 16 | (key-string :accessor key-string :initarg :key-string) 17 | (modifier-flags :accessor modifier-flags :initarg :modifier-flags 18 | :documentation "The unmasked integer value of the currently 19 | depressed modifiers as reported by Qt.") 20 | (modifiers :accessor modifiers :initarg :modifiers))) 21 | (export '(key-code key-string modifiers)) 22 | 23 | (defparameter qt-keyboard-modifiers 24 | (list 33554432 "shift" ; Shift 25 | 67108864 "control" ; Control 26 | 134217728 "meta" ; Alt 27 | 268435456 "meta")) ; Meta 28 | (defmethod initialize-instance :after ((event keypress-event) &key) 29 | (setf (modifiers event) 30 | (loop for (i y) on qt-keyboard-modifiers by #'cddr 31 | unless (zerop (logand i (modifier-flags event))) 32 | collect y))) 33 | 34 | (cffi:defcallback key-pressed :void 35 | ((id :int) 36 | (key-code :int) 37 | (key-string :string) 38 | (modifier-flags :int)) 39 | (let* ((callback (find id callbacks :key (function callback-id)))) 40 | (when (callback-function callback) 41 | (let ((event (make-instance 42 | 'keypress-event 43 | :key-code key-code 44 | :key-string key-string 45 | :modifier-flags modifier-flags))) 46 | (funcall (callback-function callback) event))))) 47 | 48 | (defcfun ("newKeyPressFilter" new-key-press-filter) :pointer 49 | (id :int) 50 | (callback :pointer)) 51 | (export 'new-key-press-filter) 52 | 53 | (defcfun ("widgetInstallKeyPressFilter" %widget-install-key-press-filter) :pointer 54 | (widget :pointer) 55 | (key-press-filter :pointer)) 56 | 57 | (defun widget-install-key-press-filter (widget callback) 58 | (incf callback-counter) 59 | (push (make-callback :id callback-counter :function callback) callbacks) 60 | (%widget-install-key-press-filter 61 | widget 62 | (new-key-press-filter callback-counter (cffi:callback key-pressed)))) 63 | (export 'widget-install-key-press-filter) 64 | 65 | (defcfun ("newLoadFinishedListener" new-load-finished-listener) :pointer 66 | (id :int) 67 | (callback :pointer)) 68 | (export 'new-load-finished-listener) 69 | 70 | (defcfun ("loadFinishedListenerConnect" %load-finished-listener-connect) :void 71 | (load-finished-listener :pointer) 72 | (web-engine-view :pointer)) 73 | 74 | (defun load-finished-listener-connect (web-engine-view callback) 75 | (incf callback-counter) 76 | (push (make-callback :id callback-counter :function callback) callbacks) 77 | (%load-finished-listener-connect 78 | (new-load-finished-listener callback-counter (cffi:callback load-finished)) 79 | web-engine-view)) 80 | (export 'load-finished-listener-connect) 81 | 82 | (cffi:defcallback load-finished :void 83 | ((id :int)) 84 | (let* ((callback (find id callbacks :key (function callback-id)))) 85 | (when (callback-function callback) 86 | (funcall (callback-function callback))))) 87 | 88 | (defcfun ("newLoadStartedListener" new-load-started-listener) :pointer 89 | (id :int) 90 | (callback :pointer)) 91 | (export 'new-load-started-listener) 92 | 93 | (defcfun ("loadStartedListenerConnect" %load-started-listener-connect) :void 94 | (load-started-listener :pointer) 95 | (web-engine-view :pointer)) 96 | 97 | (defun load-started-listener-connect (web-engine-view callback) 98 | (incf callback-counter) 99 | (push (make-callback :id callback-counter :function callback) callbacks) 100 | (%load-started-listener-connect 101 | (new-load-started-listener callback-counter (cffi:callback load-started)) 102 | web-engine-view)) 103 | (export 'load-started-listener-connect) 104 | 105 | (cffi:defcallback load-started :void 106 | ((id :int)) 107 | (let* ((callback (find id callbacks :key (function callback-id)))) 108 | (when (callback-function callback) 109 | (funcall (callback-function callback))))) 110 | 111 | (defcfun ("newQApplication" new-q-application) :pointer 112 | (argc :int) 113 | (argv :pointer)) 114 | (export 'new-q-application) 115 | 116 | (defcfun ("applicationExec" application-exec) :int 117 | (application :pointer)) 118 | (export 'application-exec) 119 | 120 | (defcfun ("applicationQuit" application-quit) :void 121 | (application :pointer)) 122 | (export 'application-quit) 123 | 124 | (defcfun ("newQWindow" new-q-window) :pointer) 125 | (export 'new-q-window) 126 | 127 | (defcfun ("newQWidget" new-q-widget) :pointer) 128 | (export 'new-q-widget) 129 | 130 | (defcfun ("newQPushButton" new-q-push-button) :pointer 131 | (label :string)) 132 | (export 'new-q-push-button) 133 | 134 | (defcfun ("newQVBoxLayout" new-qv-box-layout) :pointer) 135 | (export 'new-qv-box-layout) 136 | 137 | (defcfun ("newQHBoxLayout" new-qh-box-layout) :pointer) 138 | (export 'new-qh-box-layout) 139 | 140 | (defcfun ("newQWebEngineView" new-q-web-engine-view) :pointer) 141 | (export 'new-q-web-engine-view) 142 | 143 | (defcfun ("webEngineViewLoad" web-engine-view-load) :void 144 | (webEngineView :pointer) 145 | (url :string)) 146 | (export 'web-engine-view-load) 147 | 148 | (defcfun ("webEngineViewUrl" web-engine-view-url) :string 149 | (webEngineView :pointer)) 150 | (export 'web-engine-view-url) 151 | 152 | (defcfun ("webEngineViewPage" web-engine-view-page) :pointer 153 | (webEngineView :pointer)) 154 | (export 'web-engine-view-page) 155 | 156 | (defcfun ("webEnginePageSetHtml" web-engine-page-set-html) :void 157 | (webEnginePage :pointer) 158 | (html :string)) 159 | (export 'web-engine-page-set-html) 160 | 161 | (defcfun ("webEnginePageSetLivecycleState" web-engine-page-set-livecycle-state) :void 162 | (webEnginePage :pointer) 163 | (start :int)) 164 | (export 'web-engine-page-set-livecycle-state) 165 | 166 | (defcfun ("webEnginePageLivecycleState" web-engine-page-livecycle-state) :int 167 | (webEnginePage :pointer)) 168 | (export 'web-engine-page-livecycle-state) 169 | 170 | (defcfun ("webEnginePageTriggerAction" web-engine-page-trigger-action) :void 171 | (webEnginePage :pointer) 172 | (action :int) 173 | (checked :int)) 174 | (export 'web-engine-page-trigger-action) 175 | 176 | (defcfun ("webEnginePageAction" web-engine-page-action) :pointer 177 | (webEnginePage :pointer) 178 | (action :int)) 179 | (export 'web-engine-page-action) 180 | 181 | (defcfun ("webEnginePageHistory" web-engine-page-history) :pointer 182 | (webEnginePage :pointer)) 183 | (export 'web-engine-page-history) 184 | 185 | (defcfun ("webEnginePageSetUrlRequestInterceptor" web-engine-page-set-url-request-interceptor) :void 186 | (webEnginePage :pointer) 187 | (interceptor :pointer)) 188 | (export 'web-engine-page-set-url-request-interceptor) 189 | 190 | (defcfun ("webEnginePageUrl" web-engine-page-url) :string 191 | (webEnginePage :pointer)) 192 | (export 'web-engine-page-url) 193 | 194 | (defcfun ("webEnginePageIsAudioMuted" web-engine-page-is-audio-muted) :void 195 | (webEnginePage :pointer)) 196 | (export 'web-engine-page-is-audio-muted) 197 | 198 | (defcfun ("webEnginePageSetAudioMuted" web-engine-page-set-audio-muted) :void 199 | (webEnginePage :pointer) 200 | (muted :int)) 201 | (export 'web-engine-page-set-audio-muted) 202 | 203 | (defcfun ("webEnginePageRunJavaScript" %web-engine-page-run-javascript) :void 204 | (webEnginePage :pointer) 205 | (javascript :string) 206 | (id :int) 207 | (callback :pointer)) 208 | 209 | (cffi:defcallback javascript-finished :void 210 | ((id :int) 211 | (result :string)) 212 | (let* ((callback (find id callbacks :key (function callback-id)))) 213 | (setf callbacks (delete callback callbacks)) 214 | (when (callback-function callback) 215 | (funcall (callback-function callback) result)))) 216 | 217 | (defun web-engine-page-run-javascript (web-engine-page javascript &optional callback) 218 | (incf callback-counter) 219 | (push (make-callback :id callback-counter :function callback) callbacks) 220 | (%web-engine-page-run-javascript 221 | web-engine-page 222 | javascript 223 | callback-counter 224 | (cffi:callback javascript-finished))) 225 | (export 'web-engine-page-run-javascript) 226 | 227 | (defcfun ("layoutAddWidget" layout-add-widget) :void 228 | (layout :pointer) 229 | (widget :pointer)) 230 | (export 'layout-add-widget) 231 | 232 | (defcfun ("windowShow" window-show) :void 233 | (window :pointer)) 234 | (export 'window-show) 235 | 236 | (defcfun ("windowPresent" window-present) :void 237 | (window :pointer)) 238 | (export 'window-present) 239 | 240 | (defcfun ("windowSetTitle" window-set-title) :void 241 | (window :pointer) 242 | (title :string)) 243 | (export 'window-set-title) 244 | 245 | (defcfun ("windowTitle" window-title) :string 246 | (window :pointer)) 247 | (export 'window-title) 248 | 249 | (defcfun ("windowIsActive" %window-is-active) :int 250 | (window :pointer)) 251 | 252 | (defun window-is-active (window) 253 | (> (%window-is-active window) 0)) 254 | (export 'window-is-active) 255 | 256 | (defcfun ("widgetSetLayout" widget-set-layout) :void 257 | (widget :pointer) 258 | (layout :pointer)) 259 | (export 'widget-set-layout) 260 | 261 | (defcfun ("widgetSetParent" widget-set-parent) :void 262 | (widget :pointer) 263 | (parent :pointer)) 264 | (export 'widget-set-parent) 265 | 266 | (defcfun ("widgetShow" widget-show) :void 267 | (widget :pointer)) 268 | (export 'widget-show) 269 | 270 | (defcfun ("widgetHide" widget-hide) :void 271 | (widget :pointer)) 272 | (export 'widget-hide) 273 | 274 | (defcfun ("widgetDelete" widget-delete) :void 275 | (widget :pointer)) 276 | (export 'widget-delete) 277 | 278 | (defcfun ("widgetResize" widget-resize) :void 279 | (widget :pointer) 280 | (width :int) 281 | (height :int)) 282 | (export 'widget-resize) 283 | 284 | (defcfun ("widgetSetFixedHeight" widget-set-fixed-height) :void 285 | (widget :pointer) 286 | (height :int)) 287 | (export 'widget-set-fixed-height) 288 | 289 | (defcfun ("widgetSetFixedSize" widget-set-fixed-size) :void 290 | (widget :pointer) 291 | (width :int) 292 | (height :int)) 293 | (export 'widget-set-fixed-size) 294 | 295 | (defcfun ("widgetSetWindowTitle" widget-set-window-title) :void 296 | (widget :pointer) 297 | (title :string)) 298 | (export 'widget-set-window-title) 299 | 300 | (defcfun ("widgetShowFullScreen" widget-show-full-screen) :void 301 | (widget :pointer)) 302 | (export 'widget-show-full-screen) 303 | 304 | (defcfun ("widgetShowNormal" widget-show-normal) :void 305 | (widget :pointer)) 306 | (export 'widget-show-normal) 307 | 308 | (defcfun ("widgetPresent" widget-present) :void 309 | (widget :pointer)) 310 | (export 'widget-present) 311 | 312 | (defcfun ("widgetIsActiveWindow" %widget-is-active-window) :int 313 | (widget :pointer)) 314 | 315 | (defun widget-is-active-window (widget) 316 | (if (> (%widget-is-active-window widget) 0) t nil)) 317 | (export 'widget-is-active-window) 318 | 319 | (defcfun ("layoutSetContentsMargins" layout-set-contents-margins) :void 320 | (layout :pointer) 321 | (left :int) 322 | (top :int) 323 | (right :int) 324 | (bottom :int)) 325 | (export 'layout-set-contents-margins) 326 | 327 | (defcfun ("layoutSetSpacing" layout-set-spacing) :void 328 | (layout :pointer) 329 | (spacing :int)) 330 | (export 'layout-set-spacing) 331 | 332 | (defcfun ("layoutInsertWidget" layout-insert-widget) :void 333 | (layout :pointer) 334 | (index :int) 335 | (widget :pointer)) 336 | (export 'layout-insert-widget) 337 | -------------------------------------------------------------------------------- /source/interface.cpp: -------------------------------------------------------------------------------- 1 | #include "interface.h" 2 | 3 | void* newKeyPressFilter(int id, fpKeyPress callback) { 4 | KeyPressFilter *keyPressFilter = new KeyPressFilter(); 5 | keyPressFilter->id = id; 6 | keyPressFilter->callback = callback; 7 | return keyPressFilter; 8 | } 9 | 10 | void widgetInstallKeyPressFilter(void* widget, void* keyPressFilter) { 11 | KeyPressFilter *_keyPressFilter = reinterpret_cast(keyPressFilter); 12 | QWidget *_widget = reinterpret_cast(widget); 13 | _widget->installEventFilter(_keyPressFilter); 14 | } 15 | 16 | bool KeyPressFilter::eventFilter(QObject *obj, QEvent *event) { 17 | if (event->type() == QEvent::KeyPress) { 18 | QKeyEvent *keyEvent = static_cast(event); 19 | int keyCode = keyEvent->key(); 20 | QString text; 21 | if (keyEvent->text().isEmpty()) { 22 | text = QKeySequence(keyEvent->key()).toString(); 23 | } else { 24 | text = keyEvent->text(); 25 | } 26 | QByteArray keyStringArray = text.toUtf8(); 27 | char* keyString = keyStringArray.data(); 28 | int modifierFlags = keyEvent->modifiers(); 29 | // -31 emitted as keystring when only modifiers pressed 30 | if ((int)keyString[0] == -31) { 31 | keyString = (char*)""; 32 | } 33 | callback(id, keyCode, keyString, modifierFlags); 34 | return true; 35 | } else { 36 | return QObject::eventFilter(obj, event); 37 | } 38 | } 39 | 40 | void* newLoadFinishedListener(int id, fpInt callback) { 41 | LoadFinishedListener *listener = new LoadFinishedListener(); 42 | listener->id = id; 43 | listener->callback = callback; 44 | return listener; 45 | } 46 | 47 | void loadFinishedListenerConnect(void* loadFinishedListener, void* webEngineView) { 48 | LoadFinishedListener *_loadFinishedListener = reinterpret_cast(loadFinishedListener); 49 | QWebEngineView *_webEngineView = reinterpret_cast(webEngineView); 50 | QObject::connect(_webEngineView, &QWebEngineView::loadFinished, 51 | _loadFinishedListener, &LoadFinishedListener::loadFinished); 52 | } 53 | 54 | void LoadFinishedListener::loadFinished(bool ok) { 55 | UNUSED(ok); 56 | callback(id); 57 | return; 58 | } 59 | 60 | void* newLoadStartedListener(int id, fpInt callback) { 61 | LoadStartedListener *listener = new LoadStartedListener(); 62 | listener->id = id; 63 | listener->callback = callback; 64 | return listener; 65 | } 66 | 67 | void loadStartedListenerConnect(void* loadStartedListener, void* webEngineView) { 68 | LoadStartedListener *_loadStartedListener = reinterpret_cast(loadStartedListener); 69 | QWebEngineView *_webEngineView = reinterpret_cast(webEngineView); 70 | QObject::connect(_webEngineView, &QWebEngineView::loadStarted, 71 | _loadStartedListener, &LoadStartedListener::loadStarted); 72 | } 73 | 74 | void LoadStartedListener::loadStarted() { 75 | callback(id); 76 | return; 77 | } 78 | 79 | QApplication* newQApplication(int argc, char** argv) { 80 | return new QApplication(argc, argv); 81 | } 82 | 83 | int applicationExec(void* application) { 84 | QApplication *_application = reinterpret_cast(application); 85 | return _application->exec(); 86 | } 87 | 88 | void applicationQuit(void* application) { 89 | QApplication *_application = reinterpret_cast(application); 90 | _application->quit(); 91 | return; 92 | } 93 | 94 | QWidget* newQWidget() { 95 | QWidget *widget = new QWidget; 96 | return widget; 97 | } 98 | 99 | QWindow* newQWindow() { 100 | QWindow *window = new QWindow; 101 | return window; 102 | } 103 | 104 | QVBoxLayout* newQVBoxLayout() { 105 | QVBoxLayout *layout = new QVBoxLayout; 106 | return layout; 107 | } 108 | 109 | QHBoxLayout* newQHBoxLayout() { 110 | QHBoxLayout *layout = new QHBoxLayout; 111 | return layout; 112 | } 113 | 114 | QPushButton* newQPushButton(char* label){ 115 | QPushButton *pushButton = new QPushButton(label); 116 | return pushButton; 117 | } 118 | 119 | QWebEngineView* newQWebEngineView() { 120 | QWebEngineView *webEngineView = new QWebEngineView(); 121 | return webEngineView; 122 | } 123 | 124 | void webEngineViewLoad(void* webEngineView, char* url) { 125 | QWebEngineView *_webEngineView = reinterpret_cast(webEngineView); 126 | _webEngineView->setUrl(QUrl(url)); 127 | } 128 | 129 | char* webEngineViewUrl(void* webEngineView) { 130 | QWebEngineView *_webEngineView = reinterpret_cast(webEngineView); 131 | return _webEngineView->url().toString().toUtf8().data(); 132 | } 133 | 134 | void* webEngineViewPage(void* webEngineView) { 135 | QWebEngineView *_webEngineView = reinterpret_cast(webEngineView); 136 | return _webEngineView->page(); 137 | } 138 | 139 | void webEnginePageSetHtml(void* webEnginePage, char* html) { 140 | QWebEnginePage *_webEnginePage = reinterpret_cast(webEnginePage); 141 | _webEnginePage->setHtml(html); 142 | } 143 | 144 | void webEnginePageRunJavaScript(void* webEnginePage, char* javascript, int id, fpIntChar callback) { 145 | QWebEnginePage *_webEnginePage = reinterpret_cast(webEnginePage); 146 | _webEnginePage->runJavaScript(javascript, [id, callback](const QVariant &v) { callback(id, v.toString().toUtf8().data()); }); 147 | } 148 | 149 | void webEnginePageSetLivecycleState(void* webEnginePage, int state) { 150 | QWebEnginePage *_webEnginePage = reinterpret_cast(webEnginePage); 151 | _webEnginePage->setLifecycleState(static_cast(state)); 152 | } 153 | 154 | int webEnginePageLivecycleState(void* webEnginePage) { 155 | QWebEnginePage *_webEnginePage = reinterpret_cast(webEnginePage); 156 | return (int)_webEnginePage->lifecycleState(); 157 | } 158 | 159 | void webEnginePageTriggerAction(void* webEnginePage, int action, int checked) { 160 | QWebEnginePage *_webEnginePage = reinterpret_cast(webEnginePage); 161 | _webEnginePage->triggerAction(static_cast(action), checked); 162 | } 163 | 164 | void* webEnginePageAction(void* webEnginePage, int action) { 165 | QWebEnginePage *_webEnginePage = reinterpret_cast(webEnginePage); 166 | return (void*)_webEnginePage->action(static_cast(action)); 167 | } 168 | 169 | void* webEnginePageHistory(void* webEnginePage) { 170 | QWebEnginePage *_webEnginePage = reinterpret_cast(webEnginePage); 171 | return (void*)_webEnginePage->history(); 172 | } 173 | 174 | void webEnginePageSetUrlRequestInterceptor(void* webEnginePage, void* interceptor) { 175 | QWebEnginePage *_webEnginePage = reinterpret_cast(webEnginePage); 176 | QWebEngineUrlRequestInterceptor *_interceptor 177 | = reinterpret_cast(interceptor); 178 | _webEnginePage->setUrlRequestInterceptor(_interceptor); 179 | } 180 | 181 | char* webEnginePageUrl(void* webEnginePage) { 182 | QWebEnginePage *_webEnginePage = reinterpret_cast(webEnginePage); 183 | return (char*)_webEnginePage->url().toString().toUtf8().data(); 184 | } 185 | 186 | int webEnginePageIsAudioMuted(void* webEnginePage) { 187 | QWebEnginePage *_webEnginePage = reinterpret_cast(webEnginePage); 188 | return (int)_webEnginePage->isAudioMuted(); 189 | } 190 | 191 | void webEnginePageSetAudioMuted(void* webEnginePage, int muted) { 192 | QWebEnginePage *_webEnginePage = reinterpret_cast(webEnginePage); 193 | _webEnginePage->setAudioMuted((bool)muted); 194 | } 195 | 196 | void layoutAddWidget(void* layout, void* widget) { 197 | QLayout *_layout = reinterpret_cast(layout); 198 | QWidget *_widget = reinterpret_cast(widget); 199 | _layout->addWidget(_widget); 200 | } 201 | 202 | void windowShow(void* window){ 203 | QWindow *_window = reinterpret_cast(window); 204 | _window->show(); 205 | } 206 | 207 | void windowPresent(void* window) { 208 | QWindow *_window = reinterpret_cast(window); 209 | _window->show(); 210 | _window->raise(); 211 | } 212 | 213 | void windowSetTitle(void* window, char* title){ 214 | QWindow *_window = reinterpret_cast(window); 215 | _window->setTitle(title); 216 | } 217 | 218 | char* windowTitle(void* window){ 219 | QWindow *_window = reinterpret_cast(window); 220 | return _window->title().toUtf8().data(); 221 | } 222 | 223 | int windowIsActive(void* window) { 224 | QWindow *_window = reinterpret_cast(window); 225 | return _window->isActive(); 226 | } 227 | 228 | void widgetSetLayout(void* widget, void* layout) { 229 | QWidget *_widget = reinterpret_cast(widget); 230 | QLayout *_layout = reinterpret_cast(layout); 231 | _widget->setLayout(_layout); 232 | } 233 | 234 | void widgetSetParent(void* widget, void* parent) { 235 | QWidget *_widget = reinterpret_cast(widget); 236 | QWidget *_parent = reinterpret_cast(parent); 237 | _widget->setParent(_parent); 238 | } 239 | 240 | void widgetShow(void* widget) { 241 | QWidget *_widget = reinterpret_cast(widget); 242 | _widget->show(); 243 | } 244 | 245 | void widgetHide(void* widget) { 246 | QWidget *_widget = reinterpret_cast(widget); 247 | _widget->hide(); 248 | } 249 | 250 | void widgetDelete(void* widget) { 251 | QWidget *_widget = reinterpret_cast(widget); 252 | delete _widget; 253 | } 254 | 255 | void widgetResize(void* widget, int width, int height) { 256 | QWidget *_widget = reinterpret_cast(widget); 257 | _widget->resize(width, height); 258 | } 259 | 260 | void widgetSetFixedHeight(void* widget, int height) { 261 | QWidget *_widget = reinterpret_cast(widget); 262 | _widget->setFixedHeight(height); 263 | } 264 | 265 | void widgetSetFixedSize(void* widget, int width, int height) { 266 | QWidget *_widget = reinterpret_cast(widget); 267 | _widget->setFixedSize(width, height); 268 | } 269 | 270 | void widgetSetWindowTitle(void* widget, char* title) { 271 | QWidget *_widget = reinterpret_cast(widget); 272 | _widget->setWindowTitle(title); 273 | } 274 | 275 | int widgetIsActiveWindow(void* widget) { 276 | QWidget *_widget = reinterpret_cast(widget); 277 | return _widget->isActiveWindow(); 278 | } 279 | 280 | void widgetShowFullScreen(void* widget) { 281 | QWidget *_widget = reinterpret_cast(widget); 282 | _widget->showFullScreen(); 283 | } 284 | 285 | void widgetShowNormal(void* widget) { 286 | QWidget *_widget = reinterpret_cast(widget); 287 | _widget->showNormal(); 288 | } 289 | 290 | void widgetPresent(void* widget) { 291 | QWidget *_widget = reinterpret_cast(widget); 292 | _widget->show(); 293 | _widget->raise(); 294 | } 295 | 296 | void layoutSetContentsMargins(void* layout, int left, int top, int right, int bottom) { 297 | QLayout *_layout = reinterpret_cast(layout); 298 | _layout->setContentsMargins(left, top, right, bottom); 299 | } 300 | 301 | void layoutSetSpacing(void* layout, int spacing) { 302 | QLayout *_layout = reinterpret_cast(layout); 303 | _layout->setSpacing(spacing); 304 | } 305 | 306 | void layoutInsertWidget(void* layout, int index, void* widget) { 307 | QBoxLayout *_layout = reinterpret_cast(layout); 308 | QWidget *_widget = reinterpret_cast(widget); 309 | _layout->insertWidget(index, _widget); 310 | } 311 | 312 | int main (int argc, char** argv) { 313 | QApplication* app = new QApplication(argc, argv); 314 | QWidget *window = reinterpret_cast(newQWidget()); 315 | QVBoxLayout *layout = reinterpret_cast(newQVBoxLayout()); 316 | QWebEngineView *web = reinterpret_cast(newQWebEngineView()); 317 | KeyPressFilter *keyPressFilter = new KeyPressFilter(); 318 | webEngineViewLoad(web, (char*)"https://www.duckduckgo.com"); 319 | layoutAddWidget(layout, web); 320 | widgetSetLayout(window, layout); 321 | widgetShow(window); 322 | window->installEventFilter(keyPressFilter); 323 | return app->exec(); 324 | } 325 | --------------------------------------------------------------------------------