35 Commits

Author SHA1 Message Date
hans 16b3a784ad documentation more consistent 2026-08-03 16:50:36 +02:00
hans e674693a28 scribble dingetje 2026-08-03 14:15:19 +02:00
hans dbf108a601 Better logging small bug in wv-dialog, conversion to stdio. 2026-08-03 13:44:01 +02:00
hans 1ecb678e38 Omzetting naar stdio. 2026-08-03 08:20:56 +02:00
hans 93453c351f webview-get-style debugging 2026-07-30 14:59:39 +02:00
hans 62b2af086a webview-get-style debugging 2026-07-30 14:56:05 +02:00
hans af91944aaf webview-get-style debugging 2026-07-30 14:53:19 +02:00
hans 57eb80ce1d webview-get-style debugging 2026-07-30 13:46:13 +02:00
hans 75232b1460 webview-get-style debugging 2026-07-30 13:41:29 +02:00
hans 31b1e82834 webview-get-style debugging 2026-07-30 13:30:36 +02:00
hans ac961f5fe0 webview-get-style debugging 2026-07-30 13:22:38 +02:00
hans 6a4dd25dfe webview-get-style debugging 2026-07-30 13:19:01 +02:00
hans 97313c1357 webview-get-style debugging 2026-07-30 12:59:37 +02:00
hans 9e6a2a83f4 webview-get-style debugging 2026-07-30 12:54:36 +02:00
hans f29bad676f webview-get-style debugging 2026-07-30 12:29:50 +02:00
hans 41cfd5abd6 solving bug in webview-get-style 2026-07-30 11:56:31 +02:00
hans c02fe6ee99 solving bug in webview-get-style 2026-07-30 11:53:06 +02:00
hans 39b6e1adf5 solving bug in webview-get-style 2026-07-30 11:44:21 +02:00
hans d8ed6235ef racket-mimetypes needs to be a dependency in info.rkt. 2026-07-28 09:05:31 +02:00
hans 13ddedbc11 Mimetypes is now in a module: racket-mimetypes. 2026-07-27 13:31:11 +02:00
hans d33e8164c8 QtWebEngine select popup rendering issue observed with older Qt 6.x.
Symptom: native HTML <select> popup keeps growing/repainting while open;
QtWebEngine process busy, Racket process idle.
Resolved by upgrading to Qt 6.11.1.
2026-07-07 19:24:46 +02:00
hans 9caa41a6f5 Windows has been migrated to Qt 6.11.1 2026-07-07 17:57:56 +02:00
hans 48076b8a38 (js (= x y)) does noet work, needs to be (js (== x y)) 2026-07-03 22:02:43 +02:00
hans 8eeb02a9fa display weg 2026-07-03 19:14:58 +02:00
hans ee5cc863fa Don't display javascript code 2026-07-03 14:32:57 +02:00
hans 9a670acf15 js-maker integration 2026-07-02 15:36:03 +02:00
hans d71f326d88 js-maker integration part 1 2026-06-01 20:18:21 +02:00
hans 231d30c561 migrating to js-maker 2026-05-28 08:17:25 +02:00
hans 325e890737 webview-call-js can return #f, this is now an accepted return value in other webview-.. functions that make use of call-js. 2026-05-19 13:34:52 +02:00
hans c1b0d8559c unexpected result from call-js corrected 2026-05-18 12:57:40 +02:00
hans dff979350a debug webview-call-js 2026-05-18 11:49:48 +02:00
hans 18cd4d3bd9 js-tranform documentented. 2026-05-16 23:17:59 +02:00
hans 3cb7f56167 Repair 2026-05-16 12:45:20 +02:00
hans cc26bd7e13 Merge branch 'main' of https://git.dijkewijk.nl/hans/racket-webview 2026-05-16 12:43:47 +02:00
hans e8acb62f6b Rearranged documentation 2026-05-16 12:40:05 +02:00
31 changed files with 1870 additions and 2261 deletions
+33 -1
View File
@@ -1,3 +1,35 @@
# racket-webview # racket-webview
Webview integration for racket Webview integration for Racket.
## Release v0.1.11
This release assigns explicit, file-prefixed Scribble tags to manual parts and sections. This prevents duplicate collected-information warnings for headings such as `Overview`, `Example`, `Conversion`, `Events`, and `racket-webview` during `raco setup`.
The process-interface changes from v0.1.10 remain unchanged.
### Process interface (introduced in v0.1.10)
This version replaces the FFI/shared-memory transport with a child-process
interface to racket-webview-qt v0.2.3:
- commands: JSON lines on child stdin
- results and events: JSON lines on child stdout
- backend diagnostics: child stderr
The public Racket procedures, command numbers, command payloads, result symbols,
and event JSON remain unchanged. Set `RKT_WEBVIEW_PRG` to an explicit locally
built backend executable during development.
## Previous Qt update
QtWebEngine select popup rendering issues were observed with older Qt 6.x. The
native HTML `<select>` popup could keep growing or repainting while open while
the QtWebEngine process remained busy. Upgrading to Qt 6.11.1 resolved this.
### Qt backend logging
Structured stderr records from `rktwebview_prg` are logged through `simple-log`
under the separate topic `webview-backend`. Ordinary Racket-side messages keep
the topic `webview`. Unstructured stderr lines are accepted and logged at debug
level under `webview-backend`.
+5
View File
@@ -19,6 +19,11 @@
</div> </div>
<p><span id="pos">screen coöords</span></p> <p><span id="pos">screen coöords</span></p>
<h2>Opening a link to some website</h2> <h2>Opening a link to some website</h2>
<label for="sel-lang">Hoi:</label>
<select id="sel-lang">
<option value="nl" selected="selected">Nederlands</option>
<option value="en">English</option>
</select>
<p> <p>
<ul> <ul>
<li><a href="https://wikipedia.org">To Wikipedia</a></li> <li><a href="https://wikipedia.org">To Wikipedia</a></li>
+3 -2
View File
@@ -310,7 +310,8 @@
(webview-set-loglevel 'debug) (webview-set-loglevel 'debug)
(define log-file (build-path (find-system-path 'temp-dir) "example1.log")) (define log-file (build-path (find-system-path 'temp-dir) "example1.log"))
(displayln (format "logging to ~a" log-file)) (displayln (format "logging to ~a" log-file))
(sl-log-to-file log-file) ;(sl-log-to-file log-file)
(define store (sl-log-to-store 10000))
(define (run-example) (define (run-example)
(let* ((ini (new ini% [file 'web-racket-example1])) (let* ((ini (new ini% [file 'web-racket-example1]))
@@ -327,5 +328,5 @@
(let ((window (run-example))) (let ((window (run-example)))
(webview-wait-for-quit) (webview-wait-for-quit)
(webview-exit) (webview-exit)
(exit) ;(exit)
)) ))
+4 -16
View File
@@ -1,28 +1,14 @@
#lang info #lang info
(define pkg-authors '(hnmdijkema)) (define pkg-authors '(hnmdijkema))
(define version "0.1.6") (define version "0.1.11")
(define license 'MIT) (define license 'MIT)
(define collection "racket-webview") (define collection "racket-webview")
(define pkg-desc "racket-webview - A Web Based GUI library, based on a Qt WebEngine backend") (define pkg-desc "racket-webview - A Web Based GUI library, based on a Qt WebEngine backend")
(define scribblings (define scribblings
'( '(
("scrbl/racket-webview-intro.scrbl" () (gui-library) "racket-webview-introduction") ("scrbl/racket-webview-collection.scrbl" (multi-page) (gui-library 0) "racket-webview")
("scrbl/wv-context.scrbl" () (gui-library) "wv-context")
("scrbl/wv-settings.scrbl" () (gui-library) "wv-settings")
("scrbl/wv-window.scrbl" () (gui-library) "wv-window")
("scrbl/wv-tray.scrbl" () (gui-library) "wv-tray")
("scrbl/menu.scrbl" () (gui-library) "menu")
("scrbl/wv-dialog.scrbl" () (gui-library) "wv-dialog")
("scrbl/wv-element.scrbl" () (gui-library) "wv-element")
("scrbl/wv-input.scrbl" () (gui-library) "wv-input")
("scrbl/racket-webview-qt.scrbl" () (gui-library) "racket-webview-qt")
("scrbl/racket-webview.scrbl" () (gui-library) "racket-webview")
("scrbl/rgba.scrbl" () (gui-library) "rgba")
("scrbl/mimetypes.scrbl" () (gui-library) "mimetypes")
("scrbl/rktwebview-api.scrbl" () (gui-library) "rktwebview-api")
("scrbl/rktwebviewqt-internals.scrbl" () (gui-library) "rktwebviewqt-internals")
) )
) )
@@ -42,6 +28,8 @@
"web-server-lib" "web-server-lib"
"net-cookies-lib" "net-cookies-lib"
"simple-log" "simple-log"
"js-maker"
"racket-mimetypes"
) )
) )
-2
View File
@@ -9,7 +9,6 @@
(require "wv-input.rkt") (require "wv-input.rkt")
(require "wv-tray.rkt") (require "wv-tray.rkt")
(require "rgba.rkt") (require "rgba.rkt")
(require "mimetypes.rkt")
(require "menu.rkt") (require "menu.rkt")
(require "private/js-transform.rkt") (require "private/js-transform.rkt")
@@ -20,7 +19,6 @@
"wv-input.rkt" "wv-input.rkt"
"wv-tray.rkt" "wv-tray.rkt"
"rgba.rkt" "rgba.rkt"
"mimetypes.rkt"
"menu.rkt" "menu.rkt"
"racket-webview-downloader.rkt" "racket-webview-downloader.rkt"
"racket-webview.rkt" "racket-webview.rkt"
-724
View File
@@ -1,724 +0,0 @@
#lang racket/base
(require racket/contract)
(provide mimetype-for-ext)
(define/contract (mimetype-for-ext ext)
(-> (or/c string? symbol?) string?)
(hash-ref mimetypes
(if (string? ext) (string->symbol ext) ext)
"application/octet-stream"))
(define mimetypes (make-hash))
(define-syntax addMimeType
(syntax-rules ()
((_ description http-mimetype extensions description2)
(for-each (λ (mimetype)
(unless (hash-has-key? mimetypes mimetype)
(hash-set! mimetypes mimetype http-mimetype)))
extensions))))
(addMimeType "3D Crossword Plugin" "application/vnd.hzn-3d-crossword" '(x3d) "IANA: 3D Crossword Plugin")
(addMimeType "3GP" "video/3gpp" '(3gp) "Wikipedia: 3GP")
(addMimeType "3GP2" "video/3gpp2" '(3g2) "Wikipedia: 3G2")
(addMimeType "3GPP MSEQ File" "application/vnd.mseq" '(mseq) "IANA: 3GPP MSEQ File")
(addMimeType "3M Post It Notes" "application/vnd.3m.post-it-notes" '(pwn) "IANA: 3M Post It Notes")
(addMimeType "3rd Generation Partnership Project - Pic Large" "application/vnd.3gpp.pic-bw-large" '(plb) "3GPP")
(addMimeType "3rd Generation Partnership Project - Pic Small" "application/vnd.3gpp.pic-bw-small" '(psb) "3GPP")
(addMimeType "3rd Generation Partnership Project - Pic Var" "application/vnd.3gpp.pic-bw-var" '(pvb) "3GPP")
(addMimeType "3rd Generation Partnership Project - Transaction Capabilities Application Part" "application/vnd.3gpp2.tcap" '(tcap) "3GPP")
(addMimeType "7-Zip" "application/x-7z-compressed" '(7z) "Wikipedia: 7-Zip")
(addMimeType "AbiWord" "application/x-abiword" '(abw) "Wikipedia: AbiWord")
(addMimeType "Ace Archive" "application/x-ace-compressed" '(ace) "Wikipedia: ACE")
(addMimeType "Active Content Compression" "application/vnd.americandynamics.acc" '(acc) "IANA: Active Content Compression")
(addMimeType "ACU Cobol" "application/vnd.acucobol" '(acu) "IANA: ACU Cobol")
(addMimeType "ACU Cobol" "application/vnd.acucorp" '(atc) "IANA: ACU Cobol")
(addMimeType "Adaptive differential pulse-code modulation" "audio/adpcm" '(adp) "Wikipedia: ADPCM")
(addMimeType "Adobe (Macropedia) Authorware - Binary File" "application/x-authorware-bin" '(aab) "Wikipedia: Authorware")
(addMimeType "Adobe (Macropedia) Authorware - Map" "application/x-authorware-map" '(aam) "Wikipedia: Authorware")
(addMimeType "Adobe (Macropedia) Authorware - Segment File" "application/x-authorware-seg" '(aas) "Wikipedia: Authorware")
(addMimeType "Adobe AIR Application" "application/vnd.adobe.air-application-installer-package+zip" '(air) "Building AIR Applications")
(addMimeType "Adobe Flash" "application/x-shockwave-flash" '(swf) "Wikipedia: Adobe Flash")
(addMimeType "Adobe Flex Project" "application/vnd.adobe.fxp" '(fxp) "IANA: Adobe Flex Project")
(addMimeType "Adobe Portable Document Format" "application/pdf" '(pdf) "Adobe PDF")
(addMimeType "Adobe PostScript Printer Description File Format" "application/vnd.cups-ppd" '(ppd) "IANA: Cups")
(addMimeType "Adobe Shockwave Player" "application/x-director" '(dir) "Wikipedia: Adobe Shockwave Player")
(addMimeType "Adobe XML Data Package" "application/vnd.adobe.xdp+xml" '(xdp) "Wikipedia: XML Data Package")
(addMimeType "Adobe XML Forms Data Format" "application/vnd.adobe.xfdf" '(xfdf) "Wikipedia: XML Portable Document Format")
(addMimeType "Advanced Audio Coding (AAC)" "audio/x-aac" '(aac) "Wikipedia: AAC")
(addMimeType "Ahead AIR Application" "application/vnd.ahead.space" '(ahead) "IANA: Ahead AIR Application")
(addMimeType "AirZip FileSECURE" "application/vnd.airzip.filesecure.azf" '(azf) "IANA: AirZip")
(addMimeType "AirZip FileSECURE" "application/vnd.airzip.filesecure.azs" '(azs) "IANA: AirZip")
(addMimeType "Amazon Kindle eBook format" "application/vnd.amazon.ebook" '(azw) "Kindle Direct Publishing")
(addMimeType "AmigaDE" "application/vnd.amiga.ami" '(ami) "IANA: Amiga")
(addMimeType "Andrew Toolkit" "application/andrew-inset" '(N/A) "IANA - Andrew Inset")
(addMimeType "Android Package Archive" "application/vnd.android.package-archive" '(apk) "Wikipedia: APK File Format")
(addMimeType "ANSER-WEB Terminal Client - Certificate Issue" "application/vnd.anser-web-certificate-issue-initiation" '(cii) "IANA: ANSWER-WEB")
(addMimeType "ANSER-WEB Terminal Client - Web Funds Transfer" "application/vnd.anser-web-funds-transfer-initiation" '(fti) "IANA: ANSWER-WEB")
(addMimeType "Antix Game Player" "application/vnd.antix.game-component" '(atx) "IANA: Antix Game Component")
(addMimeType "Apple Disk Image" "application/x-apple-diskimage" '(dmg) "Apple Disk Image")
(addMimeType "Apple Installer Package" "application/vnd.apple.installer+xml" '(mpkg) "IANA: Apple Installer")
(addMimeType "Applixware" "application/applixware" '(aw) "Vistasource")
(addMimeType "Archipelago Lesson Player" "application/vnd.hhe.lesson-player" '(les) "IANA: Archipelago Lesson Player")
(addMimeType "Archive document - Multiple Fils Embedded" "application/x-freearc" '(arc) "FreeArc")
(addMimeType "Arista Networks Software Image" "application/vnd.aristanetworks.swi" '(swi) "IANA: Arista Networks Software Image")
(addMimeType "Assembler Source File" "text/x-asm" '(s) "Wikipedia: Assembly")
(addMimeType "Atom Publishing Protocol" "application/atomcat+xml" '(atomcat) "RFC 5023")
(addMimeType "Atom Publishing Protocol Service Document" "application/atomsvc+xml" '(atomsvc) "RFC 5023")
(addMimeType "Atom Syndication Format" "application/atom+xml" '(atom xml) "RFC 4287")
(addMimeType "Attribute Certificate" "application/pkix-attr-cert" '(ac) "RFC 5877")
(addMimeType "Audio Interchange File Format" "audio/x-aiff" '(aif) "Wikipedia: Audio Interchange File Format")
(addMimeType "Audio Video Interleave (AVI)" "video/x-msvideo" '(avi) "Wikipedia: AVI")
(addMimeType "Audiograph" "application/vnd.audiograph" '(aep) "IANA: Audiograph")
(addMimeType "AutoCAD DXF" "image/vnd.dxf" '(dxf) "Wikipedia: AutoCAD DXF")
(addMimeType "Autodesk Design Web Format (DWF)" "model/vnd.dwf" '(dwf) "Wikipedia: Design Web Format")
(addMimeType "AV1 Image File" "image/avif" '(avif) "AV1 Image File Format")
(addMimeType "BAS Partitur Format" "text/plain-bas" '(par) "Phonetik BAS")
(addMimeType "Binary CPIO Archive" "application/x-bcpio" '(bcpio) "Wikipedia: cpio")
(addMimeType "Binary Data" "application/octet-stream" '(bin) "")
(addMimeType "Bitmap Image File" "image/bmp" '(bmp) "Wikipedia: BMP File Format")
(addMimeType "BitTorrent" "application/x-bittorrent" '(torrent) "Wikipedia: BitTorrent")
(addMimeType "Blackberry COD File" "application/vnd.rim.cod" '(cod) "")
(addMimeType "Blueice Research Multipass" "application/vnd.blueice.multipass" '(mpm) "IANA: Multipass")
(addMimeType "BMI Drawing Data Interchange" "application/vnd.bmi" '(bmi) "IANA: BMI")
(addMimeType "Bourne Shell Script" "application/x-sh" '(sh) "Wikipedia: Bourne Shell")
(addMimeType "BTIF" "image/prs.btif" '(btif) "IANA: BTIF")
(addMimeType "BusinessObjects" "application/vnd.businessobjects" '(rep) "IANA: BusinessObjects")
(addMimeType "Bzip Archive" "application/x-bzip" '(bz) "Wikipedia: Bzip")
(addMimeType "Bzip2 Archive" "application/x-bzip2" '(bz2) "Wikipedia: Bzip")
(addMimeType "C Shell Script" "application/x-csh" '(csh) "Wikipedia: C Shell")
(addMimeType "C Source File" "text/x-c" '(c) "Wikipedia: C Programming Language")
(addMimeType "CambridgeSoft Chem Draw" "application/vnd.chemdraw+xml" '(cdxml) "IANA: Chem Draw")
(addMimeType "Cascading Style Sheets (CSS)" "text/css" '(css) "Wikipedia: CSS")
(addMimeType "CD Audio" "application/x-cdf" '(cda) "Wikipedia: CDA File")
(addMimeType "ChemDraw eXchange file" "chemical/x-cdx" '(cdx) "ChemDraw eXchange file")
(addMimeType "Chemical Markup Language" "chemical/x-cml" '(cml) "Wikipedia: Chemical Markup Language")
(addMimeType "Chemical Style Markup Language" "chemical/x-csml" '(csml) "Wikipedia: Chemical Style Markup Language")
(addMimeType "CIM Database" "application/vnd.contact.cmsg" '(cdbcmsg) "IANA: CIM Database")
(addMimeType "Claymore Data Files" "application/vnd.claymore" '(cla) "IANA: Claymore")
(addMimeType "Clonk Game" "application/vnd.clonk.c4group" '(c4g) "IANA: Clonk")
(addMimeType "Close Captioning - Subtitle" "image/vnd.dvb.subtitle" '(sub) "Wikipedia: Closed Captioning")
(addMimeType "Cloud Data Management Interface (CDMI) - Capability" "application/cdmi-capability" '(cdmia) "RFC 6208")
(addMimeType "Cloud Data Management Interface (CDMI) - Contaimer" "application/cdmi-container" '(cdmic) "RFC 6209")
(addMimeType "Cloud Data Management Interface (CDMI) - Domain" "application/cdmi-domain" '(cdmid) "RFC 6210")
(addMimeType "Cloud Data Management Interface (CDMI) - Object" "application/cdmi-object" '(cdmio) "RFC 6211")
(addMimeType "Cloud Data Management Interface (CDMI) - Queue" "application/cdmi-queue" '(cdmiq) "RFC 6212")
(addMimeType "ClueTrust CartoMobile - Config" "application/vnd.cluetrust.cartomobile-config" '(c11amc) "IANA: CartoMobile")
(addMimeType "ClueTrust CartoMobile - Config Package" "application/vnd.cluetrust.cartomobile-config-pkg" '(c11amz) "IANA: CartoMobile")
(addMimeType "CMU Image" "image/x-cmu-raster" '(ras) "")
(addMimeType "COLLADA" "model/vnd.collada+xml" '(dae) "IANA: COLLADA")
(addMimeType "Comma-Seperated Values" "text/csv" '(csv) "Wikipedia: CSV")
(addMimeType "Compact Pro" "application/mac-compactpro" '(cpt) "Compact Pro")
(addMimeType "Compiled Wireless Markup Language (WMLC)" "application/vnd.wap.wmlc" '(wmlc) "IANA: WMLC")
(addMimeType "Computer Graphics Metafile" "image/cgm" '(cgm) "Wikipedia: Computer Graphics Metafile")
(addMimeType "CoolTalk" "x-conference/x-cooltalk" '(ice) "Wikipedia: CoolTalk")
(addMimeType "Corel Metafile Exchange (CMX)" "image/x-cmx" '(cmx) "Wikipedia: CorelDRAW")
(addMimeType "CorelXARA" "application/vnd.xara" '(xar) "IANA: CorelXARA")
(addMimeType "CosmoCaller" "application/vnd.cosmocaller" '(cmc) "IANA: CosmoCaller")
(addMimeType "CPIO Archive" "application/x-cpio" '(cpio) "Wikipedia: cpio")
(addMimeType "CrickSoftware - Clicker" "application/vnd.crick.clicker" '(clkx) "IANA: Clicker")
(addMimeType "CrickSoftware - Clicker - Keyboard" "application/vnd.crick.clicker.keyboard" '(clkk) "IANA: Clicker")
(addMimeType "CrickSoftware - Clicker - Palette" "application/vnd.crick.clicker.palette" '(clkp) "IANA: Clicker")
(addMimeType "CrickSoftware - Clicker - Template" "application/vnd.crick.clicker.template" '(clkt) "IANA: Clicker")
(addMimeType "CrickSoftware - Clicker - Wordbank" "application/vnd.crick.clicker.wordbank" '(clkw) "IANA: Clicker")
(addMimeType "Critical Tools - PERT Chart EXPERT" "application/vnd.criticaltools.wbs+xml" '(wbs) "IANA: Critical Tools")
(addMimeType "CryptoNote" "application/vnd.rig.cryptonote" '(cryptonote) "IANA: CryptoNote")
(addMimeType "Crystallographic Interchange Format" "chemical/x-cif" '(cif) "Crystallographic Interchange Format")
(addMimeType "CrystalMaker Data Format" "chemical/x-cmdf" '(cmdf) "CrystalMaker Data Format")
(addMimeType "CU-SeeMe" "application/cu-seeme" '(cu) "White Pine")
(addMimeType "CU-Writer" "application/prs.cww" '(cww) "")
(addMimeType "Curl - Applet" "text/vnd.curl" '(curl) "Curl Applet")
(addMimeType "Curl - Detached Applet" "text/vnd.curl.dcurl" '(dcurl) "Curl Detached Applet")
(addMimeType "Curl - Manifest File" "text/vnd.curl.mcurl" '(mcurl) "Curl Manifest File")
(addMimeType "Curl - Source Code" "text/vnd.curl.scurl" '(scurl) "Curl Source Code")
(addMimeType "CURL Applet" "application/vnd.curl.car" '(car) "IANA: CURL Applet")
(addMimeType "CURL Applet" "application/vnd.curl.pcurl" '(pcurl) "IANA: CURL Applet")
(addMimeType "CustomMenu" "application/vnd.yellowriver-custom-menu" '(cmp) "IANA: CustomMenu")
(addMimeType "Data Structure for the Security Suitability of Cryptographic Algorithms" "application/dssc+der" '(dssc) "RFC 5698")
(addMimeType "Data Structure for the Security Suitability of Cryptographic Algorithms" "application/dssc+xml" '(xdssc) "RFC 5698")
(addMimeType "Debian Package" "application/x-debian-package" '(deb) "Wikipedia: Debian Package")
(addMimeType "DECE Audio" "audio/vnd.dece.audio" '(uva) "IANA: Dece Audio")
(addMimeType "DECE Graphic" "image/vnd.dece.graphic" '(uvi) "IANA: DECE Graphic")
(addMimeType "DECE High Definition Video" "video/vnd.dece.hd" '(uvh) "IANA: DECE HD Video")
(addMimeType "DECE Mobile Video" "video/vnd.dece.mobile" '(uvm) "IANA: DECE Mobile Video")
(addMimeType "DECE MP4" "video/vnd.uvvu.mp4" '(uvu) "IANA: DECE MP4")
(addMimeType "DECE PD Video" "video/vnd.dece.pd" '(uvp) "IANA: DECE PD Video")
(addMimeType "DECE SD Video" "video/vnd.dece.sd" '(uvs) "IANA: DECE SD Video")
(addMimeType "DECE Video" "video/vnd.dece.video" '(uvv) "IANA: DECE Video")
(addMimeType "Device Independent File Format (DVI)" "application/x-dvi" '(dvi) "Wikipedia: DVI")
(addMimeType "Digital Siesmograph Networks - SEED Datafiles" "application/vnd.fdsn.seed" '(seed) "IANA: SEED")
(addMimeType "Digital Talking Book" "application/x-dtbook+xml" '(dtb) "Wikipedia: EPUB")
(addMimeType "Digital Talking Book - Resource File" "application/x-dtbresource+xml" '(res) "Digital Talking Book")
(addMimeType "Digital Video Broadcasting" "application/vnd.dvb.ait" '(ait) "IANA: Digital Video Broadcasting")
(addMimeType "Digital Video Broadcasting" "application/vnd.dvb.service" '(svc) "IANA: Digital Video Broadcasting")
(addMimeType "Digital Winds Music" "audio/vnd.digital-winds" '(eol) "IANA: Digital Winds")
(addMimeType "DjVu" "image/vnd.djvu" '(djvu) "Wikipedia: DjVu")
(addMimeType "Document Type Definition" "application/xml-dtd" '(dtd) "W3C DTD")
(addMimeType "Dolby Meridian Lossless Packing" "application/vnd.dolby.mlp" '(mlp) "IANA: Dolby Meridian Lossless Packing")
(addMimeType "Doom Video Game" "application/x-doom" '(wad) "Wikipedia: Doom WAD")
(addMimeType "DPGraph" "application/vnd.dpgraph" '(dpg) "IANA: DPGraph")
(addMimeType "DRA Audio" "audio/vnd.dra" '(dra) "IANA: DRA")
(addMimeType "DreamFactory" "application/vnd.dreamfactory" '(dfac) "IANA: DreamFactory")
(addMimeType "DTS Audio" "audio/vnd.dts" '(dts) "IANA: DTS")
(addMimeType "DTS High Definition Audio" "audio/vnd.dts.hd" '(dtshd) "IANA: DTS HD")
(addMimeType "DWG Drawing" "image/vnd.dwg" '(dwg) "Wikipedia: DWG")
(addMimeType "DynaGeo" "application/vnd.dynageo" '(geo) "IANA: DynaGeo")
(addMimeType "ECMAScript" "application/ecmascript" '(es) "ECMA-357")
(addMimeType "EcoWin Chart" "application/vnd.ecowin.chart" '(mag) "IANA: EcoWin Chart")
(addMimeType "EDMICS 2000" "image/vnd.fujixerox.edmics-mmr" '(mmr) "IANA: EDMICS 2000")
(addMimeType "EDMICS 2000" "image/vnd.fujixerox.edmics-rlc" '(rlc) "IANA: EDMICS 2000")
(addMimeType "Efficient XML Interchange" "application/exi" '(exi) "Efficient XML Interchange (EXI) Best Practices")
(addMimeType "EFI Proteus" "application/vnd.proteus.magazine" '(mgz) "IANA: EFI Proteus")
(addMimeType "Electronic Publication" "application/epub+zip" '(epub) "Wikipedia: EPUB")
(addMimeType "Email Message" "message/rfc822" '(eml) "RFC 2822")
(addMimeType "Enliven Viewer" "application/vnd.enliven" '(nml) "IANA: Enliven Viewer")
(addMimeType "Express by Infoseek" "application/vnd.is-xpr" '(xpr) "IANA: Express by Infoseek")
(addMimeType "eXtended Image File Format (XIFF)" "image/vnd.xiff" '(xif) "IANA: XIFF")
(addMimeType "Extensible Forms Description Language" "application/vnd.xfdl" '(xfdl) "IANA: Extensible Forms Description Language")
(addMimeType "Extensible MultiModal Annotation" "application/emma+xml" '(emma) "EMMA: Extensible MultiModal Annotation markup language")
(addMimeType "EZPix Secure Photo Album" "application/vnd.ezpix-album" '(ez2) "IANA: EZPix Secure Photo Album")
(addMimeType "EZPix Secure Photo Album" "application/vnd.ezpix-package" '(ez3) "IANA: EZPix Secure Photo Album")
(addMimeType "FAST Search & Transfer ASA" "image/vnd.fst" '(fst) "IANA: FAST Search & Transfer ASA")
(addMimeType "FAST Search & Transfer ASA" "video/vnd.fvt" '(fvt) "IANA: FVT")
(addMimeType "FastBid Sheet" "image/vnd.fastbidsheet" '(fbs) "IANA: FastBid Sheet")
(addMimeType "FCS Express Layout Link" "application/vnd.denovo.fcselayout-link" '(fe_launch) "IANA: FCS Express Layout Link")
(addMimeType "Flash Video" "video/x-f4v" '(f4v) "Wikipedia: Flash Video")
(addMimeType "Flash Video" "video/x-flv" '(flv) "Wikipedia: Flash Video")
(addMimeType "FlashPix" "image/vnd.fpx" '(fpx) "IANA: FPX")
(addMimeType "FlashPix" "image/vnd.net-fpx" '(npx) "IANA: FPX")
(addMimeType "FLEXSTOR" "text/vnd.fmi.flexstor" '(flx) "IANA: FLEXSTOR")
(addMimeType "FLI/FLC Animation Format" "video/x-fli" '(fli) "FLI/FLC Animation Format")
(addMimeType "FluxTime Clip" "application/vnd.fluxtime.clip" '(ftc) "IANA: FluxTime Clip")
(addMimeType "Forms Data Format" "application/vnd.fdf" '(fdf) "IANA: Forms Data Format")
(addMimeType "Fortran Source File" "text/x-fortran" '(f) "Wikipedia: Fortran")
(addMimeType "FrameMaker Interchange Format" "application/vnd.mif" '(mif) "IANA: FrameMaker Interchange Format")
(addMimeType "FrameMaker Normal Format" "application/vnd.framemaker" '(fm) "IANA: FrameMaker")
(addMimeType "FreeHand MX" "image/x-freehand" '(fh) "Wikipedia: Macromedia Freehand")
(addMimeType "Friendly Software Corporation" "application/vnd.fsc.weblaunch" '(fsc) "IANA: Friendly Software Corporation")
(addMimeType "Frogans Player" "application/vnd.frogans.fnc" '(fnc) "IANA: Frogans Player")
(addMimeType "Frogans Player" "application/vnd.frogans.ltf" '(ltf) "IANA: Frogans Player")
(addMimeType "Fujitsu - Xerox 2D CAD Data" "application/vnd.fujixerox.ddd" '(ddd) "IANA: Fujitsu DDD")
(addMimeType "Fujitsu - Xerox DocuWorks" "application/vnd.fujixerox.docuworks" '(xdw) "IANA: Docuworks")
(addMimeType "Fujitsu - Xerox DocuWorks Binder" "application/vnd.fujixerox.docuworks.binder" '(xbd) "IANA: Docuworks Binder")
(addMimeType "Fujitsu Oasys" "application/vnd.fujitsu.oasys" '(oas) "IANA: Fujitsu Oasys")
(addMimeType "Fujitsu Oasys" "application/vnd.fujitsu.oasys2" '(oa2) "IANA: Fujitsu Oasys")
(addMimeType "Fujitsu Oasys" "application/vnd.fujitsu.oasys3" '(oa3) "IANA: Fujitsu Oasys")
(addMimeType "Fujitsu Oasys" "application/vnd.fujitsu.oasysgp" '(fg5) "IANA: Fujitsu Oasys")
(addMimeType "Fujitsu Oasys" "application/vnd.fujitsu.oasysprs" '(bh2) "IANA: Fujitsu Oasys")
(addMimeType "FutureSplash Animator" "application/x-futuresplash" '(spl) "Wikipedia: FutureSplash Animator")
(addMimeType "FuzzySheet" "application/vnd.fuzzysheet" '(fzs) "IANA: FuzySheet")
(addMimeType "G3 Fax Image" "image/g3fax" '(g3) "Wikipedia: G3 Fax Image")
(addMimeType "GameMaker ActiveX" "application/vnd.gmx" '(gmx) "IANA: GameMaker ActiveX")
(addMimeType "Gen-Trix Studio" "model/vnd.gtw" '(gtw) "IANA: GTW")
(addMimeType "Genomatix Tuxedo Framework" "application/vnd.genomatix.tuxedo" '(txd) "IANA: Genomatix Tuxedo Framework")
(addMimeType "GeoGebra" "application/vnd.geogebra.file" '(ggb) "IANA: GeoGebra")
(addMimeType "GeoGebra" "application/vnd.geogebra.tool" '(ggt) "IANA: GeoGebra")
(addMimeType "Geometric Description Language (GDL)" "model/vnd.gdl" '(gdl) "IANA: GDL")
(addMimeType "GeoMetry Explorer" "application/vnd.geometry-explorer" '(gex) "IANA: GeoMetry Explorer")
(addMimeType "GEONExT and JSXGraph" "application/vnd.geonext" '(gxt) "IANA: GEONExT and JSXGraph")
(addMimeType "GeoplanW" "application/vnd.geoplan" '(g2w) "IANA: GeoplanW")
(addMimeType "GeospacW" "application/vnd.geospace" '(g3w) "IANA: GeospacW")
(addMimeType "Ghostscript Font" "application/x-font-ghostscript" '(gsf) "Wikipedia: Ghostscript")
(addMimeType "Glyph Bitmap Distribution Format" "application/x-font-bdf" '(bdf) "Wikipedia: Glyph Bitmap Distribution Format")
(addMimeType "GNU Tar Files" "application/x-gtar" '(gtar) "GNU Tar")
(addMimeType "GNU Texinfo Document" "application/x-texinfo" '(texinfo) "Wikipedia: Texinfo")
(addMimeType "Gnumeric" "application/x-gnumeric" '(gnumeric) "Wikipedia: Gnumeric")
(addMimeType "Google Earth - KML" "application/vnd.google-earth.kml+xml" '(kml) "IANA: Google Earth")
(addMimeType "Google Earth - Zipped KML" "application/vnd.google-earth.kmz" '(kmz) "IANA: Google Earth")
(addMimeType "GPS eXchange Format" "application/gpx+xml" '(gpx) "GPS eXchange Format")
(addMimeType "GrafEq" "application/vnd.grafeq" '(gqf) "IANA: GrafEq")
(addMimeType "Graphics Interchange Format" "image/gif" '(gif) "Wikipedia: Graphics Interchange Format")
(addMimeType "Graphviz" "text/vnd.graphviz" '(gv) "IANA: Graphviz")
(addMimeType "Groove - Account" "application/vnd.groove-account" '(gac) "IANA: Groove")
(addMimeType "Groove - Help" "application/vnd.groove-help" '(ghf) "IANA: Groove")
(addMimeType "Groove - Identity Message" "application/vnd.groove-identity-message" '(gim) "IANA: Groove")
(addMimeType "Groove - Injector" "application/vnd.groove-injector" '(grv) "IANA: Groove")
(addMimeType "Groove - Tool Message" "application/vnd.groove-tool-message" '(gtm) "IANA: Groove")
(addMimeType "Groove - Tool Template" "application/vnd.groove-tool-template" '(tpl) "IANA: Groove")
(addMimeType "Groove - Vcard" "application/vnd.groove-vcard" '(vcg) "IANA: Groove")
(addMimeType "GZip" "application/gzip" '(gz) "Wikipedia: GZip")
(addMimeType "H.261" "video/h261" '(h261) "Wikipedia: H.261")
(addMimeType "H.263" "video/h263" '(h263) "Wikipedia: H.263")
(addMimeType "H.264" "video/h264" '(h264) "Wikipedia: H.264")
(addMimeType "Hewlett Packard Instant Delivery" "application/vnd.hp-hpid" '(hpid) "IANA: Hewlett Packard Instant Delivery")
(addMimeType "Hewlett-Packard's WebPrintSmart" "application/vnd.hp-hps" '(hps) "IANA: Hewlett-Packard's WebPrintSmart")
(addMimeType "Hierarchical Data Format" "application/x-hdf" '(hdf) "Wikipedia: Hierarchical Data Format")
(addMimeType "Hit'n'Mix" "audio/vnd.rip" '(rip) "IANA: Hit'n'Mix")
(addMimeType "Homebanking Computer Interface (HBCI)" "application/vnd.hbci" '(hbci) "IANA: HBCI")
(addMimeType "HP Indigo Digital Press - Job Layout Languate" "application/vnd.hp-jlyt" '(jlt) "IANA: HP Job Layout Language")
(addMimeType "HP Printer Command Language" "application/vnd.hp-pcl" '(pcl) "IANA: HP Printer Command Language")
(addMimeType "HP-GL/2 and HP RTL" "application/vnd.hp-hpgl" '(hpgl) "IANA: HP-GL/2 and HP RTL")
(addMimeType "HV Script" "application/vnd.yamaha.hv-script" '(hvs) "IANA: HV Script")
(addMimeType "HV Voice Dictionary" "application/vnd.yamaha.hv-dic" '(hvd) "IANA: HV Voice Dictionary")
(addMimeType "HV Voice Parameter" "application/vnd.yamaha.hv-voice" '(hvp) "IANA: HV Voice Parameter")
(addMimeType "Hydrostatix Master Suite" "application/vnd.hydrostatix.sof-data" '(sfd-hdstx) "IANA: Hydrostatix Master Suite")
(addMimeType "Hyperstudio" "application/hyperstudio" '(stk) "IANA - Hyperstudio")
(addMimeType "Hypertext Application Language" "application/vnd.hal+xml" '(hal) "IANA: HAL")
(addMimeType "HyperText Markup Language (HTML)" "text/html" '(html) "Wikipedia: HTML")
(addMimeType "IBM DB2 Rights Manager" "application/vnd.ibm.rights-management" '(irm) "IANA: IBM DB2 Rights Manager")
(addMimeType "IBM Electronic Media Management System - Secure Container" "application/vnd.ibm.secure-container" '(sc) "IANA: EMMS")
(addMimeType "iCalendar" "text/calendar" '(ics) "Wikipedia: iCalendar")
(addMimeType "ICC profile" "application/vnd.iccprofile" '(icc) "IANA: ICC profile")
(addMimeType "Icon Image" "image/x-icon" '(ico) "Wikipedia: ICO File Format")
(addMimeType "igLoader" "application/vnd.igloader" '(igl) "IANA: igLoader")
(addMimeType "Image Exchange Format" "image/ief" '(ief) "RFC 1314")
(addMimeType "ImmerVision PURE Players" "application/vnd.immervision-ivp" '(ivp) "IANA: ImmerVision PURE Players")
(addMimeType "ImmerVision PURE Players" "application/vnd.immervision-ivu" '(ivu) "IANA: ImmerVision PURE Players")
(addMimeType "IMS Networks" "application/reginfo+xml" '(rif) "")
(addMimeType "In3D - 3DML" "text/vnd.in3d.3dml" '(3dml) "IANA: In3D")
(addMimeType "In3D - 3DML" "text/vnd.in3d.spot" '(spot) "IANA: In3D")
(addMimeType "Initial Graphics Exchange Specification (IGES)" "model/iges" '(igs) "Wikipedia: IGES")
(addMimeType "Interactive Geometry Software" "application/vnd.intergeo" '(i2g) "IANA: Interactive Geometry Software")
(addMimeType "Interactive Geometry Software Cinderella" "application/vnd.cinderella" '(cdy) "IANA: Cinderella")
(addMimeType "Intercon FormNet" "application/vnd.intercon.formnet" '(xpw) "IANA: Intercon FormNet")
(addMimeType "International Society for Advancement of Cytometry" "application/vnd.isac.fcs" '(fcs) "IANA: International Society for Advancement of Cytometry")
(addMimeType "Internet Protocol Flow Information Export" "application/ipfix" '(ipfix) "RFC 3917")
(addMimeType "Internet Public Key Infrastructure - Certificate" "application/pkix-cert" '(cer) "RFC 2585")
(addMimeType "Internet Public Key Infrastructure - Certificate Management Protocole" "application/pkixcmp" '(pki) "RFC 2585")
(addMimeType "Internet Public Key Infrastructure - Certificate Revocation Lists" "application/pkix-crl" '(crl) "RFC 2585")
(addMimeType "Internet Public Key Infrastructure - Certification Path" "application/pkix-pkipath" '(pkipath) "RFC 2585")
(addMimeType "IOCOM Visimeet" "application/vnd.insors.igm" '(igm) "IANA: IOCOM Visimeet")
(addMimeType "IP Unplugged Roaming Client" "application/vnd.ipunplugged.rcprofile" '(rcprofile) "IANA: IP Unplugged Roaming Client")
(addMimeType "iRepository / Lucidoc Editor" "application/vnd.irepository.package+xml" '(irp) "IANA: iRepository / Lucidoc Editor")
(addMimeType "J2ME App Descriptor" "text/vnd.sun.j2me.app-descriptor" '(jad) "IANA: J2ME App Descriptor")
(addMimeType "Java Archive" "application/java-archive" '(jar) "Wikipedia: JAR file format")
(addMimeType "Java Bytecode File" "application/java-vm" '(class) "Wikipedia: Java Bytecode")
(addMimeType "Java Network Launching Protocol" "application/x-java-jnlp-file" '(jnlp) "Wikipedia: Java Web Start")
(addMimeType "Java Serialized Object" "application/java-serialized-object" '(ser) "Java Serialization API")
(addMimeType "Java Source File" "text/x-java-source,java" '(java) "Wikipedia: Java")
(addMimeType "JavaScript" "application/javascript" '(js) "JavaScript")
(addMimeType "JavaScript Module" "text/javascript" '(mjs) "Wikipedia: Javascript")
(addMimeType "JavaScript Module" "text/javascript" '(mjs) "ECMAScript modules")
(addMimeType "JavaScript Object Notation (JSON)" "application/json" '(json) "Wikipedia: JSON")
(addMimeType "Joda Archive" "application/vnd.joost.joda-archive" '(joda) "IANA: Joda Archive")
(addMimeType "JPEG Image" "image/jpeg" '(jpeg jpg) "RFC 1314")
(addMimeType "JPEG 2000 Compound Image File Format" "video/jpm" '(jpm) "IANA: JPM")
(addMimeType "JPEG Image (Citrix client)" "image/x-citrix-jpeg" '(jpeg jpg) "RFC 1314")
(addMimeType "JPEG Image (Progressive)" "image/pjpeg" '(pjpeg) "JPEG image compression FAQ")
(addMimeType "JPGVideo" "video/jpeg" '(jpgv) "RFC 3555")
(addMimeType "JSON - Linked Data" "application/ld+json" '(jsonld) "Wikipedia: JSON-LD")
(addMimeType "Kahootz" "application/vnd.kahootz" '(ktz) "IANA: Kahootz")
(addMimeType "Karaoke on Chipnuts Chipsets" "application/vnd.chipnuts.karaoke-mmd" '(mmd) "IANA: Chipnuts Karaoke")
(addMimeType "KDE KOffice Office Suite - Karbon" "application/vnd.kde.karbon" '(karbon) "IANA: KDE KOffice Office Suite")
(addMimeType "KDE KOffice Office Suite - KChart" "application/vnd.kde.kchart" '(chrt) "IANA: KDE KOffice Office Suite")
(addMimeType "KDE KOffice Office Suite - Kformula" "application/vnd.kde.kformula" '(kfo) "IANA: KDE KOffice Office Suite")
(addMimeType "KDE KOffice Office Suite - Kivio" "application/vnd.kde.kivio" '(flw) "IANA: KDE KOffice Office Suite")
(addMimeType "KDE KOffice Office Suite - Kontour" "application/vnd.kde.kontour" '(kon) "IANA: KDE KOffice Office Suite")
(addMimeType "KDE KOffice Office Suite - Kpresenter" "application/vnd.kde.kpresenter" '(kpr) "IANA: KDE KOffice Office Suite")
(addMimeType "KDE KOffice Office Suite - Kspread" "application/vnd.kde.kspread" '(ksp) "IANA: KDE KOffice Office Suite")
(addMimeType "KDE KOffice Office Suite - Kword" "application/vnd.kde.kword" '(kwd) "IANA: KDE KOffice Office Suite")
(addMimeType "Kenamea App" "application/vnd.kenameaapp" '(htke) "IANA: Kenamea App")
(addMimeType "Kidspiration" "application/vnd.kidspiration" '(kia) "IANA: Kidspiration")
(addMimeType "Kinar Applications" "application/vnd.kinar" '(kne) "IANA: Kina Applications")
(addMimeType "Kodak Storyshare" "application/vnd.kodak-descriptor" '(sse) "IANA: Kodak Storyshare")
(addMimeType "Laser App Enterprise" "application/vnd.las.las+xml" '(lasxml) "IANA: Laser App Enterprise")
(addMimeType "LaTeX" "application/x-latex" '(latex) "Wikipedia: LaTeX")
(addMimeType "Life Balance - Desktop Edition" "application/vnd.llamagraphics.life-balance.desktop" '(lbd) "IANA: Life Balance")
(addMimeType "Life Balance - Exchange Format" "application/vnd.llamagraphics.life-balance.exchange+xml" '(lbe) "IANA: Life Balance")
(addMimeType "Lightspeed Audio Lab" "application/vnd.jam" '(jam) "IANA: Lightspeed Audio Lab")
(addMimeType "Lotus 1-2-3" "application/vnd.lotus-1-2-3" '(123) "IANA: Lotus 1-2-3")
(addMimeType "Lotus Approach" "application/vnd.lotus-approach" '(apr) "IANA: Lotus Approach")
(addMimeType "Lotus Freelance" "application/vnd.lotus-freelance" '(pre) "IANA: Lotus Freelance")
(addMimeType "Lotus Notes" "application/vnd.lotus-notes" '(nsf) "IANA: Lotus Notes")
(addMimeType "Lotus Organizer" "application/vnd.lotus-organizer" '(org) "IANA: Lotus Organizer")
(addMimeType "Lotus Screencam" "application/vnd.lotus-screencam" '(scm) "IANA: Lotus Screencam")
(addMimeType "Lotus Wordpro" "application/vnd.lotus-wordpro" '(lwp) "IANA: Lotus Wordpro")
(addMimeType "Lucent Voice" "audio/vnd.lucent.voice" '(lvp) "IANA: Lucent Voice")
(addMimeType "M3U (Multimedia Playlist)" "audio/x-mpegurl" '(m3u) "Wikipedia: M3U")
(addMimeType "M4v" "video/x-m4v" '(m4v) "Wikipedia: M4v")
(addMimeType "Macintosh BinHex 4.0" "application/mac-binhex40" '(hqx) "MacMIME")
(addMimeType "MacPorts Port System" "application/vnd.macports.portpkg" '(portpkg) "IANA: MacPorts Port System")
(addMimeType "MapGuide DBXML" "application/vnd.osgeo.mapguide.package" '(mgp) "IANA: MapGuide DBXML")
(addMimeType "MARC Formats" "application/marc" '(mrc) "RFC 2220")
(addMimeType "MARC21 XML Schema" "application/marcxml+xml" '(mrcx) "RFC 6207")
(addMimeType "Material Exchange Format" "application/mxf" '(mxf) "RFC 4539")
(addMimeType "Mathematica Notebook Player" "application/vnd.wolfram.player" '(nbp) "IANA: Mathematica Notebook Player")
(addMimeType "Mathematica Notebooks" "application/mathematica" '(ma) "IANA - Mathematica")
(addMimeType "Mathematical Markup Language" "application/mathml+xml" '(mathml) "W3C Math Home")
(addMimeType "Mbox database files" "application/mbox" '(mbox) "RFC 4155")
(addMimeType "MedCalc" "application/vnd.medcalcdata" '(mc1) "IANA: MedCalc")
(addMimeType "Media Server Control Markup Language" "application/mediaservercontrol+xml" '(mscml) "RFC 5022")
(addMimeType "MediaRemote" "application/vnd.mediastation.cdkey" '(cdkey) "IANA: MediaRemote")
(addMimeType "Medical Waveform Encoding Format" "application/vnd.mfer" '(mwf) "IANA: Medical Waveform Encoding Format")
(addMimeType "Melody Format for Mobile Platform" "application/vnd.mfmp" '(mfm) "IANA: Melody Format for Mobile Platform")
(addMimeType "Mesh Data Type" "model/mesh" '(msh) "RFC 2077")
(addMimeType "Metadata Authority Description Schema" "application/mads+xml" '(mads) "RFC 6207")
(addMimeType "Metadata Encoding and Transmission Standard" "application/mets+xml" '(mets) "RFC 6207")
(addMimeType "Metadata Object Description Schema" "application/mods+xml" '(mods) "RFC 6207")
(addMimeType "Metalink" "application/metalink4+xml" '(meta4) "Wikipedia: Metalink")
(addMimeType "Micro CADAM Helix D&D" "application/vnd.mcd" '(mcd) "IANA: Micro CADAM Helix D&D")
(addMimeType "Micrografx" "application/vnd.micrografx.flo" '(flo) "IANA: Micrografx")
(addMimeType "Micrografx iGrafx Professional" "application/vnd.micrografx.igx" '(igx) "IANA: Micrografx")
(addMimeType "MICROSEC e-Szign?" "application/vnd.eszigno3+xml" '(es3) "IANA: MICROSEC e-Szign?")
(addMimeType "Microsoft Access" "application/x-msaccess" '(mdb) "Wikipedia: Microsoft Access")
(addMimeType "Microsoft Advanced Systems Format (ASF)" "video/x-ms-asf" '(asf) "Wikipedia: Advanced Systems Format (ASF)")
(addMimeType "Microsoft Application" "application/x-msdownload" '(exe) "Wikipedia: EXE")
(addMimeType "Microsoft Artgalry" "application/vnd.ms-artgalry" '(cil) "IANA: MS Artgalry")
(addMimeType "Microsoft Cabinet File" "application/vnd.ms-cab-compressed" '(cab) "IANA: MS Cabinet File")
(addMimeType "Microsoft Class Server" "application/vnd.ms-ims" '(ims) "IANA: MS Class Server")
(addMimeType "Microsoft ClickOnce" "application/x-ms-application" '(application) "Wikipedia: ClickOnce")
(addMimeType "Microsoft Clipboard Clip" "application/x-msclip" '(clp) "Wikipedia: Clipboard")
(addMimeType "Microsoft Document Imaging Format" "image/vnd.ms-modi" '(mdi) "Wikipedia: Microsoft Document Image Format")
(addMimeType "Microsoft Embedded OpenType" "application/vnd.ms-fontobject" '(eot) "IANA: MS Embedded OpenType")
(addMimeType "Microsoft Excel" "application/vnd.ms-excel" '(xls) "IANA: MS Excel")
(addMimeType "Microsoft Excel - Add-In File" "application/vnd.ms-excel.addin.macroenabled.12" '(xlam) "IANA: MS Excel")
(addMimeType "Microsoft Excel - Binary Workbook" "application/vnd.ms-excel.sheet.binary.macroenabled.12" '(xlsb) "IANA: MS Excel")
(addMimeType "Microsoft Excel - Macro-Enabled Template File" "application/vnd.ms-excel.template.macroenabled.12" '(xltm) "IANA: MS Excel")
(addMimeType "Microsoft Excel - Macro-Enabled Workbook" "application/vnd.ms-excel.sheet.macroenabled.12" '(xlsm) "IANA: MS Excel")
(addMimeType "Microsoft Html Help File" "application/vnd.ms-htmlhelp" '(chm) "IANA:MS Html Help File")
(addMimeType "Microsoft Information Card" "application/x-mscardfile" '(crd) "Wikipedia: Information Card")
(addMimeType "Microsoft Learning Resource Module" "application/vnd.ms-lrm" '(lrm) "IANA: MS Learning Resource Module")
(addMimeType "Microsoft MediaView" "application/x-msmediaview" '(mvb) "Windows Help")
(addMimeType "Microsoft Money" "application/x-msmoney" '(mny) "Wikipedia: Microsoft Money")
(addMimeType "Microsoft Office - OOXML - Presentation" "application/vnd.openxmlformats-officedocument.presentationml.presentation" '(pptx) "IANA: OOXML - Presentation")
(addMimeType "Microsoft Office - OOXML - Presentation (Slide)" "application/vnd.openxmlformats-officedocument.presentationml.slide" '(sldx) "IANA: OOXML - Presentation")
(addMimeType "Microsoft Office - OOXML - Presentation (Slideshow)" "application/vnd.openxmlformats-officedocument.presentationml.slideshow" '(ppsx) "IANA: OOXML - Presentation")
(addMimeType "Microsoft Office - OOXML - Presentation Template" "application/vnd.openxmlformats-officedocument.presentationml.template" '(potx) "IANA: OOXML - Presentation Template")
(addMimeType "Microsoft Office - OOXML - Spreadsheet" "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" '(xlsx) "IANA: OOXML - Spreadsheet")
(addMimeType "Microsoft Office - OOXML - Spreadsheet Template" "application/vnd.openxmlformats-officedocument.spreadsheetml.template" '(xltx) "IANA: OOXML - Spreadsheet Template")
(addMimeType "Microsoft Office - OOXML - Word Document" "application/vnd.openxmlformats-officedocument.wordprocessingml.document" '(docx) "IANA: OOXML - Word Document")
(addMimeType "Microsoft Office - OOXML - Word Document Template" "application/vnd.openxmlformats-officedocument.wordprocessingml.template" '(dotx) "IANA: OOXML - Word Document Template")
(addMimeType "Microsoft Office Binder" "application/x-msbinder" '(obd) "Wikipedia: Microsoft Shared Tools")
(addMimeType "Microsoft Office System Release Theme" "application/vnd.ms-officetheme" '(thmx) "IANA: MS Office System Release Theme")
(addMimeType "Microsoft OneNote" "application/onenote" '(onetoc) "MS OneNote 2010")
(addMimeType "Microsoft PlayReady Ecosystem" "audio/vnd.ms-playready.media.pya" '(pya) "IANA: Microsoft PlayReady Ecosystem")
(addMimeType "Microsoft PlayReady Ecosystem Video" "video/vnd.ms-playready.media.pyv" '(pyv) "IANA: Microsoft PlayReady Ecosystem")
(addMimeType "Microsoft PowerPoint" "application/vnd.ms-powerpoint" '(ppt) "IANA: MS PowerPoint")
(addMimeType "Microsoft PowerPoint - Add-in file" "application/vnd.ms-powerpoint.addin.macroenabled.12" '(ppam) "IANA: MS PowerPoint")
(addMimeType "Microsoft PowerPoint - Macro-Enabled Open XML Slide" "application/vnd.ms-powerpoint.slide.macroenabled.12" '(sldm) "IANA: MS PowerPoint")
(addMimeType "Microsoft PowerPoint - Macro-Enabled Presentation File" "application/vnd.ms-powerpoint.presentation.macroenabled.12" '(pptm) "IANA: MS PowerPoint")
(addMimeType "Microsoft PowerPoint - Macro-Enabled Slide Show File" "application/vnd.ms-powerpoint.slideshow.macroenabled.12" '(ppsm) "IANA: MS PowerPoint")
(addMimeType "Microsoft PowerPoint - Macro-Enabled Template File" "application/vnd.ms-powerpoint.template.macroenabled.12" '(potm) "IANA: MS PowerPoint")
(addMimeType "Microsoft Project" "application/vnd.ms-project" '(mpp) "IANA: MS PowerPoint")
(addMimeType "Microsoft Publisher" "application/x-mspublisher" '(pub) "Wikipedia: Microsoft Publisher")
(addMimeType "Microsoft Schedule+" "application/x-msschedule" '(scd) "Wikipedia: Microsoft Schedule Plus")
(addMimeType "Microsoft Silverlight" "application/x-silverlight-app" '(xap) "Wikipedia: Silverlight")
(addMimeType "Microsoft Trust UI Provider - Certificate Trust Link" "application/vnd.ms-pki.stl" '(stl) "IANA: MS Trust UI Provider")
(addMimeType "Microsoft Trust UI Provider - Security Catalog" "application/vnd.ms-pki.seccat" '(cat) "IANA: MS Trust UI Provider")
(addMimeType "Microsoft Visio" "application/vnd.visio" '(vsd) "IANA: Visio")
(addMimeType "Microsoft Visio 2013" "application/vnd.visio2013" '(vsdx) "IANA: Visio")
(addMimeType "Microsoft Windows Media" "video/x-ms-wm" '(wm) "Wikipedia: Advanced Systems Format (ASF)")
(addMimeType "Microsoft Windows Media Audio" "audio/x-ms-wma" '(wma) "Wikipedia: Windows Media Audio")
(addMimeType "Microsoft Windows Media Audio Redirector" "audio/x-ms-wax" '(wax) "Windows Media Metafiles")
(addMimeType "Microsoft Windows Media Audio/Video Playlist" "video/x-ms-wmx" '(wmx) "Wikipedia: Advanced Systems Format (ASF)")
(addMimeType "Microsoft Windows Media Player Download Package" "application/x-ms-wmd" '(wmd) "Wikipedia: Windows Media Player")
(addMimeType "Microsoft Windows Media Player Playlist" "application/vnd.ms-wpl" '(wpl) "IANA: MS Windows Media Player Playlist")
(addMimeType "Microsoft Windows Media Player Skin Package" "application/x-ms-wmz" '(wmz) "Wikipedia: Windows Media Player")
(addMimeType "Microsoft Windows Media Video" "video/x-ms-wmv" '(wmv) "Wikipedia: Advanced Systems Format (ASF)")
(addMimeType "Microsoft Windows Media Video Playlist" "video/x-ms-wvx" '(wvx) "Wikipedia: Advanced Systems Format (ASF)")
(addMimeType "Microsoft Windows Metafile" "application/x-msmetafile" '(wmf) "Wikipedia: Windows Metafile")
(addMimeType "Microsoft Windows Terminal Services" "application/x-msterminal" '(trm) "Wikipedia: Terminal Server")
(addMimeType "Microsoft Word" "application/msword" '(doc) "Wikipedia: Microsoft Word")
(addMimeType "Microsoft Word - Macro-Enabled Document" "application/vnd.ms-word.document.macroenabled.12" '(docm) "IANA: MS Word")
(addMimeType "Microsoft Word - Macro-Enabled Template" "application/vnd.ms-word.template.macroenabled.12" '(dotm) "IANA: MS Word")
(addMimeType "Microsoft Wordpad" "application/x-mswrite" '(wri) "Wikipedia: Wordpad")
(addMimeType "Microsoft Works" "application/vnd.ms-works" '(wps) "IANA: MS Works")
(addMimeType "Microsoft XAML Browser Application" "application/x-ms-xbap" '(xbap) "Wikipedia: XAML Browser")
(addMimeType "Microsoft XML Paper Specification" "application/vnd.ms-xpsdocument" '(xps) "IANA: MS XML Paper Specification")
(addMimeType "MIDI" "audio/midi" '(midi) "Wikipedia: MIDI")
(addMimeType "MIDI - Musical Instrument Digital Interface" "audio/midi" '(mid) "Wikipedia: MIDI")
(addMimeType "MiniPay" "application/vnd.ibm.minipay" '(mpy) "IANA: MiniPay")
(addMimeType "MO:DCA-P" "application/vnd.ibm.modcap" '(afp) "IANA: MO:DCA-P")
(addMimeType "Mobile Information Device Profile" "application/vnd.jcp.javame.midlet-rms" '(rms) "IANA: Mobile Information Device Profile")
(addMimeType "MobileTV" "application/vnd.tmobile-livetv" '(tmo) "IANA: MobileTV")
(addMimeType "Mobipocket" "application/x-mobipocket-ebook" '(prc) "Wikipedia: Mobipocket")
(addMimeType "Mobius Management Systems - Basket file" "application/vnd.mobius.mbk" '(mbk) "IANA: Mobius Management Systems")
(addMimeType "Mobius Management Systems - Distribution Database" "application/vnd.mobius.dis" '(dis) "IANA: Mobius Management Systems")
(addMimeType "Mobius Management Systems - Policy Definition Language File" "application/vnd.mobius.plc" '(plc) "IANA: Mobius Management Systems")
(addMimeType "Mobius Management Systems - Query File" "application/vnd.mobius.mqy" '(mqy) "IANA: Mobius Management Systems")
(addMimeType "Mobius Management Systems - Script Language" "application/vnd.mobius.msl" '(msl) "IANA: Mobius Management Systems")
(addMimeType "Mobius Management Systems - Topic Index File" "application/vnd.mobius.txf" '(txf) "IANA: Mobius Management Systems")
(addMimeType "Mobius Management Systems - UniversalArchive" "application/vnd.mobius.daf" '(daf) "IANA: Mobius Management Systems")
(addMimeType "mod_fly / fly.cgi" "text/vnd.fly" '(fly) "IANA: Fly")
(addMimeType "Mophun Certificate" "application/vnd.mophun.certificate" '(mpc) "IANA: Mophun Certificate")
(addMimeType "Mophun VM" "application/vnd.mophun.application" '(mpn) "IANA: Mophun VM")
(addMimeType "Motion JPEG 2000" "video/mj2" '(mj2) "IANA: MJ2")
(addMimeType "MPEG Audio" "audio/mpeg" '(mpga) "Wikipedia: MPGA")
(addMimeType "MPEG Transport Stream" "video/mp2t" '(ts) "Wikipedia: MPEG Transport Stream")
(addMimeType "MPEG Url" "video/vnd.mpegurl" '(mxu) "IANA: MPEG Url")
(addMimeType "MPEG Video" "video/mpeg" '(mpeg) "Wikipedia: MPEG")
(addMimeType "MPEG-21" "application/mp21" '(m21) "Wikipedia: MPEG-21")
(addMimeType "MPEG-4 Audio" "audio/mp4" '(mp4a) "Wikipedia: MP4A")
(addMimeType "MPEG-4 Video" "video/mp4" '(mp4) "Wikipedia: MP4")
(addMimeType "MPEG4" "application/mp4" '(mp4) "RFC 4337")
(addMimeType "Multimedia Playlist Unicode" "application/vnd.apple.mpegurl" '(m3u8) "Wikipedia: M3U")
(addMimeType "MUsical Score Interpreted Code Invented for the ASCII designation of Notation" "application/vnd.musician" '(mus) "IANA: MUSICIAN")
(addMimeType "Muvee Automatic Video Editing" "application/vnd.muvee.style" '(msty) "IANA: Muvee")
(addMimeType "MXML" "application/xv+xml" '(mxml) "Wikipedia: MXML")
(addMimeType "N-Gage Game Data" "application/vnd.nokia.n-gage.data" '(ngdat) "IANA: N-Gage Game Data")
(addMimeType "N-Gage Game Installer" "application/vnd.nokia.n-gage.symbian.install" '(n-gage) "IANA: N-Gage Game Installer")
(addMimeType "Navigation Control file for XML (for ePub)" "application/x-dtbncx+xml" '(ncx) "Wikipedia: EPUB")
(addMimeType "Network Common Data Form (NetCDF)" "application/x-netcdf" '(nc) "Wikipedia: NetCDF")
(addMimeType "neuroLanguage" "application/vnd.neurolanguage.nlu" '(nlu) "IANA: neuroLanguage")
(addMimeType "New Moon Liftoff/DNA" "application/vnd.dna" '(dna) "IANA: New Moon Liftoff/DNA")
(addMimeType "NobleNet Directory" "application/vnd.noblenet-directory" '(nnd) "IANA: NobleNet Directory")
(addMimeType "NobleNet Sealer" "application/vnd.noblenet-sealer" '(nns) "IANA: NobleNet Sealer")
(addMimeType "NobleNet Web" "application/vnd.noblenet-web" '(nnw) "IANA: NobleNet Web")
(addMimeType "Nokia Radio Application - Preset" "application/vnd.nokia.radio-preset" '(rpst) "IANA: Nokia Radio Application")
(addMimeType "Nokia Radio Application - Preset" "application/vnd.nokia.radio-presets" '(rpss) "IANA: Nokia Radio Application")
(addMimeType "Notation3" "text/n3" '(n3) "Wikipedia: Notation3")
(addMimeType "Novadigm's RADIA and EDM products" "application/vnd.novadigm.edm" '(edm) "IANA: Novadigm's RADIA and EDM products")
(addMimeType "Novadigm's RADIA and EDM products" "application/vnd.novadigm.edx" '(edx) "IANA: Novadigm's RADIA and EDM products")
(addMimeType "Novadigm's RADIA and EDM products" "application/vnd.novadigm.ext" '(ext) "IANA: Novadigm's RADIA and EDM products")
(addMimeType "NpGraphIt" "application/vnd.flographit" '(gph) "IANA: FloGraphIt")
(addMimeType "Nuera ECELP 4800" "audio/vnd.nuera.ecelp4800" '(ecelp4800) "IANA: ECELP 4800")
(addMimeType "Nuera ECELP 7470" "audio/vnd.nuera.ecelp7470" '(ecelp7470) "IANA: ECELP 7470")
(addMimeType "Nuera ECELP 9600" "audio/vnd.nuera.ecelp9600" '(ecelp9600) "IANA: ECELP 9600")
(addMimeType "Office Document Architecture" "application/oda" '(oda) "RFC 2161")
(addMimeType "Ogg" "application/ogg" '(ogx) "Wikipedia: Ogg")
(addMimeType "Ogg Audio" "audio/ogg" '(oga) "Wikipedia: Ogg")
(addMimeType "Ogg Video" "video/ogg" '(ogv) "Wikipedia: Ogg")
(addMimeType "OMA Download Agents" "application/vnd.oma.dd2+xml" '(dd2) "IANA: OMA Download Agents")
(addMimeType "Open Document Text Web" "application/vnd.oasis.opendocument.text-web" '(oth) "IANA: OpenDocument Text Web")
(addMimeType "Open eBook Publication Structure" "application/oebps-package+xml" '(opf) "Wikipedia: Open eBook")
(addMimeType "Open Financial Exchange" "application/vnd.intu.qbo" '(qbo) "IANA: Open Financial Exchange")
(addMimeType "Open Office Extension" "application/vnd.openofficeorg.extension" '(oxt) "IANA: Open Office Extension")
(addMimeType "Open Score Format" "application/vnd.yamaha.openscoreformat" '(osf) "IANA: Open Score Format")
(addMimeType "Open Web Media Project - Audio" "audio/webm" '(weba) "WebM Project")
(addMimeType "Open Web Media Project - Video" "video/webm" '(webm) "WebM Project")
(addMimeType "OpenDocument Chart" "application/vnd.oasis.opendocument.chart" '(odc) "IANA: OpenDocument Chart")
(addMimeType "OpenDocument Chart Template" "application/vnd.oasis.opendocument.chart-template" '(otc) "IANA: OpenDocument Chart Template")
(addMimeType "OpenDocument Database" "application/vnd.oasis.opendocument.database" '(odb) "IANA: OpenDocument Database")
(addMimeType "OpenDocument Formula" "application/vnd.oasis.opendocument.formula" '(odf) "IANA: OpenDocument Formula")
(addMimeType "OpenDocument Formula Template" "application/vnd.oasis.opendocument.formula-template" '(odft) "IANA: OpenDocument Formula Template")
(addMimeType "OpenDocument Graphics" "application/vnd.oasis.opendocument.graphics" '(odg) "IANA: OpenDocument Graphics")
(addMimeType "OpenDocument Graphics Template" "application/vnd.oasis.opendocument.graphics-template" '(otg) "IANA: OpenDocument Graphics Template")
(addMimeType "OpenDocument Image" "application/vnd.oasis.opendocument.image" '(odi) "IANA: OpenDocument Image")
(addMimeType "OpenDocument Image Template" "application/vnd.oasis.opendocument.image-template" '(oti) "IANA: OpenDocument Image Template")
(addMimeType "OpenDocument Presentation" "application/vnd.oasis.opendocument.presentation" '(odp) "IANA: OpenDocument Presentation")
(addMimeType "OpenDocument Presentation Template" "application/vnd.oasis.opendocument.presentation-template" '(otp) "IANA: OpenDocument Presentation Template")
(addMimeType "OpenDocument Spreadsheet" "application/vnd.oasis.opendocument.spreadsheet" '(ods) "IANA: OpenDocument Spreadsheet")
(addMimeType "OpenDocument Spreadsheet Template" "application/vnd.oasis.opendocument.spreadsheet-template" '(ots) "IANA: OpenDocument Spreadsheet Template")
(addMimeType "OpenDocument Text" "application/vnd.oasis.opendocument.text" '(odt) "IANA: OpenDocument Text")
(addMimeType "OpenDocument Text Master" "application/vnd.oasis.opendocument.text-master" '(odm) "IANA: OpenDocument Text Master")
(addMimeType "OpenDocument Text Template" "application/vnd.oasis.opendocument.text-template" '(ott) "IANA: OpenDocument Text Template")
(addMimeType "OpenGL Textures (KTX)" "image/ktx" '(ktx) "KTX File Format")
(addMimeType "OpenOffice - Calc (Spreadsheet)" "application/vnd.sun.xml.calc" '(sxc) "Wikipedia: OpenOffice")
(addMimeType "OpenOffice - Calc Template (Spreadsheet)" "application/vnd.sun.xml.calc.template" '(stc) "Wikipedia: OpenOffice")
(addMimeType "OpenOffice - Draw (Graphics)" "application/vnd.sun.xml.draw" '(sxd) "Wikipedia: OpenOffice")
(addMimeType "OpenOffice - Draw Template (Graphics)" "application/vnd.sun.xml.draw.template" '(std) "Wikipedia: OpenOffice")
(addMimeType "OpenOffice - Impress (Presentation)" "application/vnd.sun.xml.impress" '(sxi) "Wikipedia: OpenOffice")
(addMimeType "OpenOffice - Impress Template (Presentation)" "application/vnd.sun.xml.impress.template" '(sti) "Wikipedia: OpenOffice")
(addMimeType "OpenOffice - Math (Formula)" "application/vnd.sun.xml.math" '(sxm) "Wikipedia: OpenOffice")
(addMimeType "OpenOffice - Writer (Text - HTML)" "application/vnd.sun.xml.writer" '(sxw) "Wikipedia: OpenOffice")
(addMimeType "OpenOffice - Writer (Text - HTML)" "application/vnd.sun.xml.writer.global" '(sxg) "Wikipedia: OpenOffice")
(addMimeType "OpenOffice - Writer Template (Text - HTML)" "application/vnd.sun.xml.writer.template" '(stw) "Wikipedia: OpenOffice")
(addMimeType "OpenType Font File" "application/x-font-otf" '(otf) "OpenType Font File")
(addMimeType "Opus Audio" "audio/opus" '(opus) "Wikipedia: Opus Audio")
(addMimeType "OSFPVG" "application/vnd.yamaha.openscoreformat.osfpvg+xml" '(osfpvg) "IANA: OSFPVG")
(addMimeType "OSGi Deployment Package" "application/vnd.osgi.dp" '(dp) "IANA: OSGi Deployment Package")
(addMimeType "PalmOS Data" "application/vnd.palm" '(pdb) "IANA: PalmOS Data")
(addMimeType "Pascal Source File" "text/x-pascal" '(p) "Wikipedia: Pascal")
(addMimeType "PawaaFILE" "application/vnd.pawaafile" '(paw) "IANA: PawaaFILE")
(addMimeType "PCL 6 Enhanced (Formely PCL XL)" "application/vnd.hp-pclxl" '(pclxl) "IANA: HP PCL XL")
(addMimeType "Pcsel eFIF File" "application/vnd.picsel" '(efif) "IANA: Picsel eFIF File")
(addMimeType "PCX Image" "image/x-pcx" '(pcx) "Wikipedia: PCX")
(addMimeType "Photoshop Document" "image/vnd.adobe.photoshop" '(psd) "Wikipedia: Photoshop Document")
(addMimeType "PICSRules" "application/pics-rules" '(prf) "W3C PICSRules")
(addMimeType "PICT Image" "image/x-pict" '(pic) "Wikipedia: PICT")
(addMimeType "pIRCh" "application/x-chat" '(chat) "Wikipedia: pIRCh")
(addMimeType "PKCS #10 - Certification Request Standard" "application/pkcs10" '(p10) "RFC 2986")
(addMimeType "PKCS #12 - Personal Information Exchange Syntax Standard" "application/x-pkcs12" '(p12) "RFC 2986")
(addMimeType "PKCS #7 - Cryptographic Message Syntax Standard" "application/pkcs7-mime" '(p7m) "RFC 2315")
(addMimeType "PKCS #7 - Cryptographic Message Syntax Standard" "application/pkcs7-signature" '(p7s) "RFC 2315")
(addMimeType "PKCS #7 - Cryptographic Message Syntax Standard (Certificate Request Response)" "application/x-pkcs7-certreqresp" '(p7r) "RFC 2986")
(addMimeType "PKCS #7 - Cryptographic Message Syntax Standard (Certificates)" "application/x-pkcs7-certificates" '(p7b) "RFC 2986")
(addMimeType "PKCS #8 - Private-Key Information Syntax Standard" "application/pkcs8" '(p8) "RFC 5208")
(addMimeType "PocketLearn Viewers" "application/vnd.pocketlearn" '(plf) "IANA: PocketLearn Viewers")
(addMimeType "Portable Anymap Image" "image/x-portable-anymap" '(pnm) "Wikipedia: Netpbm Format")
(addMimeType "Portable Bitmap Format" "image/x-portable-bitmap" '(pbm) "Wikipedia: Netpbm Format")
(addMimeType "Portable Compiled Format" "application/x-font-pcf" '(pcf) "Wikipedia: Portable Compiled Format")
(addMimeType "Portable Font Resource" "application/font-tdpfr" '(pfr) "RFC 3073")
(addMimeType "Portable Game Notation (Chess Games)" "application/x-chess-pgn" '(pgn) "Wikipedia: Portable Game Notationb")
(addMimeType "Portable Graymap Format" "image/x-portable-graymap" '(pgm) "Wikipedia: Netpbm Format")
(addMimeType "Portable Network Graphics (PNG)" "image/png" '(png) "RFC 2083")
(addMimeType "Portable Network Graphics (PNG) (Citrix client)" "image/x-citrix-png" '(png) "RFC 2083")
(addMimeType "Portable Network Graphics (PNG) (x-token)" "image/x-png" '(png) "RFC 2083")
(addMimeType "Portable Pixmap Format" "image/x-portable-pixmap" '(ppm) "Wikipedia: Netpbm Format")
(addMimeType "Portable Symmetric Key Container" "application/pskc+xml" '(pskcxml) "RFC 6030")
(addMimeType "PosML" "application/vnd.ctc-posml" '(pml) "IANA: PosML")
(addMimeType "PostScript" "application/postscript" '(ai) "Wikipedia: PostScript")
(addMimeType "PostScript Fonts" "application/x-font-type1" '(pfa) "Wikipedia: PostScript Fonts")
(addMimeType "PowerBuilder" "application/vnd.powerbuilder6" '(pbd) "IANA: PowerBuilder")
(addMimeType "Pretty Good Privacy" "application/pgp-encrypted" '(pgp) "RFC 2015")
(addMimeType "Pretty Good Privacy - Signature" "application/pgp-signature" '(pgp) "RFC 2015")
(addMimeType "Preview Systems ZipLock/VBox" "application/vnd.previewsystems.box" '(box) "IANA: Preview Systems ZipLock/Vbox")
(addMimeType "Princeton Video Image" "application/vnd.pvi.ptid1" '(ptid) "IANA: Princeton Video Image")
(addMimeType "Pronunciation Lexicon Specification" "application/pls+xml" '(pls) "RFC 4267")
(addMimeType "Proprietary P&G Standard Reporting System" "application/vnd.pg.format" '(str) "IANA: Proprietary P&G Standard Reporting System")
(addMimeType "Proprietary P&G Standard Reporting System" "application/vnd.pg.osasli" '(ei6) "IANA: Proprietary P&G Standard Reporting System")
(addMimeType "PRS Lines Tag" "text/prs.lines.tag" '(dsc) "IANA: PRS Lines Tag")
(addMimeType "PSF Fonts" "application/x-font-linux-psf" '(psf) "PSF Fonts")
(addMimeType "PubliShare Objects" "application/vnd.publishare-delta-tree" '(qps) "IANA: PubliShare Objects")
(addMimeType "Qualcomm's Plaza Mobile Internet" "application/vnd.pmi.widget" '(wg) "IANA: Qualcomm's Plaza Mobile Internet")
(addMimeType "QuarkXpress" "application/vnd.quark.quarkxpress" '(qxd) "IANA: QuarkXPress")
(addMimeType "QUASS Stream Player" "application/vnd.epson.esf" '(esf) "IANA: QUASS Stream Player")
(addMimeType "QUASS Stream Player" "application/vnd.epson.msf" '(msf) "IANA: QUASS Stream Player")
(addMimeType "QUASS Stream Player" "application/vnd.epson.ssf" '(ssf) "IANA: QUASS Stream Player")
(addMimeType "QuickAnime Player" "application/vnd.epson.quickanime" '(qam) "IANA: QuickAnime Player")
(addMimeType "Quicken" "application/vnd.intu.qfx" '(qfx) "IANA: Quicken")
(addMimeType "Quicktime Video" "video/quicktime" '(qt) "Wikipedia: Quicktime")
(addMimeType "RAR Archive" "application/x-rar-compressed" '(rar) "Wikipedia: RAR")
(addMimeType "Real Audio Sound" "audio/x-pn-realaudio" '(ram) "Wikipedia: RealPlayer")
(addMimeType "Real Audio Sound" "audio/x-pn-realaudio-plugin" '(rmp) "Wikipedia: RealPlayer")
(addMimeType "Really Simple Discovery" "application/rsd+xml" '(rsd) "Wikipedia: Really Simple Discovery")
(addMimeType "RealMedia" "application/vnd.rn-realmedia" '(rm) "")
(addMimeType "RealVNC" "application/vnd.realvnc.bed" '(bed) "IANA: RealVNC")
(addMimeType "Recordare Applications" "application/vnd.recordare.musicxml" '(mxl) "IANA: Recordare Apps")
(addMimeType "Recordare Applications" "application/vnd.recordare.musicxml+xml" '(musicxml) "IANA: Recordare Apps")
(addMimeType "Relax NG Compact Syntax" "application/relax-ng-compact-syntax" '(rnc) "Relax NG")
(addMimeType "RemoteDocs R-Viewer" "application/vnd.data-vision.rdz" '(rdz) "IANA: Data-Vision")
(addMimeType "Resource Description Framework" "application/rdf+xml" '(rdf) "RFC 3870")
(addMimeType "RetroPlatform Player" "application/vnd.cloanto.rp9" '(rp9) "IANA: RetroPlatform Player")
(addMimeType "RhymBox" "application/vnd.jisp" '(jisp) "IANA: RhymBox")
(addMimeType "Rich Text Format" "application/rtf" '(rtf) "Wikipedia: Rich Text Format")
(addMimeType "Rich Text Format (RTF)" "text/richtext" '(rtx) "Wikipedia: Rich Text Format")
(addMimeType "ROUTE 66 Location Based Services" "application/vnd.route66.link66+xml" '(link66) "IANA: ROUTE 66")
(addMimeType "RSS - Really Simple Syndication" "application/rss+xml" '(rss xml) "Wikipedia: RSS")
(addMimeType "S Hexdump Format" "application/shf+xml" '(shf) "RFC 4194")
(addMimeType "SailingTracker" "application/vnd.sailingtracker.track" '(st) "IANA: SailingTracker")
(addMimeType "Scalable Vector Graphics (SVG)" "image/svg+xml" '(svg) "Wikipedia: SVG")
(addMimeType "ScheduleUs" "application/vnd.sus-calendar" '(sus) "IANA: ScheduleUs")
(addMimeType "Search/Retrieve via URL Response Format" "application/sru+xml" '(sru) "RFC 6207")
(addMimeType "Secure Electronic Transaction - Payment" "application/set-payment-initiation" '(setpay) "IANA: SET Payment")
(addMimeType "Secure Electronic Transaction - Registration" "application/set-registration-initiation" '(setreg) "IANA: SET Registration")
(addMimeType "Secured eMail" "application/vnd.sema" '(sema) "IANA: Secured eMail")
(addMimeType "Secured eMail" "application/vnd.semd" '(semd) "IANA: Secured eMail")
(addMimeType "Secured eMail" "application/vnd.semf" '(semf) "IANA: Secured eMail")
(addMimeType "SeeMail" "application/vnd.seemail" '(see) "IANA: SeeMail")
(addMimeType "Server Normal Format" "application/x-font-snf" '(snf) "Wikipedia: Server Normal Format")
(addMimeType "Server-Based Certificate Validation Protocol - Validation Policies - Request" "application/scvp-vp-request" '(spq) "RFC 5055")
(addMimeType "Server-Based Certificate Validation Protocol - Validation Policies - Response" "application/scvp-vp-response" '(spp) "RFC 5055")
(addMimeType "Server-Based Certificate Validation Protocol - Validation Request" "application/scvp-cv-request" '(scq) "RFC 5055")
(addMimeType "Server-Based Certificate Validation Protocol - Validation Response" "application/scvp-cv-response" '(scs) "RFC 5055")
(addMimeType "Session Description Protocol" "application/sdp" '(sdp) "RFC 2327")
(addMimeType "Setext" "text/x-setext" '(etx) "Wikipedia: Setext")
(addMimeType "SGI Movie" "video/x-sgi-movie" '(movie) "SGI Facts")
(addMimeType "Shana Informed Filler" "application/vnd.shana.informed.formdata" '(ifm) "IANA: Shana Informed Filler")
(addMimeType "Shana Informed Filler" "application/vnd.shana.informed.formtemplate" '(itp) "IANA: Shana Informed Filler")
(addMimeType "Shana Informed Filler" "application/vnd.shana.informed.interchange" '(iif) "IANA: Shana Informed Filler")
(addMimeType "Shana Informed Filler" "application/vnd.shana.informed.package" '(ipk) "IANA: Shana Informed Filler")
(addMimeType "Sharing Transaction Fraud Data" "application/thraud+xml" '(tfi) "RFC 5941")
(addMimeType "Shell Archive" "application/x-shar" '(shar) "Wikipedia: Shell Archie")
(addMimeType "Silicon Graphics RGB Bitmap" "image/x-rgb" '(rgb) "RGB Image Format")
(addMimeType "SimpleAnimeLite Player" "application/vnd.epson.salt" '(slt) "IANA: SimpleAnimeLite Player")
(addMimeType "Simply Accounting" "application/vnd.accpac.simply.aso" '(aso) "IANA: Simply Accounting")
(addMimeType "Simply Accounting - Data Import" "application/vnd.accpac.simply.imp" '(imp) "IANA: Simply Accounting")
(addMimeType "SimTech MindMapper" "application/vnd.simtech-mindmapper" '(twd) "IANA: SimTech MindMapper")
(addMimeType "Sixth Floor Media - CommonSpace" "application/vnd.commonspace" '(csp) "IANA: CommonSpace")
(addMimeType "SMAF Audio" "application/vnd.yamaha.smaf-audio" '(saf) "IANA: SMAF Audio")
(addMimeType "SMAF File" "application/vnd.smaf" '(mmf) "IANA: SMAF File")
(addMimeType "SMAF Phrase" "application/vnd.yamaha.smaf-phrase" '(spf) "IANA: SMAF Phrase")
(addMimeType "SMART Technologies Apps" "application/vnd.smart.teacher" '(teacher) "IANA: SMART Technologies Apps")
(addMimeType "SourceView Document" "application/vnd.svd" '(svd) "IANA: SourceView Document")
(addMimeType "SPARQL - Query" "application/sparql-query" '(rq) "W3C SPARQL")
(addMimeType "SPARQL - Results" "application/sparql-results+xml" '(srx) "W3C SPARQL")
(addMimeType "Speech Recognition Grammar Specification" "application/srgs" '(gram) "W3C Speech Grammar")
(addMimeType "Speech Recognition Grammar Specification - XML" "application/srgs+xml" '(grxml) "W3C Speech Grammar")
(addMimeType "Speech Synthesis Markup Language" "application/ssml+xml" '(ssml) "W3C Speech Synthesis")
(addMimeType "SSEYO Koan Play File" "application/vnd.koan" '(skp) "IANA: SSEYO Koan Play File")
(addMimeType "Standard Generalized Markup Language (SGML)" "text/sgml" '(sgml) "Wikipedia: SGML")
(addMimeType "StarOffice - Calc" "application/vnd.stardivision.calc" '(sdc) "")
(addMimeType "StarOffice - Draw" "application/vnd.stardivision.draw" '(sda) "")
(addMimeType "StarOffice - Impress" "application/vnd.stardivision.impress" '(sdd) "")
(addMimeType "StarOffice - Math" "application/vnd.stardivision.math" '(smf) "")
(addMimeType "StarOffice - Writer" "application/vnd.stardivision.writer" '(sdw) "")
(addMimeType "StarOffice - Writer (Global)" "application/vnd.stardivision.writer-global" '(sgl) "")
(addMimeType "StepMania" "application/vnd.stepmania.stepchart" '(sm) "IANA: StepMania")
(addMimeType "Stuffit Archive" "application/x-stuffit" '(sit) "Wikipedia: Stuffit")
(addMimeType "Stuffit Archive" "application/x-stuffitx" '(sitx) "Wikipedia: Stuffit")
(addMimeType "SudokuMagic" "application/vnd.solent.sdkm+xml" '(sdkm) "IANA: SudokuMagic")
(addMimeType "Sugar Linux Application Bundle" "application/vnd.olpc-sugar" '(xo) "IANA: Sugar Linux App Bundle")
(addMimeType "Sun Audio - Au file format" "audio/basic" '(au) "Wikipedia: Sun audio")
(addMimeType "SundaHus WQ" "application/vnd.wqd" '(wqd) "IANA: SundaHus WQ")
(addMimeType "Symbian Install Package" "application/vnd.symbian.install" '(sis) "IANA: Symbian Install")
(addMimeType "Synchronized Multimedia Integration Language" "application/smil+xml" '(smi) "RFC 4536")
(addMimeType "SyncML" "application/vnd.syncml+xml" '(xsm) "IANA: SyncML")
(addMimeType "SyncML - Device Management" "application/vnd.syncml.dm+wbxml" '(bdm) "IANA: SyncML")
(addMimeType "SyncML - Device Management" "application/vnd.syncml.dm+xml" '(xdm) "IANA: SyncML")
(addMimeType "System V Release 4 CPIO Archive" "application/x-sv4cpio" '(sv4cpio) "Wikipedia: pax")
(addMimeType "System V Release 4 CPIO Checksum Data" "application/x-sv4crc" '(sv4crc) "Wikipedia: pax")
(addMimeType "Systems Biology Markup Language" "application/sbml+xml" '(sbml) "RFC 3823")
(addMimeType "Tab Seperated Values" "text/tab-separated-values" '(tsv) "Wikipedia: TSV")
(addMimeType "Tagged Image File Format" "image/tiff" '(tiff) "Wikipedia: TIFF")
(addMimeType "Tao Intent" "application/vnd.tao.intent-module-archive" '(tao) "IANA: Tao Intent")
(addMimeType "Tar File (Tape Archive)" "application/x-tar" '(tar) "Wikipedia: Tar")
(addMimeType "Tcl Script" "application/x-tcl" '(tcl) "Wikipedia: Tcl")
(addMimeType "TeX" "application/x-tex" '(tex) "Wikipedia: TeX")
(addMimeType "TeX Font Metric" "application/x-tex-tfm" '(tfm) "Wikipedia: TeX Font Metric")
(addMimeType "Text Encoding and Interchange" "application/tei+xml" '(tei) "RFC 6129")
(addMimeType "Text File" "text/plain" '(txt) "Wikipedia: Text File")
(addMimeType "TIBCO Spotfire" "application/vnd.spotfire.dxp" '(dxp) "IANA: TIBCO Spotfire")
(addMimeType "TIBCO Spotfire" "application/vnd.spotfire.sfs" '(sfs) "IANA: TIBCO Spotfire")
(addMimeType "Time Stamped Data Envelope" "application/timestamped-data" '(tsd) "RFC 5955")
(addMimeType "TRI Systems Config" "application/vnd.trid.tpt" '(tpt) "IANA: TRI Systems")
(addMimeType "Triscape Map Explorer" "application/vnd.triscape.mxs" '(mxs) "IANA: Triscape Map Explorer")
(addMimeType "troff" "text/troff" '(t) "Wikipedia: troff")
(addMimeType "True BASIC" "application/vnd.trueapp" '(tra) "IANA: True BASIC")
(addMimeType "TrueType Font" "application/x-font-ttf" '(ttf) "Wikipedia: TrueType")
(addMimeType "Turtle (Terse RDF Triple Language)" "text/turtle" '(ttl) "Wikipedia: Turtle")
(addMimeType "UMAJIN" "application/vnd.umajin" '(umj) "IANA: UMAJIN")
(addMimeType "Unique Object Markup Language" "application/vnd.uoml+xml" '(uoml) "IANA: UOML")
(addMimeType "Unity 3d" "application/vnd.unity" '(unityweb) "IANA: Unity 3d")
(addMimeType "Universal Forms Description Language" "application/vnd.ufdl" '(ufd) "IANA: Universal Forms Description Language")
(addMimeType "URI Resolution Services" "text/uri-list" '(uri) "RFC 2483")
(addMimeType "User Interface Quartz - Theme (Symbian)" "application/vnd.uiq.theme" '(utz) "IANA: User Interface Quartz")
(addMimeType "Ustar (Uniform Standard Tape Archive)" "application/x-ustar" '(ustar) "Wikipedia: Ustar")
(addMimeType "UUEncode" "text/x-uuencode" '(uu) "Wikipedia: UUEncode")
(addMimeType "vCalendar" "text/x-vcalendar" '(vcs) "Wikipedia: vCalendar")
(addMimeType "vCard" "text/x-vcard" '(vcf) "Wikipedia: vCard")
(addMimeType "Video CD" "application/x-cdlink" '(vcd) "Wikipedia: Video CD")
(addMimeType "Viewport+" "application/vnd.vsf" '(vsf) "IANA: Viewport+")
(addMimeType "Virtual Reality Modeling Language" "model/vrml" '(wrl) "Wikipedia: VRML")
(addMimeType "VirtualCatalog" "application/vnd.vcx" '(vcx) "IANA: VirtualCatalog")
(addMimeType "Virtue MTS" "model/vnd.mts" '(mts) "IANA: MTS")
(addMimeType "Virtue VTU" "model/vnd.vtu" '(vtu) "IANA: VTU")
(addMimeType "Visionary" "application/vnd.visionary" '(vis) "IANA: Visionary")
(addMimeType "Vivo" "video/vnd.vivo" '(viv) "IANA: Vivo")
(addMimeType "Voice Browser Call Control" "application/ccxml+xml," '(ccxml) "Voice Browser Call Control: CCXML Version 1.0")
(addMimeType "VoiceXML" "application/voicexml+xml" '(vxml) "RFC 4267")
(addMimeType "WAIS Source" "application/x-wais-source" '(src) "YoLinux")
(addMimeType "WAP Binary XML (WBXML)" "application/vnd.wap.wbxml" '(wbxml) "IANA: WBXML")
(addMimeType "WAP Bitamp (WBMP)" "image/vnd.wap.wbmp" '(wbmp) "IANA: WBMP")
(addMimeType "Waveform Audio File Format (WAV)" "audio/x-wav" '(wav) "Wikipedia: WAV")
(addMimeType "Web Distributed Authoring and Versioning" "application/davmount+xml" '(davmount) "RFC 4918")
(addMimeType "Web Open Font Format" "application/x-font-woff" '(woff) "Wikipedia: Web Open Font Format")
(addMimeType "Web Services Policy" "application/wspolicy+xml" '(wspolicy) "W3C Web Services Policy")
(addMimeType "WebP Image" "image/webp" '(webp) "Wikipedia: WebP")
(addMimeType "WebTurbo" "application/vnd.webturbo" '(wtb) "IANA: WebTurbo")
(addMimeType "Widget Packaging and XML Configuration" "application/widget" '(wgt) "W3C Widget Packaging and XML Configuration")
(addMimeType "WinHelp" "application/winhlp" '(hlp) "Wikipedia: WinHelp")
(addMimeType "Wireless Markup Language (WML)" "text/vnd.wap.wml" '(wml) "Wikipedia: WML")
(addMimeType "Wireless Markup Language Script (WMLScript)" "text/vnd.wap.wmlscript" '(wmls) "Wikipedia: WMLScript")
(addMimeType "WMLScript" "application/vnd.wap.wmlscriptc" '(wmlsc) "IANA: WMLScript")
(addMimeType "Wordperfect" "application/vnd.wordperfect" '(wpd) "IANA: Wordperfect")
(addMimeType "Worldtalk" "application/vnd.wt.stf" '(stf) "IANA: Worldtalk")
(addMimeType "WSDL - Web Services Description Language" "application/wsdl+xml" '(wsdl) "W3C Web Service Description Language")
(addMimeType "X BitMap" "image/x-xbitmap" '(xbm) "Wikipedia: X BitMap")
(addMimeType "X PixMap" "image/x-xpixmap" '(xpm) "Wikipedia: X PixMap")
(addMimeType "X Window Dump" "image/x-xwindowdump" '(xwd) "Wikipedia: X Window Dump")
(addMimeType "X.509 Certificate" "application/x-x509-ca-cert" '(der) "Wikipedia: X.509")
(addMimeType "Xfig" "application/x-xfig" '(fig) "Wikipedia: Xfig")
(addMimeType "XHTML - The Extensible HyperText Markup Language" "application/xhtml+xml" '(xhtml) "W3C XHTML")
(addMimeType "XML - Extensible Markup Language" "application/xml" '(xml) "W3C XML")
(addMimeType "XML Configuration Access Protocol - XCAP Diff" "application/xcap-diff+xml" '(xdf) "Wikipedia: XCAP")
(addMimeType "XML Encryption Syntax and Processing" "application/xenc+xml" '(xenc) "W3C XML Encryption Syntax and Processing")
(addMimeType "XML Patch Framework" "application/patch-ops-error+xml" '(xer) "RFC 5261")
(addMimeType "XML Resource Lists" "application/resource-lists+xml" '(rl) "RFC 4826")
(addMimeType "XML Resource Lists" "application/rls-services+xml" '(rs) "RFC 4826")
(addMimeType "XML Resource Lists Diff" "application/resource-lists-diff+xml" '(rld) "RFC 4826")
(addMimeType "XML Transformations" "application/xslt+xml" '(xslt) "W3C XSLT")
(addMimeType "XML-Binary Optimized Packaging" "application/xop+xml" '(xop) "W3C XOP")
(addMimeType "XPInstall - Mozilla" "application/x-xpinstall" '(xpi) "Wikipedia: XPI")
(addMimeType "XSPF - XML Shareable Playlist Format" "application/xspf+xml" '(xspf) "XML Shareable Playlist Format")
(addMimeType "XUL - XML User Interface Language" "application/vnd.mozilla.xul+xml" '(xul) "IANA: XUL")
(addMimeType "XYZ File Format" "chemical/x-xyz" '(xyz) "Wikipedia: XYZ File Format")
(addMimeType "YAML Ain't Markup Language / Yet Another Markup Language" "text/yaml" '(yaml) "YAML: YAML Ain't Markup Language")
(addMimeType "YANG Data Modeling Language" "application/yang" '(yang) "Wikipedia: YANG")
(addMimeType "YIN (YANG - XML)" "application/yin+xml" '(yin) "Wikipedia: YANG")
(addMimeType "Z.U.L. Geometry" "application/vnd.zul" '(zir) "IANA: Z.U.L.")
(addMimeType "Zip Archive" "application/zip" '(zip) "Wikipedia: Zip")
(addMimeType "ZVUE Media Manager" "application/vnd.handheld-entertainment+xml" '(zmm) "IANA: ZVUE Media Manager")
(addMimeType "Zzazz Deck" "application/vnd.zzazz.deck+xml" '(zaz) "IANA: Zzazz")
+36 -2
View File
@@ -281,6 +281,9 @@
(syntax-case stx () (syntax-case stx ()
((_ (a c b1 b2)) ((_ (a c b1 b2))
(cond (cond
((eq? (syntax->datum #'a) 'define) #'(js-def c (b1 b2)))
((eq? (syntax->datum #'a) 'lambda) #'(js-lambda c b1 b2))
((eq? (syntax->datum #'a) 'λ) #'(js-lambda c b1 b2))
((eq? (syntax->datum #'a) 'if) #'(js2-if c b1 b2)) ((eq? (syntax->datum #'a) 'if) #'(js2-if c b1 b2))
((memq (syntax->datum #'a) js-ops) #'(js-op a c b1 b2)) ((memq (syntax->datum #'a) js-ops) #'(js-op a c b1 b2))
((eq? (syntax->datum #'a) 'let*) #'(js2-let* c b1 b2)) ((eq? (syntax->datum #'a) 'let*) #'(js2-let* c b1 b2))
@@ -321,6 +324,7 @@
((eq? (syntax->datum #'a) 'return) #'(js-return b)) ((eq? (syntax->datum #'a) 'return) #'(js-return b))
((eq? (syntax->datum #'a) 'quote) #'(js-quote b)) ((eq? (syntax->datum #'a) 'quote) #'(js-quote b))
((eq? (syntax->datum #'a) 'eval) #'(js-eval b)) ((eq? (syntax->datum #'a) 'eval) #'(js-eval b))
((eq? (syntax->datum #'a) 'list) #'(js-op a b))
;string-append ;string-append
; "\"" (esc-double-quote (format "~a" 'b)) "\"")) ; "\"" (esc-double-quote (format "~a" 'b)) "\""))
(else (else
@@ -334,6 +338,8 @@
(cond (cond
((eq? (syntax->datum #'a) 'let*) #'(js2-let* c b1 ...)) ((eq? (syntax->datum #'a) 'let*) #'(js2-let* c b1 ...))
((eq? (syntax->datum #'a) 'define) #'(js-def c (b1 ...))) ((eq? (syntax->datum #'a) 'define) #'(js-def c (b1 ...)))
((eq? (syntax->datum #'a) 'lambda) #'(js-lambda c b1 ...))
((eq? (syntax->datum #'a) 'λ) #'(js-lambda c b1 ...))
((memq (syntax->datum #'a) js-ops) #'(js-op a c b1 ...)) ((memq (syntax->datum #'a) js-ops) #'(js-op a c b1 ...))
((eq? (syntax->datum #'a) 'begin) #'(js-begin c b1 ...)) ((eq? (syntax->datum #'a) 'begin) #'(js-begin c b1 ...))
((eq? (syntax->datum #'a) 'let) #'(error "let is not supported in js context, use let*")) ((eq? (syntax->datum #'a) 'let) #'(error "let is not supported in js context, use let*"))
@@ -392,10 +398,11 @@
#| #|
(define t1 (define t1
(js (set! window.myfunc (λ (x) (js (set! window.myfunc (λ (x)
(let* ((el (document.getElementById 'hi)) (let* ((el (send document getElementById 'hi))
(y (* x x))) (y (* x x)))
(el.setAttribute "x" (+ y "")) (send el setAttribute "x" (+ y ""))
) )
(send console log "dit set attribute x on element hi")
) )
))) )))
@@ -408,6 +415,33 @@
) )
) )
) )
(define t3 (js (define (f x y z)
(send console log (cons x (cons y (list z))))
(let* ((l (cons x (cons y (list z)))))
(return (send l map (λ (a) (return (+ a 10)))))
)
)
)
)
==>
function f(x, y, z) {
console.log([ x].concat([ y].concat([ z])));
{
let l = [ x].concat([ y].concat([ z]));
return (l.map(function (a) { return (a + 10);
;
}
));
;
}
;
}
;
|# |#
+8
View File
@@ -41,10 +41,18 @@
fatal-webview fatal-webview
sync-log-webview sync-log-webview
dbg-webview-backend
err-webview-backend
info-webview-backend
warn-webview-backend
fatal-webview-backend
sync-log-webview-backend
) )
(sl-def-log webview) (sl-def-log webview)
(sl-def-log webview-backend)
(define-syntax while (define-syntax while
(syntax-rules () (syntax-rules ()
+2 -2
View File
@@ -26,7 +26,7 @@
(define rkt-qt-version-major 0) (define rkt-qt-version-major 0)
(define rkt-qt-version-minor 2) (define rkt-qt-version-minor 2)
(define rkt-qt-version-patch 1) (define rkt-qt-version-patch 3)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Internal functions ;; Internal functions
@@ -164,7 +164,7 @@
(let ((out (open-output-file version-file #:exists 'replace))) (let ((out (open-output-file version-file #:exists 'replace)))
(write version out) (write version out)
(close-output-port out))) (close-output-port out)))
(displayln "Version file written; ready for FFI integration") (displayln "Version file written; backend process is ready")
#t #t
) )
) )
+856 -868
View File
File diff suppressed because it is too large Load Diff
+264 -117
View File
@@ -3,7 +3,7 @@
(require "racket-webview-qt.rkt" (require "racket-webview-qt.rkt"
"racket-webview-version.rkt" "racket-webview-version.rkt"
"private/utils.rkt" "private/utils.rkt"
"mimetypes.rkt" racket-mimetypes
"rgba.rkt" "rgba.rkt"
"menu.rkt" "menu.rkt"
finalizer finalizer
@@ -30,6 +30,7 @@
lru-cache lru-cache
racket-self-signed-cert racket-self-signed-cert
simple-log simple-log
js-maker
) )
(provide webview-new-context (provide webview-new-context
@@ -143,6 +144,10 @@
;test ;test
) )
(define (to-symbol s)
(string->symbol (format "~a" s)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Web server ;; Web server
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -396,6 +401,14 @@
#f)) #f))
(define-syntax with-id->el
(syntax-rules ()
((_ id el e1 ...)
(js (let ((el (send document getElementById (eval id))))
e1 ...)))
)
)
(define-syntax with-id (define-syntax with-id
(syntax-rules () (syntax-rules ()
((_ id el ((_ id el
@@ -420,9 +433,13 @@
(define-syntax with-selector (define-syntax with-selector
(syntax-rules () (syntax-rules ()
((_ selector func) ((_ selector func)
(format "return window.rkt_with_selector('~a', ~a)" (js
(esc-quote selector) (return (send window rkt_with_selector (eval selector) func))))
func)))) )
)
; (format "return window.rkt_with_selector('~a', ~a)"
; (esc-quote selector)
; func))))
(define (make-exts-filter list-of-pe) (define (make-exts-filter list-of-pe)
(define (mef pe) (define (mef pe)
@@ -572,22 +589,26 @@
(define/contract (webview-set-menu! wv menu) (define/contract (webview-set-menu! wv menu)
(-> wv-win? is-wv-menu? symbol?) (-> wv-win? is-wv-menu? symbol?)
(let* ((json (wv-menu->json menu)) (let* ((json (wv-menu->json menu))
(js (string-append "window._web_wire_menu('" (js-code (js (send window _web_wire_menu (eval json))))
json ;(string-append "window._web_wire_menu('"
"');")) ; json
; "');"))
) )
(webview-run-js wv js) (webview-run-js wv js-code)
) )
) )
(define/contract (webview-popup-menu! wv menu x y) (define/contract (webview-popup-menu! wv menu x y)
(-> wv-win? is-wv-menu? number? number? symbol?) (-> wv-win? is-wv-menu? number? number? symbol?)
(let* ((json (wv-menu->json menu)) (let* ((json (wv-menu->json menu))
(js (string-append "window._web_wire_popup_menu(JSON.parse('" (js-code (js (send window _web_wire_popup_menu
json "'), " (format "~a, ~a" x y) (send JSON parse (eval json))
");")) (eval x) (eval y))))
;(string-append "window._web_wire_popup_menu(JSON.parse('"
; json "'), " (format "~a, ~a" x y)
; ");"))
) )
(webview-run-js wv js))) (webview-run-js wv js-code)))
(define (loglevel? x) (define (loglevel? x)
(and (symbol? x) (and (symbol? x)
@@ -617,8 +638,10 @@
(define/contract (webview-navigate! wv place) (define/contract (webview-navigate! wv place)
(-> wv-win? string? symbol?) (-> wv-win? string? symbol?)
(webview-run-js wv (webview-run-js wv
(format "window.location = '~a';" (js (set! (js-dot window location) (eval place)))
(esc-quote place)))) ;(format "window.location = '~a';"
; (esc-quote place))))
))
(define/contract (webview-base-url wv) (define/contract (webview-base-url wv)
(-> wv-win? url?) (-> wv-win? url?)
@@ -718,10 +741,11 @@
(wv-win-window-nr wv) sel evt (if no-prevent-default 'true 'false))) (wv-win-window-nr wv) sel evt (if no-prevent-default 'true 'false)))
(r (webview-call-js wv j)) (r (webview-call-js wv j))
) )
;(dbg-webview "called js: ~a" j) (if (eq? r #f)
#f
(map (λ (el) (map (λ (el)
(list (string->symbol (car el)) (cadr el) (caddr el))) (list (string->symbol (car el)) (cadr el) (caddr el)))
r)))) r)))))
(define/contract (webview-unbind! wv selector event) (define/contract (webview-unbind! wv selector event)
(-> wv-win? (or/c symbol? string?) (or/c symbol? list-of-symbol?) list?) (-> wv-win? (or/c symbol? string?) (or/c symbol? list-of-symbol?) list?)
@@ -735,9 +759,11 @@
(let ((r (webview-call-js wv (let ((r (webview-call-js wv
(format "return window.rkt_unbind_evt_ids(~a, '~a', ~a)" (format "return window.rkt_unbind_evt_ids(~a, '~a', ~a)"
(wv-win-window-nr wv) sel evt)))) (wv-win-window-nr wv) sel evt))))
(if (eq? r #f)
#f
(map (λ (el) (map (λ (el)
(list (string->symbol (car el)) (cadr el) (caddr el))) (list (string->symbol (car el)) (cadr el) (caddr el)))
r)))) r)))))
(define/contract (webview-run-js wv js) (define/contract (webview-run-js wv js)
(-> wv-win? string? symbol?) (-> wv-win? string? symbol?)
@@ -762,15 +788,14 @@
(define/contract (webview-call-js wv js) (define/contract (webview-call-js wv js)
(-> wv-win? string? (or/c string? list? boolean? hash? symbol? number?)) (-> wv-win? string? (or/c string? list? boolean? hash? symbol? number?))
;(displayln js)
(let ((result (rkt-webview-call-js (wv-win-handle wv) js))) (let ((result (rkt-webview-call-js (wv-win-handle wv) js)))
;(displayln result)
(if (webview-call-js-result? result) (if (webview-call-js-result? result)
(if (eq? (car result) 'oke) (if (eq? (car result) 'oke)
(hash-ref (fromJson (cadr result)) 'result #f) (hash-ref (fromJson (cadr result)) 'result #f)
(error (begin
(format "Error calling javascript. Message: ~a" (err-webview "Error calling javascript: ~a" result)
(hash-ref (fromJson (cadr result)) 'exn result))) #f))
)
(error (error
(format "Wrong result from webview-call-js: ~a" result)) (format "Wrong result from webview-call-js: ~a" result))
) )
@@ -785,9 +810,12 @@
(-> wv-win? symbol? (or/c string? xexpr?) symbol?) (-> wv-win? symbol? (or/c string? xexpr?) symbol?)
(if (string? html) (if (string? html)
(let ((r (webview-call-js wv (let ((r (webview-call-js wv
(with-id id el (with-id->el id el
("el.innerHTML = '~a'; return true;" (set! (js-dot el innerHTML) (eval html))
(esc-quote html)))))) (return #t)))))
;(with-id id el
; ("el.innerHTML = '~a'; return true;"
; (esc-quote html))))))
(if r 'oke 'failed)) (if r 'oke 'failed))
(webview-set-innerHTML! wv id (xexpr->string html)) (webview-set-innerHTML! wv id (xexpr->string html))
) )
@@ -796,6 +824,26 @@
(define/contract (webview-set-value! wv id val) (define/contract (webview-set-value! wv id val)
(-> wv-win? symbol? (or/c symbol? string? number? boolean? g:date? g:time? g:datetime? rgba?) symbol?) (-> wv-win? symbol? (or/c symbol? string? number? boolean? g:date? g:time? g:datetime? rgba?) symbol?)
(webview-run-js wv (webview-run-js wv
(with-id->el id el
(if (or
(== (js-dot el type) "checkbox")
(== (js-dot el type) "radio"))
(set! (js-dot el checked)
(eval
(if (eq? val #f) #f #t)))
(set! (js-dot el value)
(eval
(cond
((g:date? val) (date->string val))
((g:time? val) (time->string val))
((g:datetime? val) (datetime->string val))
((rgba? val) (rgba->hex val))
(else val)))))
)
)
)
#|
(with-id id el (with-id id el
((string-append ((string-append
"if (el.type == 'checkbox' || el.type == 'radio') {\n" "if (el.type == 'checkbox' || el.type == 'radio') {\n"
@@ -819,19 +867,25 @@
) )
) )
) )
|#
(define/contract (webview-value wv id) (define/contract (webview-value wv id)
(-> wv-win? symbol? (or/c string? boolean?)) (-> wv-win? symbol? (or/c string? boolean?))
(let ((v (webview-call-js wv (let ((v (webview-call-js wv
(with-id id el (with-id->el id el
((string-append "let f = function() {\n" (if (or (== (js-dot el type) "checkbox")
" if (el.type == 'checkbox' || el.type == 'radio') {\n" (== (js-dot el type) "radio"))
" return '' + el.checked;\n" (return (js-dot el checked))
" } else {\n" (return (js-dot el value)))))))
" return el.value;\n" ;(with-id id el
" }\n" ; ((string-append "let f = function() {\n"
"};\n")) ; " if (el.type == 'checkbox' || el.type == 'radio') {\n"
-> "f()")))) ; " return '' + el.checked;\n"
; " } else {\n"
; " return el.value;\n"
; " }\n"
; "};\n"))
; -> "f()"))))
(if (eq? v #f) (if (eq? v #f)
#f #f
v))) v)))
@@ -859,132 +913,210 @@
(define/contract (webview-add-class! wv id-or-selector class) (define/contract (webview-add-class! wv id-or-selector class)
(-> wv-win? (or/c symbol? string?) (or/c symbol? string? list?) hash?) (-> wv-win? (or/c symbol? string?) (or/c symbol? string? list?) (or/c hash? boolean?))
(let ((sel (if (symbol? id-or-selector) (let ((sel (if (symbol? id-or-selector)
(format "#~a" id-or-selector) (format "#~a" id-or-selector)
id-or-selector)) id-or-selector))
(cl (mk-js-array class)) ;(cl (mk-js-array class))
(cl (if (list? class) class (list class)))
) )
(webview-call-js wv (with-selector sel (webview-call-js wv (with-selector sel
(format (λ (id el)
(js-code (let ((cl (eval cl)))
"function(id, el) {" (send cl forEach
" let cl = ~a;" (λ (c)
" cl.forEach(function(c) {" (send (js-dot el classList) add c)
" el.classList.add(c);" )
" });" )
" return id;" (return id))))
"}") cl))) )
) )
) )
; (format
; (js-code
; "function(id, el) {"
; " let cl = ~a;"
; " cl.forEach(function(c) {"
; " el.classList.add(c);"
; " });"
; " return id;"
; "}") cl)))
; )
; )
(define/contract (webview-remove-class! wv id-or-selector class) (define/contract (webview-remove-class! wv id-or-selector class)
(-> wv-win? (or/c symbol? string?) (or/c symbol? string? list?) hash?) (-> wv-win? (or/c symbol? string?) (or/c symbol? string? list?) (or/c hash? boolean?))
(let ((sel (if (symbol? id-or-selector) (let ((sel (if (symbol? id-or-selector)
(format "#~a" id-or-selector) (format "#~a" id-or-selector)
id-or-selector)) id-or-selector))
(cl (mk-js-array class)) (cl (if (list? class) class (list class)))
) )
(webview-call-js wv (webview-call-js wv
(with-selector sel (with-selector sel
(format (λ (id el)
(js-code (let ((cl (eval cl)))
"function(id, el) {" (send cl forEach
" let cl = ~a;" (λ (c)
" cl.forEach(function(c) {" (send (js-dot el classList) remove c))))
" el.classList.remove(c);" id)))
" });"
" return id;"
"}") cl))
)
) )
) )
; (with-selector sel
; (format
;; (js-code
; "function(id, el) {"
; " let cl = ~a;"
; " cl.forEach(function(c) {"
; " el.classList.remove(c);"
; " });"
; " return id;"
; "}") cl))
; )
; )
; )
(define/contract (webview-set-style! wv selector style-entries) (define/contract (webview-set-style! wv selector style-entries)
(-> wv-win? (or/c symbol? string?) (or/c kv? list-of-kv?) hash?) (-> wv-win? (or/c symbol? string?) (or/c kv? list-of-kv?) (or/c hash? boolean?))
(let ((sel (if (symbol? selector) (let ((sel (if (symbol? selector)
(format "#~a" selector) (format "#~a" selector)
selector)) selector))
(cl (mk-js-array (if (kv? style-entries) ;(cl (mk-js-array (if (kv? style-entries)
; (list style-entries)
; style-entries)))
(cl (if (kv? style-entries)
(list style-entries) (list style-entries)
style-entries))) style-entries))
) )
(webview-call-js wv (webview-call-js wv
(with-selector sel (with-selector sel
(format (λ (id el)
(js-code (let ((cl (eval cl)))
"function(id, el) {" (send cl forEach
" let cl = ~a;" (λ (st)
" cl.forEach(function(st) {" (set! (js-ref
" el.style[st[0]] = st[1];" (js-dot el style)
" });" (js-ref st 0))
" return id;" (js-ref st 1))))
"}") cl)) id)))
) )
) )
) )
; (format
; (js-code
; "function(id, el) {"
; " let cl = ~a;"
; " cl.forEach(function(st) {"
; " el.style[st[0]] = st[1];"
; " });"
; " return id;"
; "}") cl))
; )
; )
; )
(define/contract (webview-get-style wv selector styles) (define/contract (webview-get-style wv selector styles)
(-> wv-win? (or/c symbol? string?) (or/c symbol? list-of-symbol?) (or/c list? hash?)) (-> wv-win? (or/c symbol? string?) (or/c symbol? list-of-symbol?) (or/c list? hash? boolean?))
(let ((sel (if (symbol? selector) (let ((sel (if (symbol? selector)
(format "#~a" selector) (format "#~a" selector)
selector)) selector))
(cl (mk-js-array (if (symbol? styles) (cl (if (symbol? styles)
(list styles) (list styles)
styles))) styles))
;(cl (mk-js-array (if (symbol? styles)
; (list styles)
; styles)))
) )
(let ((r (webview-call-js wv (let ((js-code (with-selector sel
(with-selector sel (λ (id el)
(format (let ((cl (eval cl))
(js-code (r '()))
"function(id, el) {" (send cl forEach
" let cl = ~a;" (λ (st)
" let r = {};" (send console log st)
" cl.forEach(function(st) {" (let ((stl (send window getComputedStyle el)))
" let stl = window.getComputedStyle(el);" (set! (js-ref r st) (js-ref stl st)))))
" r[st] = stl[st];" (send console log r)
" });" (return (list (list 'id id)
" return { id: id, style: r };" (list 'style (send Object entries r))))))))
"}") cl)) )
))) ;(displayln js-code)
(let ((r (webview-call-js wv js-code)))
; (format
; (js-code
; "function(id, el) {"
; " let cl = ~a;"
; " let r = {};"
; " cl.forEach(function(st) {"
; " let stl = window.getComputedStyle(el);"
; " r[st] = stl[st];"
; " });"
; " return { id: id, style: r };"
; "}") cl))
; )))
; (display "Result: ") (write r) (newline)
(if (eq? r #f)
#f
(let ((h (hash-ref r 'with-ids))) (let ((h (hash-ref r 'with-ids)))
(let ((l (map (λ (e) (cons (string->symbol (hash-ref e 'id)) (hash-ref e 'style))) h))) (let ((l (map (λ (e)
(let ((id-rec (car e))
(style-rec (cadr e)))
(cons (string->symbol (cadr id-rec))
(make-hash (map (λ (e) (cons (to-symbol (car e)) (cadr e))) (cadr style-rec)))
)
)) h)))
;(displayln (format "l = ~a" l))
;(write l)(newline)
; l = ((volume-meter . #hash((display . none))))
; ((volume-meter . #hash(("display" . "none"))))
(if (symbol? selector) (if (symbol? selector)
(cdr (car l)) (cdr (car l))
l))) l)))))
) )
) )
) )
(define/contract (webview-unset-style! wv selector style-entries) (define/contract (webview-unset-style! wv selector style-entries)
(-> wv-win? (or/c symbol? string?) (or/c symbol? list-of-symbol?) hash?) (-> wv-win? (or/c symbol? string?) (or/c symbol? list-of-symbol?) (or/c hash? boolean?))
(let ((sel (if (symbol? selector) (let ((sel (if (symbol? selector)
(format "#~a" selector) (format "#~a" selector)
selector)) selector))
(cl (mk-js-array (if (symbol? style-entries) (cl (if (symbol? style-entries)
(list style-entries) (list style-entries)
style-entries))) style-entries))
) )
(webview-call-js wv (webview-call-js wv
(with-selector sel (with-selector sel
(format (λ (id el)
(js-code (let ((cl (eval cl)))
"function(id, el) {" (send cl forEach
" let cl = ~a;" (λ (st)
" cl.forEach(function(st) {" (set! (js-ref
" el.style[st] = '';" (js-dot el style)
" });" st) "")))
" return id;" id))))
"}") cl)
)
)
) )
) )
; (format
; (js-code
; "function(id, el) {"
; " let cl = ~a;"
; " cl.forEach(function(st) {"
; " el.style[st] = '';"
; " });"
; " return id;"
; "}") cl)
; )
; )
; )
; )
(define/contract (webview-set-attr! wv selector attr-entries) (define/contract (webview-set-attr! wv selector attr-entries)
(-> wv-win? (or/c symbol? string?) (-> wv-win? (or/c symbol? string?)
(or/c kv? list-of-kv?) hash?) (or/c kv? list-of-kv?) (or/c hash? boolean?))
(let* ((sel (if (symbol? selector) (let* ((sel (if (symbol? selector)
(format "#~a" selector) (format "#~a" selector)
selector)) selector))
@@ -999,29 +1131,44 @@
([rgba? v] (rgba->hex v)) ([rgba? v] (rgba->hex v))
(else (format "~a" v)))) (else (format "~a" v))))
)) ae*)) )) ae*))
(cl (mk-js-array ae**)) ;(cl (mk-js-array ae**))
(cl ae**)
) )
;(display cl)
(webview-call-js wv (webview-call-js wv
(with-selector sel (with-selector sel
(format (λ (id el)
(js-code (let ((cl (eval cl)))
"function(id, el) {" (send cl forEach
" let cl = ~a;" (λ (av)
" cl.forEach(function(av) {" (send el setAttribute (js-ref av 0)
" el.setAttribute(av[0], av[1]);" (js-ref av 1))))
" });" id))))
" return id;"
"}") cl))
)
) )
) )
; (with-selector sel
; (format
; (js-code
; "function(id, el) {"
; " let cl = ~a;"
; " cl.forEach(function(av) {"
; " el.setAttribute(av[0], av[1]);"
; " });"
; " return id;"
; "}") cl))
; )
; )
; )
(define/contract (webview-attr wv id attr) (define/contract (webview-attr wv id attr)
(-> wv-win? symbol? (or/c symbol? string?) (or/c string? boolean?)) (-> wv-win? symbol? (or/c symbol? string?) (or/c string? boolean?))
(let ((v (webview-call-js wv (let ((v (webview-call-js wv
(with-id id el (with-id->el id el
-> (format "el.getAttribute('~a');" attr)) (return (send el getAttribute (eval attr)))))))
))) ;(with-id id el
; -> (format "el.getAttribute('~a');" attr))
;)))
(if (eq? v 'null) (if (eq? v 'null)
#f #f
v) v)
+340
View File
@@ -0,0 +1,340 @@
#lang scribble/manual
@(require (for-label racket/base
"../private/js-transform.rkt"))
@title[#:tag "js-transform"]{JavaScript Transformation}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/private/js-transform]
This module provides a small compile-time DSL for generating JavaScript source
text from Racket-like forms. It is used internally by the webview
implementation to construct JavaScript snippets in a structured way, without
having to write the complete snippet as one raw string.
The module exports only @racket[js]. The other forms described in this section
are DSL forms recognized by @racket[js]; they are not exported as separate
bindings.
@defform[
(js js-statement ...)
]{
Transforms each @racket[js-statement] into JavaScript source text. The result
is a string. The generated string is not evaluated by Racket and no JavaScript
is executed by this module.
Each top-level statement is emitted with a trailing semicolon and newline. The
resulting string can be passed to the webview layer for injection or execution
in the browser context.
For example:
@racketblock[
(define source
(js
(set! window.myfunc
(λ (x)
(let* ((el (send document getElementById 'hi))
(y (* x x)))
(send el setAttribute "x" (+ y "")))
(send console log "did set attribute x on element hi")))))
]
This generates JavaScript source that assigns a function to
@tt{window.myfunc}. The function looks up a DOM element, calculates a value,
sets an attribute, and writes a message to the JavaScript console.
}
@section[#:tag "js-transform-primitive-values"]{Primitive values}
Numbers are emitted as JavaScript numeric literals. Strings are emitted as
double-quoted JavaScript strings, with embedded double quotes escaped.
Identifiers are emitted as JavaScript names.
For example:
@racketblock[
(js
(send console log "hello")
(send console log 42))
]
Symbols can be quoted to produce JavaScript string values:
@racketblock[
(js
(send console log 'hello))
]
@section[#:tag "js-transform-function-calls-and-method-calls"]{Function calls and method calls}
A form that is not recognized as a special DSL form is treated as a JavaScript
function call:
@racketblock[
(js
(alert "Hello from Racket"))
]
This generates a JavaScript call to @tt{alert}.
Method calls can be written with @racket[send]:
@racketblock[
(js
(send document getElementById 'hi))
]
The @racket[send] form has the shape:
@racketblock[
(send object method arg ...)
]
and generates a JavaScript method call of the form:
@codeblock|{
object.method(arg, ...)
}|
For example, @racket[(send document getElementById 'hi)] generates a call shaped
like:
@codeblock|{
document.getElementById("hi")
}|
Using @racket[send] keeps the method-call structure explicit in the DSL. It is
usually clearer than writing dotted JavaScript names directly as function names.
@section[#:tag "js-transform-operators"]{Operators}
The DSL supports a small set of JavaScript infix operators.
@itemlist[
#:style 'compact
@item{@racket[(+ a b ...)], @racket[(- a b ...)],
@racket[(* a b ...)] and @racket[(/ a b ...)] generate arithmetic infix
expressions.}
@item{@racket[(and a b ...)] and @racket[(or a b ...)] generate JavaScript
@tt{&&} and @tt{||} expressions.}
@item{@racket[(> a b)], @racket[(< a b)], @racket[(>= a b)],
@racket[(<= a b)], @racket[(== a b)], @racket[(=== a b)] and
@racket[(!= a b)] generate JavaScript comparison expressions.}
]
For example:
@racketblock[
(js
(define (inside-range x)
(if (and (> x 10) (< x 15))
(return x)
(return (* x x)))))
]
@section[#:tag "js-transform-definitions-and-assignments"]{Definitions and assignments}
@defform[(define (name arg ...) body ...)]{
Generates a JavaScript function declaration.
@racketblock[
(js
(define (square x)
(return (* x x))))
]
This produces a JavaScript function named @tt{square}.
}
@defform[(set! name expr)]{
Generates a JavaScript assignment.
@racketblock[
(js
(set! window.answer 42))
]
This produces an assignment to @tt{window.answer}.
}
@section[#:tag "js-transform-functions"]{Functions}
@defform[(lambda (arg ...) body ...)]{
Generates a JavaScript function expression.
}
@defform[(λ (arg ...) body ...)]{
Equivalent to @racket[lambda].
}
For example:
@racketblock[
(js
(set! window.square
(λ (x)
(return (* x x)))))
]
A function body may contain more than one DSL statement:
@racketblock[
(js
(set! window.f
(λ (x)
(send console log x)
(return (* x x)))))
]
@section[#:tag "js-transform-control-flow-and-statement-blocks"]{Control flow and statement blocks}
@defform[(if condition then-expr else-expr)]{
Generates a JavaScript @tt{if}/@tt{else} statement. The condition is translated
as a JavaScript expression. The two branches are translated as JavaScript
statements.
@racketblock[
(js
(define (f x)
(if (> x 0)
(return x)
(return (- 0 x)))))
]
}
@defform[(begin body ...)]{
Generates a JavaScript block.
@racketblock[
(js
(if (> x 10)
(begin
(send console log x)
(return x))
(return 0)))
]
}
@defform[(return expr)]{
Generates a JavaScript @tt{return} statement.
@racketblock[
(js
(define (id x)
(return x)))
]
}
@section[#:tag "js-transform-sequential-bindings"]{Sequential bindings}
@defform[(let* ((id expr) ...) body ...)]{
Generates a JavaScript block with sequential @tt{let} declarations, followed by
the generated body statements.
@racketblock[
(js
(let* ((x 10)
(y (* x x)))
(send console log y)
(return y)))
]
The plain @racket[let] form is intentionally not supported in a JavaScript
context. Use @racket[let*] instead, so that the generated JavaScript bindings
remain explicitly sequential.
}
@section[#:tag "js-transform-lists"]{Lists}
@defform[(list expr ...)]{
Generates a JavaScript array literal.
@racketblock[
(js
(send console log (list 1 2 3)))
]
}
@defform[(cons expr list-expr)]{
Generates JavaScript that prepends a value to an array-like expression by
concatenating a one-element array with the translated list expression.
For example:
@racketblock[
(js
(send console log (cons x (cons y (list z)))))
]
This generates JavaScript shaped like:
@codeblock|{
console.log([ x].concat([ y].concat([ z])));
}|
}
@section[#:tag "js-transform-embedding-racket-values"]{Embedding Racket values}
@defform[(eval value)]{
Embeds a simple Racket value as a JavaScript literal at expansion time. The
supported values are strings, symbols, numbers and lists containing those same
kinds of values.
@racketblock[
(define names '(alice bob charlie))
(js
(send console log (eval names)))
]
The value is converted to JavaScript source text before the generated JavaScript
is returned.
}
@section[#:tag "js-transform-example"]{Example}
The following example combines function definition, method calls, list
construction, sequential bindings and a lambda expression passed to a JavaScript
method:
@racketblock[
(define source
(js
(define (f x y z)
(send console log (cons x (cons y (list z))))
(let* ((l (cons x (cons y (list z)))))
(return
(send l map
(λ (a)
(return (+ a 10)))))))))
]
This generates a JavaScript function that logs an array, constructs the same
array in a local binding, maps over it, and returns the mapped result.
@section[#:tag "js-transform-limitations"]{Limitations}
This transformer is intentionally small. It is not a complete JavaScript
parser, not a JavaScript evaluator and not a general Racket-to-JavaScript
compiler. Unrecognized forms are generally treated as JavaScript function
calls. This keeps the implementation compact, but it also means that some
mistakes may produce JavaScript source that only fails when the browser runs the
generated code.
The generated source is intended for small snippets used by the webview layer,
not for translating arbitrary Racket programs to JavaScript.
+9 -9
View File
@@ -8,7 +8,7 @@
json json
"../menu.rkt")) "../menu.rkt"))
@title{menu} @title[#:tag "menu"]{menu}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/menu] @defmodule[racket-webview/menu]
@@ -18,7 +18,7 @@ Menu data structures used by the webview library.
This module provides constructors, predicates, traversal helpers, mutation This module provides constructors, predicates, traversal helpers, mutation
operations, and JSON conversion for menu trees. operations, and JSON conversion for menu trees.
@section{Overview} @section[#:tag "menu-overview"]{Overview}
A menu is represented as a tree. A menu consists of menu items, and a menu item A menu is represented as a tree. A menu consists of menu items, and a menu item
may optionally contain a submenu. may optionally contain a submenu.
@@ -29,14 +29,14 @@ strings and may be supplied either as @racket[#f], strings, or URL values.
The module does not display menus itself. It provides the menu data structure The module does not display menus itself. It provides the menu data structure
used by higher layers. used by higher layers.
@section{Internal Representation} @section[#:tag "menu-internal-representation"]{Internal Representation}
Internally, menus are represented by transparent structure values. These Internally, menus are represented by transparent structure values. These
structure constructors and predicates are not exported directly. The public API structure constructors and predicates are not exported directly. The public API
uses constructor procedures and helper functions operating on those internal uses constructor procedures and helper functions operating on those internal
values. values.
@section{Predicates} @section[#:tag "menu-predicates"]{Predicates}
@defproc[(is-wv-menu? [mnu any/c]) boolean?]{ @defproc[(is-wv-menu? [mnu any/c]) boolean?]{
@@ -48,7 +48,7 @@ list is a list of internal menu items, and every submenu recursively also
satisfies @racket[is-wv-menu?]. satisfies @racket[is-wv-menu?].
} }
@section{Constructors} @section[#:tag "menu-constructors"]{Constructors}
@defproc[(wv-menu [item-or-id any/c] ...) @defproc[(wv-menu [item-or-id any/c] ...)
any/c]{ any/c]{
@@ -97,7 +97,7 @@ stored.
If any argument does not satisfy these conditions, an exception is raised. If any argument does not satisfy these conditions, an exception is raised.
} }
@section{Traversal and Lookup} @section[#:tag "menu-traversal-and-lookup"]{Traversal and Lookup}
@defproc[(wv-menu-for-each [menu any/c] [cb procedure?]) boolean?]{ @defproc[(wv-menu-for-each [menu any/c] [cb procedure?]) boolean?]{
@@ -121,7 +121,7 @@ After the callback has been applied, the original @racket[menu] value is
returned. returned.
} }
@section{Mutation} @section[#:tag "menu-mutation"]{Mutation}
@defproc[(wv-menu-set-title! [menu any/c] [id symbol?] [title string?]) @defproc[(wv-menu-set-title! [menu any/c] [id symbol?] [title string?])
any/c]{ any/c]{
@@ -154,7 +154,7 @@ Sets the callback of the menu item identified by @racket[id].
@racket[menu] value. @racket[menu] value.
} }
@section{Conversion} @section[#:tag "menu-conversion"]{Conversion}
@defproc[(wv-menu->json [menu any/c]) string?]{ @defproc[(wv-menu->json [menu any/c]) string?]{
@@ -177,7 +177,7 @@ The @racket['id] field of the top-level menu is also converted to a string in
the JSON output. the JSON output.
} }
@section{Accessors} @section[#:tag "menu-accessors"]{Accessors}
@defproc[(wv-menu-id [m any/c]) any/c]{ @defproc[(wv-menu-id [m any/c]) any/c]{
-60
View File
@@ -1,60 +0,0 @@
#lang scribble/manual
@(require racket/base
scribble/core
(for-label racket/base
racket/string
racket/file))
@title{mimetypes}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/mimetypes]
MIME type utilities used by the webview library.
This module provides a mapping from file extensions to MIME types together with
a function to determine the MIME type of a file path.
@section{Overview}
The module is used by the local HTTPS server to determine the correct
@tt{Content-Type} header when serving files.
MIME types are determined based on the file extension.
@section{Function: path->mimetype}
@defproc[(path->mimetype [p path-string?]) string?]{
Returns the MIME type associated with @racket[p].
The file extension of @racket[p] is extracted and used to look up the
corresponding MIME type.
If the extension is not recognized, a default MIME type is returned.
}
@section{Mapping}
The module contains a predefined mapping from file extensions to MIME types.
Typical mappings include:
@itemlist[#:style 'compact
@item{@tt{.html} → @tt{text/html}}
@item{@tt{.css} → @tt{text/css}}
@item{@tt{.js} → @tt{application/javascript}}
@item{@tt{.json} → @tt{application/json}}
@item{@tt{.png} → @tt{image/png}}
@item{@tt{.jpg}, @tt{.jpeg} → @tt{image/jpeg}}
@item{@tt{.svg} → @tt{image/svg+xml}}]
The exact mapping is defined in the source code and can be extended if needed.
@section{Notes}
The returned MIME type is always a string suitable for use in HTTP response
headers.
File extensions are interpreted case-insensitively.
+27
View File
@@ -0,0 +1,27 @@
#lang scribble/manual
@(require racket/runtime-path
scribble/core
)
@title[#:tag "racket-webview-collection"]{@elem{racket-webview}}
@table-of-contents[]
@include-section["racket-webview-intro.scrbl"]
@include-section["wv-context.scrbl"]
@include-section["wv-settings.scrbl"]
@include-section["wv-window.scrbl"]
@include-section["menu.scrbl"]
@include-section["wv-dialog.scrbl"]
@include-section["wv-element.scrbl"]
@include-section["wv-input.scrbl"]
@include-section["js-transform.scrbl"]
@include-section["racket-webview.scrbl"]
@include-section["racket-webview-qt.scrbl"]
@include-section["rgba.scrbl"]
@include-section["rktwebview-api.scrbl"]
@include-section["rktwebviewqt-internals.scrbl"]
@index-section[]
+7 -7
View File
@@ -7,7 +7,7 @@
setup/dirs setup/dirs
"../racket-webview-downloader.rkt")) "../racket-webview-downloader.rkt"))
@title{racket-webview-downloader} @title[#:tag "racket-webview-downloader"]{racket-webview-downloader}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/racket-webview-downloader] @defmodule[racket-webview/racket-webview-downloader]
@@ -18,7 +18,7 @@ This module provides functions for checking whether the native runtime is
already installed, whether it can be resolved and downloaded, and for already installed, whether it can be resolved and downloaded, and for
downloading and unpacking it into the user's addon directory. downloading and unpacking it into the user's addon directory.
@section{Overview} @section[#:tag "racket-webview-downloader-overview"]{Overview}
The module manages one specific downloadable version of the native The module manages one specific downloadable version of the native
@tt{racket-webview-qt} package. The version is fixed in the source code through @tt{racket-webview-qt} package. The version is fixed in the source code through
@@ -36,7 +36,7 @@ The download URL is derived from:
The downloaded archive is installed below the user's addon directory in a The downloaded archive is installed below the user's addon directory in a
subdirectory named @tt{racket-webview-qt}. subdirectory named @tt{racket-webview-qt}.
@section{Installation Layout} @section[#:tag "racket-webview-downloader-installation-layout"]{Installation Layout}
The installation directory is: The installation directory is:
@@ -57,7 +57,7 @@ The OS and architecture components are derived from:
(system-type 'arch) (system-type 'arch)
] ]
@section{Availability and Version Checks} @section[#:tag "racket-webview-downloader-availability-and-version-checks"]{Availability and Version Checks}
@defproc[(racket-webview-qt-is-available?) boolean?]{ @defproc[(racket-webview-qt-is-available?) boolean?]{
@@ -93,7 +93,7 @@ The returned path has the form:
] ]
} }
@section{Downloadability Checks} @section[#:tag "racket-webview-downloader-downloadability-checks"]{Downloadability Checks}
@defproc[(racket-webview-qt-resolves?) boolean?]{ @defproc[(racket-webview-qt-resolves?) boolean?]{
@@ -114,7 +114,7 @@ succeeds, the port is closed immediately and the function returns
@racket[#t]. Any failure is caught and results in @racket[#f]. @racket[#t]. Any failure is caught and results in @racket[#f].
} }
@section{Downloading} @section[#:tag "racket-webview-downloader-downloading"]{Downloading}
@defproc[(download-racket-webview-qt) boolean?]{ @defproc[(download-racket-webview-qt) boolean?]{
@@ -138,7 +138,7 @@ If no download port can be obtained, the function raises an exception. Otherwise
on successful completion, it returns @racket[#t]. on successful completion, it returns @racket[#t].
} }
@section{Notes} @section[#:tag "racket-webview-downloader-notes"]{Notes}
The module forces HTTPS downloads by temporarily setting the current HTTPS The module forces HTTPS downloads by temporarily setting the current HTTPS
protocol to @racket['secure] while opening the download port. protocol to @racket['secure] while opening the download port.
+12 -11
View File
@@ -16,31 +16,32 @@
"../wv-dialog.rkt" "../wv-dialog.rkt"
"../wv-settings.rkt" "../wv-settings.rkt"
"../rgba.rkt" "../rgba.rkt"
"../mimetypes.rkt" racket-mimetypes
"../racket-webview-version.rkt")) "../racket-webview-version.rkt"))
@(define version (webview-version-string)) @(define version (webview-version-string))
@title{Racket Webview - v@version - Introduction} @title[#:tag "racket-webview-intro"]{Racket Webview - v@version - Introduction}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule{racket-webview} @defmodule{racket-webview}
@section{Overview} @section[#:tag "racket-webview-intro-overview"]{Overview}
This documentation is provided for version @bold{@version} of racket webview. This documentation is provided for version @bold{@version} of racket webview.
Racket Webview is a class-oriented webview library built on top of a Qt-based Racket Webview is a class-oriented webview library built on top of a Qt-based
native runtime. native runtime.
The library is layered. At the lowest level a native FFI layer is used. On top The library is layered. At the lowest level, Racket starts a separate Qt helper
of that, @racketmodname[racket-webview/racket-webview] provides a functional API. The process and exchanges line-delimited JSON messages through stdin and stdout.
class-oriented API described in this manual is built from smaller modules on top On top of that, @racketmodname[racket-webview/racket-webview] provides a
of that layer. functional API. The class-oriented API described in this manual is built from
smaller modules on top of that layer.
@section{Core Concepts} @section[#:tag "racket-webview-intro-core-concepts"]{Core Concepts}
The library is structured around two main concepts: The library is structured around two main concepts:
@@ -51,7 +52,7 @@ The library is structured around two main concepts:
A context manages local file serving, certificates, and settings. A window loads A context manages local file serving, certificates, and settings. A window loads
content, handles events, and provides access to DOM elements. content, handles events, and provides access to DOM elements.
@section{Modules} @section[#:tag "racket-webview-intro-modules"]{Modules}
The public API is divided into the following modules: The public API is divided into the following modules:
@@ -63,9 +64,9 @@ The public API is divided into the following modules:
@item{@racketmodname[racket-webview/wv-dialog] — dialog windows} @item{@racketmodname[racket-webview/wv-dialog] — dialog windows}
@item{@racketmodname[racket-webview/wv-settings] — settings wrapper} @item{@racketmodname[racket-webview/wv-settings] — settings wrapper}
@item{@racketmodname[racket-webview/rgba] — RGBA color values} @item{@racketmodname[racket-webview/rgba] — RGBA color values}
@item{@racketmodname[racket-webview/mimetypes] — MIME type lookup}] @item{@racketmodname[racket-mimetypes] — MIME type lookup}]
@section{Typical Usage} @section[#:tag "racket-webview-intro-typical-usage"]{Typical Usage}
A typical application creates a @racket[wv-context%] object and then creates one A typical application creates a @racket[wv-context%] object and then creates one
or more @racket[wv-window%] objects within that context. DOM elements are or more @racket[wv-window%] objects within that context. DOM elements are
+61 -101
View File
@@ -2,23 +2,24 @@
@defmodule{racket-webview/racket-webview-qt} @defmodule{racket-webview/racket-webview-qt}
@title{Racket FFI Interface for @tt{rktwebview_qt}} @title[#:tag "rktwebview-process"]{Racket Process Interface for @tt{rktwebview_prg}}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@section{Overview} @section[#:tag "racket-webview-qt-overview"]{Overview}
The module @tt{racket-webview-qt.rkt} provides a Racket FFI wrapper around the The module @tt{racket-webview-qt.rkt} provides the low-level Racket interface to
native @tt{rktwebview_qt} library. It loads the shared library, initializes the the Qt helper process @tt{rktwebview_prg}. It keeps the existing command numbers,
native runtime, and exposes Racket functions for creating and controlling JSON command payloads, result symbols, event strings, and public Racket
webview windows. procedures, but no longer loads a shared library through FFI.
If the Qt backend is available locally, it is loaded directly. Otherwise the The helper process is started lazily when the first backend operation is
module attempts to resolve and download the backend. If that is not possible, requested. Commands are written as one JSON object per line to the process
the module continues in a degraded mode in which a limited subset of the stdin. Results and asynchronous events are read from stdout. Backend diagnostics
FFI entry points will only display a warning and perform a no-op. All others will fail. are copied from stderr to the current Racket error port.
The wrapper translates the low-level C interface into a Racket-oriented API Each command has a request identifier. The identifier is transport metadata and
based on structures, callbacks, and ordinary Racket values. does not alter the existing command payload. It makes it possible to associate
a result with the correct caller when multiple Racket threads use the backend.
The module provides: The module provides:
@@ -30,81 +31,39 @@ The module provides:
@item{window geometry and visibility control} @item{window geometry and visibility control}
@item{native dialogs} @item{native dialogs}
@item{asynchronous event delivery} @item{asynchronous event delivery}
@item{version and cleanup utilities} @item{version and cleanup utilities}]
]
@section{Requirements} @section[#:tag "racket-webview-qt-backend-availability"]{Backend Availability}
The native backend requires Qt version @tt{6.10.2} or newer. The environment variable @tt{RKT_WEBVIEW_PRG} may name an explicit backend
executable. This is useful during development and testing.
The shared library @tt{rktwebview_qt} must therefore be built against Qt Without that variable, the module uses the existing downloader and installation
@tt{6.10.2} or a compatible later release. directory. Availability is checked when the first backend operation is made,
not while the module is loaded. If the configured backend cannot be found or
downloaded, that operation raises an exception with the reason.
Earlier Qt versions are not supported. @section[#:tag "racket-webview-qt-module-initialization"]{Module Initialization}
@section{Backend Availability} Starting the backend performs the following steps:
The module first checks whether the expected @tt{racket-webview-qt} backend is
already installed.
If it is not installed, the module attempts to resolve the configured download
site. If the site can be resolved and the configured archive is downloadable,
the backend is downloaded automatically.
If the download site cannot be resolved, if no archive is available for the
current operating system and machine architecture, or if the download fails, the
module does not immediately abort module loading. Instead it switches to a
degraded mode in which native FFI loading is disabled.
In that degraded mode, a textual reason is stored internally and selected FFI
entry points are replaced by fallback implementations.
When the backend cannot be loaded, the module defines fallback implementations
for missing FFI entry points through @racket[define-ffi-definer] and
@racket[#:default-make-fail].
These fallbacks behave in two different ways.
For a small set of initialization and shutdown functions, a non-failing fallback
is installed:
@itemlist[#:style 'compact @itemlist[#:style 'compact
@item{@racket[rkt_webview_env] returns @racket[#t]} @item{locates or downloads @tt{rktwebview_prg}}
@item{@racket[rkt_webview_events_waiting] returns @racket[0]} @item{sets the Qt runtime environment for the child process}
@item{@racket[rkt_webview_init] returns @racket[#t]} @item{starts the child with separate stdin, stdout, and stderr pipes}
@item{@racket[rkt_webview_cleanup] returns @racket[#t]}] @item{starts a stdout protocol reader}
@item{starts a stderr forwarding thread}
@item{waits for the protocol-version handshake}
@item{starts an independent Racket event-dispatch thread}]
All other missing FFI functions raise an exception when called. Stdout is reserved for protocol records. Human-readable backend logging is
written only to stderr.
Fallback warnings are emitted at most once per function. If native loading was Currently the wrapper supports @tt{'linux} and @tt{'windows} release layouts.
disabled because the backend was unavailable, the warning message includes the
recorded reason. If native loading was enabled but a specific symbol could not
be loaded from the library, the error names the library file.
@section{Module Initialization} @section[#:tag "racket-webview-qt-data-model"]{Data Model}
Loading the module performs several initialization steps automatically. @subsection[#:tag "racket-webview-qt-rkt-wv-structure"]{The @tt{rkt-wv} Structure}
@itemlist[#:style 'compact
@item{determines the operating system and architecture}
@item{sets Qt runtime environment variables}
@item{loads the @tt{rktwebview_qt} shared library}
@item{initializes the native runtime}
@item{starts a background thread that processes native events}
]
Currently the wrapper supports the following platforms:
@itemlist[#:style 'compact
@item{@tt{'linux}}
@item{@tt{'windows}}
]
If the current system is unsupported, loading the module raises an error.
@section{Data Model}
@subsection{The @tt{rkt-wv} Structure}
Each webview window is represented by a transparent Racket structure. Each webview window is represented by a transparent Racket structure.
@@ -136,7 +95,7 @@ an opaque handle.
@;Returns the native window handle associated with @racket[wv]. @;Returns the native window handle associated with @racket[wv].
@;} @;}
@section{HTTP(S) Contexts} @section[#:tag "racket-webview-qt-http-s-contexts"]{HTTP(S) Contexts}
A context represents the shared HTTP(S) environment used by webviews. A context represents the shared HTTP(S) environment used by webviews.
@@ -167,7 +126,7 @@ The returned context identifier can be passed to
@racket[rkt-webview-create] to create webviews within that context. @racket[rkt-webview-create] to create webviews within that context.
} }
@section{Creating Webviews} @section[#:tag "racket-webview-qt-creating-webviews"]{Creating Webviews}
@defproc[(rkt-webview-create @defproc[(rkt-webview-create
[context exact-integer?] [context exact-integer?]
@@ -194,14 +153,15 @@ Events generated by the native layer are delivered asynchronously through
@racket[evt-callback]. @racket[evt-callback].
} }
@section{Window Lifecycle} @section[#:tag "racket-webview-qt-window-lifecycle"]{Window Lifecycle}
@defproc[(rkt-webview-close [wv rkt-wv?]) boolean?]{ @defproc[(rkt-webview-close [wv rkt-wv?]) boolean?]{
Requests that the webview window be closed. Requests that the webview window be closed.
The wrapper forwards the request to the native backend and schedules cleanup of The wrapper forwards the request to the helper process. The Qt-generated
the event-processing loop. @tt{"closed"} event is delivered asynchronously, after which the Racket handle
is removed.
Returns @racket[#t]. Returns @racket[#t].
} }
@@ -222,7 +182,7 @@ This function is also registered with the Racket plumber so that cleanup occurs
automatically when the process exits. automatically when the process exits.
} }
@section{Window Configuration} @section[#:tag "racket-webview-qt-window-configuration"]{Window Configuration}
@defproc[(rkt-webview-set-title! [wv rkt-wv?] [title string?]) @defproc[(rkt-webview-set-title! [wv rkt-wv?] [title string?])
symbol?]{ symbol?]{
@@ -246,7 +206,7 @@ This token may be used by the native layer when accepting certain
self-signed certificates. self-signed certificates.
} }
@section{Navigation} @section[#:tag "racket-webview-qt-navigation"]{Navigation}
@defproc[(rkt-webview-set-url! [wv rkt-wv?] [url string?]) symbol?]{ @defproc[(rkt-webview-set-url! [wv rkt-wv?] [url string?]) symbol?]{
@@ -272,7 +232,7 @@ Returns a result symbol such as:
] ]
} }
@section{JavaScript Execution} @section[#:tag "racket-webview-qt-javascript-execution"]{JavaScript Execution}
@defproc[(rkt-webview-run-js [wv rkt-wv?] [js string?]) symbol?]{ @defproc[(rkt-webview-run-js [wv rkt-wv?] [js string?]) symbol?]{
@@ -305,7 +265,7 @@ where:
The JSON structure is generated by the native backend. The JSON structure is generated by the native backend.
} }
@section{Window Geometry} @section[#:tag "racket-webview-qt-window-geometry"]{Window Geometry}
@defproc[(rkt-webview-move [wv rkt-wv?] [x exact-integer?] [y exact-integer?]) @defproc[(rkt-webview-move [wv rkt-wv?] [x exact-integer?] [y exact-integer?])
symbol?]{ symbol?]{
@@ -362,13 +322,13 @@ Possible results:
] ]
} }
@section{Developer Tools} @section[#:tag "racket-webview-qt-developer-tools"]{Developer Tools}
@defproc[(rkt-webview-open-devtools [wv rkt-wv?]) symbol?]{ @defproc[(rkt-webview-open-devtools [wv rkt-wv?]) symbol?]{
Opens the browser developer tools window. Opens the browser developer tools window.
} }
@section{Native Dialogs} @section[#:tag "racket-webview-qt-native-dialogs"]{Native Dialogs}
Dialog functions return immediately with a status code. Dialog functions return immediately with a status code.
The users choice is delivered asynchronously through the event callback. The users choice is delivered asynchronously through the event callback.
@@ -413,7 +373,7 @@ Requests a file-save dialog.
Shows a native message box. Shows a native message box.
} }
@section{Event Delivery} @section[#:tag "racket-webview-qt-event-delivery"]{Event Delivery}
Each webview has an associated event callback. Each webview has an associated event callback.
@@ -445,23 +405,23 @@ Typical event types include:
The wrapper does not parse the JSON payload. The wrapper does not parse the JSON payload.
@section{Version Information} @section[#:tag "racket-webview-qt-version-information"]{Version Information}
@defproc[(rkt-webview-version) @defproc[(rkt-webview-version)
(list/c list? list?)]{ (list/c list? list?)]{
Returns version information for the native backend. Returns the stdio protocol version and the expected Qt backend release.
Example result: Example result:
@racketblock[ @racketblock[
(list (list
(list 'webview-c-api 1 0 0) (list 'webview-stdio-api 1 0 0)
(list 'qt 6 10 2)) (list 'racket-webview-qt 0 2 3))
] ]
} }
@section{Example} @section[#:tag "racket-webview-qt-example"]{Example}
@racketblock[ @racketblock[
(define ctx (define ctx
@@ -480,16 +440,16 @@ Example result:
(rkt-webview-set-url! wv "https://example.org") (rkt-webview-set-url! wv "https://example.org")
] ]
@section{Summary} @section[#:tag "racket-webview-qt-summary"]{Summary}
The FFI module provides a thin Racket interface to the native The module provides a thin Racket interface to the separate
@tt{rktwebview_qt} backend. @tt{rktwebview_prg} process.
Key characteristics: Key characteristics:
@itemlist[#:style 'compact @itemlist[#:style 'compact
@item{thin wrapper around the native C API} @item{line-delimited JSON over stdin and stdout}
@item{asynchronous event delivery} @item{request identifiers for concurrent synchronous calls}
@item{JSON-based event payloads} @item{asynchronous event delivery on a separate Racket thread}
@item{simple Racket structures for webviews} @item{unchanged JSON event payloads}
] @item{simple Racket structures for webviews}]
+20 -19
View File
@@ -3,7 +3,7 @@
@(require racket/base @(require racket/base
scribble/core) scribble/core)
@title{racket-webview} @title[#:tag "racket-webview"]{racket-webview}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/racket-webview] @defmodule[racket-webview/racket-webview]
@@ -14,7 +14,7 @@ This module provides a structured programming model around the lower-level
webview bindings. It introduces contexts, a local HTTPS server, JSON-based webview bindings. It introduces contexts, a local HTTPS server, JSON-based
event handling, and DOM and JavaScript utilities. event handling, and DOM and JavaScript utilities.
@section{Architecture} @section[#:tag "racket-webview-architecture"]{Architecture}
The module builds on the lower-level bindings from The module builds on the lower-level bindings from
@racketmodname[racket-webview/racket-webview-qt]. It adds: @racketmodname[racket-webview/racket-webview-qt]. It adds:
@@ -31,7 +31,7 @@ JavaScript calls. When an HTML file is
served, the context's CSS boilerplate is injected immediately before the served, the context's CSS boilerplate is injected immediately before the
closing @tt{</head>} tag. closing @tt{</head>} tag.
@section{Contexts} @section[#:tag "racket-webview-contexts"]{Contexts}
@defproc[(webview-new-context @defproc[(webview-new-context
@@ -76,7 +76,7 @@ This URL can be used to construct URLs from relative path information.
Recognizes context values. Recognizes context values.
} }
@section{Windows} @section[#:tag "racket-webview-windows"]{Windows}
@defproc[(webview-create @defproc[(webview-create
[context wv-context?] [context wv-context?]
@@ -136,7 +136,7 @@ Resizes the window.
Returns the current window state. Returns the current window state.
} }
@section{Navigation and Content} @section[#:tag "racket-webview-navigation-and-content"]{Navigation and Content}
@defproc[(webview-set-url! [wv wv-win?] [url (or/c string? url?)]) @defproc[(webview-set-url! [wv wv-win?] [url (or/c string? url?)])
symbol?]{ symbol?]{
@@ -176,7 +176,7 @@ The result is the symbol returned by @racket[webview-run-js].
Sets the window title. Sets the window title.
} }
@section{JavaScript} @section[#:tag "racket-webview-javascript"]{JavaScript}
@defproc[(webview-run-js [wv wv-win?] [js string?]) symbol?]{ @defproc[(webview-run-js [wv wv-win?] [js string?]) symbol?]{
Evaluates JavaScript. Evaluates JavaScript.
@@ -196,7 +196,7 @@ structure, an exception is raised.
} }
@section{Dialogs} @section[#:tag "racket-webview-dialogs"]{Dialogs}
Dialog functions return immediately. Results are delivered asynchronously via Dialog functions return immediately. Results are delivered asynchronously via
events. events.
@@ -254,9 +254,9 @@ is indicated through the event.
} }
@section{DOM Interaction} @section[#:tag "racket-webview-dom-interaction"]{DOM Interaction}
@subsection{Selectors and Element Identifiers} @subsection[#:tag "racket-webview-selectors-and-element-identifiers"]{Selectors and Element Identifiers}
Many functions accept either an element identifier or a CSS selector. Many functions accept either an element identifier or a CSS selector.
@@ -272,7 +272,7 @@ If a string is provided, it is used directly as a CSS selector.
Functions apply their effect to all matched elements. Functions apply their effect to all matched elements.
@subsection{Event Binding} @subsection[#:tag "racket-webview-event-binding"]{Event Binding}
@defproc[(webview-bind! @defproc[(webview-bind!
[wv wv-win?] [wv wv-win?]
@@ -300,7 +300,7 @@ Selector handling is the same as for @racket[webview-bind!]. The result is a
list describing the removed bindings. list describing the removed bindings.
} }
@subsection{DOM Values} @subsection[#:tag "racket-webview-dom-values"]{DOM Values}
@defproc[(webview-set-value! @defproc[(webview-set-value!
[wv wv-win?] [wv wv-win?]
@@ -367,7 +367,7 @@ Returns the value converted to a datetime.
Returns the value converted to a color. Returns the value converted to a color.
} }
@subsection{Classes, Styles} @subsection[#:tag "racket-webview-classes-styles"]{Classes, Styles}
@defproc[(webview-add-class! @defproc[(webview-add-class!
[wv wv-win?] [wv wv-win?]
@@ -428,7 +428,7 @@ If @racket[selector] is a symbol, the result for that single element is returned
directly. Otherwise the result covers all matched elements. directly. Otherwise the result covers all matched elements.
} }
@subsection{Attributes} @subsection[#:tag "racket-webview-attributes"]{Attributes}
@defproc[(webview-set-attr! @defproc[(webview-set-attr!
[wv wv-win?] [wv wv-win?]
@@ -517,7 +517,7 @@ Returns the attribute value converted to a datetime.
Returns the attribute value converted to a color. Returns the attribute value converted to a color.
} }
@subsection{Inner HTML} @subsection[#:tag "racket-webview-inner-html"]{Inner HTML}
@defproc[(webview-set-innerHTML! @defproc[(webview-set-innerHTML!
[wv wv-win?] [wv wv-win?]
@@ -531,7 +531,7 @@ Returns @racket['oke] if the injected JavaScript yields a true value, and
@racket['failed] otherwise. @racket['failed] otherwise.
} }
@section{File Filters} @section[#:tag "racket-webview-file-filters"]{File Filters}
@defstruct*[wv-permitted-exts ([name string?] @defstruct*[wv-permitted-exts ([name string?]
[exts (listof symbol?)])]{ [exts (listof symbol?)])]{
@@ -548,7 +548,7 @@ Represents a file dialog filter entry.
Recognizes lists of filter entries. Recognizes lists of filter entries.
} }
@section{Utilities} @section[#:tag "racket-webview-utilities"]{Utilities}
@defproc[(webview-default-boilerplate-js [custom-js procedure?] ...) @defproc[(webview-default-boilerplate-js [custom-js procedure?] ...)
string?]{ string?]{
@@ -576,7 +576,7 @@ If an additional procedure is supplied, its returned string is appended to that
Creates a standard file getter. Creates a standard file getter.
} }
@section{Diagnostics} @section[#:tag "racket-webview-diagnostics"]{Diagnostics}
@defproc[(webview-version) list?]{ @defproc[(webview-version) list?]{
Returns version information. Returns version information.
@@ -589,7 +589,8 @@ Returns runtime information.
@defproc[(webview-set-loglevel [l (or/c 'error 'warning 'info 'debug)]) @defproc[(webview-set-loglevel [l (or/c 'error 'warning 'info 'debug)])
void?]{ void?]{
Sets the native log level. Sets the Qt backend log level.
The native log file path can be obtained via @racket[webview-info]. Backend diagnostics are written to stderr. The destination reported by
@racket[webview-info] is @tt{"stderr"}.
} }
+5 -5
View File
@@ -6,7 +6,7 @@
racket/string racket/string
racket/contract)) racket/contract))
@title{rgba} @title[#:tag "rgba"]{rgba}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/rgba] @defmodule[racket-webview/rgba]
@@ -16,7 +16,7 @@ RGBA color support used by the webview library.
This module exports a transparent @racket[rgba] structure together with This module exports a transparent @racket[rgba] structure together with
predicates and conversion procedures for working with CSS-style color values. predicates and conversion procedures for working with CSS-style color values.
@section{Overview} @section[#:tag "rgba-overview"]{Overview}
An @racket[rgba] value represents a color using red, green, blue, and alpha An @racket[rgba] value represents a color using red, green, blue, and alpha
components. components.
@@ -35,7 +35,7 @@ The intended external representation is the CSS form:
"rgba(r,g,b,a)" "rgba(r,g,b,a)"
] ]
@section{Predicates} @section[#:tag "rgba-predicates"]{Predicates}
@defproc[(rgba/color? [v any/c]) boolean?]{ @defproc[(rgba/color? [v any/c]) boolean?]{
@@ -53,7 +53,7 @@ A valid alpha component is a real number in the range from @racket[0] to
@racket[1], inclusive. @racket[1], inclusive.
} }
@section{Structure Type} @section[#:tag "rgba-structure-type"]{Structure Type}
@defstruct*[rgba ([r rgba/color?] @defstruct*[rgba ([r rgba/color?]
[g rgba/color?] [g rgba/color?]
@@ -68,7 +68,7 @@ components. The field @racket[a] is the alpha component.
The structure is transparent. The structure is transparent.
} }
@section{Conversion} @section[#:tag "rgba-conversion"]{Conversion}
@defproc[(rgba->string [c rgba?]) string?]{ @defproc[(rgba->string [c rgba?]) string?]{
+17 -16
View File
@@ -4,18 +4,19 @@
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@title{C API for Racket Integration} @title[#:tag "rktwebview-api"]{C API for Racket Integration}
This section describes the C API exactly as defined in @tt{rktwebview.h} and This section documents the legacy C API defined in @tt{rktwebview.h} and
@tt{rktwebview_types.h}. The API is used from Racket through FFI, but is @tt{rktwebview_types.h}. The source remains in the backend repository for
documented here in its native C/C++ form. reference and comparison, but the current build no longer exposes this shared
library to Racket. The active integration uses the stdio process protocol.
The interface is deliberately small. Handles are integers, most operations The interface is deliberately small. Handles are integers, most operations
return a @tt{result_t}, and structured values are returned as @tt{rkt_data_t *}. return a @tt{result_t}, and structured values are returned as @tt{rkt_data_t *}.
The latter are caller-owned and must be released with The latter are caller-owned and must be released with
@tt{rkt_webview_free_data()}. @tt{rkt_webview_free_data()}.
@section{Version, Export, and Basic Types} @section[#:tag "rktwebview-api-version-export-and-basic-types"]{Version, Export, and Basic Types}
The public API version is: The public API version is:
@@ -39,7 +40,7 @@ typedef int rkt_wv_context_t;
@tt{rktwebview_t} identifies a webview. @tt{rkt_wv_context_t} identifies a @tt{rktwebview_t} identifies a webview. @tt{rkt_wv_context_t} identifies a
context. context.
@section{Enums and Structured Data} @section[#:tag "rktwebview-api-enums-and-structured-data"]{Enums and Structured Data}
The API defines the following enums: @tt{rkt_webview_loglevel_t}, The API defines the following enums: @tt{rkt_webview_loglevel_t},
@tt{result_t}, @tt{window_state_t}, @tt{rkt_messagetype_t}, and @tt{result_t}, @tt{window_state_t}, @tt{rkt_messagetype_t}, and
@@ -91,7 +92,7 @@ typedef struct {
The @tt{kind} field determines which member of @tt{data} is valid. The @tt{kind} field determines which member of @tt{data} is valid.
@section{Ownership} @section[#:tag "rktwebview-api-ownership"]{Ownership}
Any function returning @tt{rkt_data_t *} returns allocated memory. The caller Any function returning @tt{rkt_data_t *} returns allocated memory. The caller
must release it using: must release it using:
@@ -104,7 +105,7 @@ This applies to values returned by @tt{rkt_webview_info()},
@tt{rkt_webview_version()}, @tt{rkt_webview_get_event()}, and @tt{rkt_webview_version()}, @tt{rkt_webview_get_event()}, and
@tt{rkt_webview_call_js()}. @tt{rkt_webview_call_js()}.
@section{Environment and Runtime Control} @section[#:tag "rktwebview-api-environment-and-runtime-control"]{Environment and Runtime Control}
@defproc[(rkt_webview_env [env_cmds any/c]) void?]{ @defproc[(rkt_webview_env [env_cmds any/c]) void?]{
C signature: C signature:
@@ -184,7 +185,7 @@ Returns a pointer to @tt{rkt_data_t}. The returned object has
Return value: @tt{rkt_data_t *}, caller-owned. Return value: @tt{rkt_data_t *}, caller-owned.
} }
@subsection{Events} @subsection[#:tag "rktwebview-api-events"]{Events}
@defproc[(rkt_webview_events_waiting) exact-integer?]{ @defproc[(rkt_webview_events_waiting) exact-integer?]{
C signature: C signature:
@@ -212,7 +213,7 @@ returned pointer may be null.
Return value: @tt{rkt_data_t *}, caller-owned, or null. Return value: @tt{rkt_data_t *}, caller-owned, or null.
} }
@subsubsection{Event Polling} @subsubsection[#:tag "rktwebview-api-event-polling"]{Event Polling}
Events are retrieved explicitly by polling. In normal use, polling should be Events are retrieved explicitly by polling. In normal use, polling should be
performed regularly; a polling interval of about 10 ms is appropriate. performed regularly; a polling interval of about 10 ms is appropriate.
@@ -221,7 +222,7 @@ This keeps the event queue flowing, allows asynchronous operations such as
dialogs to complete in a timely manner, and avoids the impression that the system dialogs to complete in a timely manner, and avoids the impression that the system
has stalled while the Racket side is simply not looking. has stalled while the Racket side is simply not looking.
@section{Contexts} @section[#:tag "rktwebview-api-contexts"]{Contexts}
@defproc[(rkt_webview_new_context [boilerplate_js string?] @defproc[(rkt_webview_new_context [boilerplate_js string?]
[optional_server_cert_pem string?]) [optional_server_cert_pem string?])
@@ -239,7 +240,7 @@ self-signed certificate.
Return value: @tt{rkt_wv_context_t}. Return value: @tt{rkt_wv_context_t}.
} }
@section{Webviews} @section[#:tag "rktwebview-api-webviews"]{Webviews}
@defproc[(rkt_webview_create [context exact-integer?] @defproc[(rkt_webview_create [context exact-integer?]
[parent exact-integer?]) [parent exact-integer?])
@@ -307,7 +308,7 @@ specified webview.
Return value: none. Return value: none.
} }
@section{Navigation and JavaScript} @section[#:tag "rktwebview-api-navigation-and-javascript"]{Navigation and JavaScript}
@defproc[(rkt_webview_set_url [wv exact-integer?] [url string?]) exact-integer?]{ @defproc[(rkt_webview_set_url [wv exact-integer?] [url string?]) exact-integer?]{
C signature: C signature:
@@ -377,7 +378,7 @@ Opens developer tools for the specified webview.
Return value: @tt{result_t}. Return value: @tt{result_t}.
} }
@section{Window Management} @section[#:tag "rktwebview-api-window-management"]{Window Management}
@defproc[(rkt_webview_move [w exact-integer?] [x exact-integer?] [y exact-integer?]) @defproc[(rkt_webview_move [w exact-integer?] [x exact-integer?] [y exact-integer?])
exact-integer?]{ exact-integer?]{
@@ -491,7 +492,7 @@ Returns the current state of the specified window.
Return value: @tt{window_state_t}. Return value: @tt{window_state_t}.
} }
@section{Dialogs} @section[#:tag "rktwebview-api-dialogs"]{Dialogs}
The dialog functions are asynchronous. They request that the dialog be opened on The dialog functions are asynchronous. They request that the dialog be opened on
the Qt side, but do not block the Racket side while the dialog is shown. This is the Qt side, but do not block the Racket side while the dialog is shown. This is
@@ -574,7 +575,7 @@ reported through events.
Return value: @tt{result_t}. Return value: @tt{result_t}.
} }
@section{Remarks} @section[#:tag "rktwebview-api-remarks"]{Remarks}
The API is queue-based. Commands are issued through function calls; events are The API is queue-based. Commands are issued through function calls; events are
retrieved explicitly using @tt{rkt_webview_events_waiting()} and retrieved explicitly using @tt{rkt_webview_events_waiting()} and
+74 -225
View File
@@ -1,265 +1,114 @@
#lang scribble/manual #lang scribble/manual
@(require racket/runtime-path)
@defmodule{racket-webview/internals} @defmodule{racket-webview/internals}
@title{Qt WebView Backend Architecture} @title[#:tag "rktwebviewqt-internals"]{Qt WebView Backend Architecture}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@section{Introduction} @section[#:tag "rktwebviewqt-internals-overview"]{Overview}
It would, of course, be preferable to place everything within a single process, The runtime consists of two processes. The Racket process owns the public API,
under a unified structure. This would be elegant. It is not how things are. contexts used by the local HTTPS server, handle wrappers, and user callbacks.
The helper process @tt{rktwebview_prg} owns @tt{QApplication}, Qt widgets,
@tt{QWebEngineProfile} objects, and all browser state.
@(define-runtime-path img-path ".") The processes communicate through standard pipes. There is no shared library,
@(define img (path->string (build-path img-path shared-memory queue, or callback from native code into the Racket runtime.
"rktwebview-shared-memory-diagram-simple.svg"
)))
@;@(displayln (format "image: '~a'" img))
@centered{ @section[#:tag "rktwebviewqt-internals-standard-streams"]{Standard Streams}
@image[#:scale 0.45]{@img}
}
Qt WebEngine establishes its own order: threads, event loops, internal state. The streams have fixed roles:
Once set in motion, it does not easily yield. It persists, and it expects its
environment to adapt accordingly. These conditions are accepted.
The Racket process, however, is of a different nature. It is light, precise, @itemlist[#:style 'compact
capable of starting and stopping without residue. It must remain so. @item{child stdin carries commands from Racket}
@item{child stdout carries the handshake, command results, and events}
@item{child stderr carries diagnostic logging}]
So a boundary is drawn. Messages on stdin and stdout are compact UTF-8 JSON objects, one object per
line. Stdout must not contain ordinary logging because the Racket protocol
reader treats every value there as a protocol record.
On one side, Qt: a large, immovable instrument—something like an organ. Once it @section[#:tag "rktwebviewqt-internals-protocol-compatibility"]{Protocol Compatibility}
begins to sound, it fills the space, and it is not easily silenced. On the other,
Racket: a violin, agile and expressive, able to begin and end a phrase at will.
They do not become the same instrument. They are allowed to play together. The command identifiers in @tt{rkt_protocol.h} and the JSON objects used as
Communication is arranged accordingly. A shared memory region, containing three command payloads are unchanged. The process transport adds an outer message
queues: commands, results, and events. A command is issued. It crosses the boundary. It is taken up and executed. A result returns. object with a type and, for commands and results, a request identifier.
Events also arise, independently, and must be handled when they appear.
Within this structure, the violin may move freely—provided it does not attempt to A command has this form:
reconfigure the organ. No attempt is made to unify the instruments. Such efforts would not improve the music. Instead, the composition is written so that each plays its part.
From the outside, one hears only a simple exchange: a call, a response. Internally, the balance is carefully maintained. For now, this is sufficient. And it holds. @verbatim|{{"type":"command","id":17,"command":6,"data":{"wv":1,"url":"https://example.test"}}}|
@section{Overview} A corresponding result has this form:
This backend provides a webview implementation by delegating all GUI and browser @verbatim|{{"type":"result","id":17,"result":0,"data":null}}|
functionality to a separate Qt process.
The embedding Racket process does not manipulate Qt widgets directly. Instead, The request identifier prevents concurrent calls from consuming each other's
it communicates with a helper process that owns the Qt event loop and all results. It is not visible in the public API.
@tt{QWebEngine} objects.
This design exists to work around limitations of Qt WebEngine in combination with @section[#:tag "rktwebviewqt-internals-command-execution"]{Command Execution}
the lifecycle model of the DrRacket environment.
@section{Execution Model} A Racket caller registers a private response channel, writes a command while
holding the transport write lock, and waits on that channel.
The runtime consists of two processes: the embedding Racket process and a helper The Qt process has a command-reader thread. That thread parses stdin records and
process running Qt and Qt WebEngine. calls the existing @tt{Rktwebview_qt} methods. Those methods post commands to the
Qt GUI thread and wait for completion. The command-reader thread then writes the
result record to stdout.
All GUI state lives in the helper process. The embedding side holds no direct The Racket stdout reader is the only thread that reads protocol output. It uses
references to Qt objects. Communication is explicit and happens through shared the request identifier to forward each result to the correct waiting caller.
memory.
@section{Shared Memory and Queues} @section[#:tag "rktwebviewqt-internals-event-delivery"]{Event Delivery}
A shared memory region is created during initialization. Inside that region, Qt events remain the original JSON strings. The Qt callback converts them only
three FIFO queues are established: a command queue, a result queue, and an event into this transport record:
queue.
Each message consists of a numeric code and a payload, typically JSON: @verbatim|{{"type":"event","wv":1,"data":"{...original event JSON...}"}}|
@centerline{@tt{(code, payload)}} The stdout reader captures the callback associated with the handle and places
the callback plus event string on an asynchronous Racket channel. A separate
event thread invokes user callbacks. Therefore a slow user callback cannot block
protocol parsing or prevent command results from being received.
The queues have distinct roles. The @italic{command queue} carries requests from the embedding process to the Qt process, for example creating a window, loading a URL, or executing JavaScript. The @italic{result queue} carries direct replies to those commands. A synchronous call on the embedding side blocks until a corresponding result is available. The @italic{event queue} carries asynchronous notifications generated by the Qt side, such as page load completion, navigation requests, window movement, or events Capturing the callback while the event record is read is important for window
originating from JavaScript. closure. Qt writes the @tt{"closed"} event before the result of the close command.
The handle can be removed immediately after the result reaches its caller, but
the already captured callback still receives the event.
@section{Command Execution} @section[#:tag "rktwebviewqt-internals-contexts-and-handles"]{Contexts and Handles}
A function call on the embedding side is translated into a command and written to A context corresponds to a @tt{QWebEngineProfile} and is identified by an
the command queue. integer. A webview or tray icon is also identified by an integer handle. Only
these numbers cross the process boundary; Qt object pointers never do.
From there the flow is fixed: (1) the command is read by a worker thread in the The existing Racket @tt{rkt-wv} structure is retained so the higher layers do
helper process, (2) it is reposted onto the Qt GUI thread, (3) the GUI thread not need to change.
executes the operation, and (4) the result is written back to the result queue.
The worker thread never manipulates Qt objects. All GUI work happens on the GUI @section[#:tag "rktwebviewqt-internals-lifecycle-and-failure-handling"]{Lifecycle and Failure Handling}
thread.
From the callers perspective, a synchronous call returns only after the GUI The backend writes a protocol-version handshake after initialization. Racket
thread has completed the action. waits for this handshake before sending application commands.
@section{Event Delivery} For normal shutdown, Racket closes open handles, sends the existing quit
command, waits for its result, closes the child's stdin, and waits for the child
process and reader threads.
Many relevant events are not tied to a specific command. Page loading, navigation If Racket terminates unexpectedly, the operating system closes the stdin pipe.
attempts, window movement, and JavaScript-originated events are delivered through The command-reader thread sees EOF, closes all Qt windows, and quits the Qt event
the event queue. loop. This replaces the former shared-memory alive and alive-ack queues.
Events are retrieved explicitly by polling. If stdout closes unexpectedly, Racket marks all handles invalid and delivers an
exception to every command still waiting for a result.
Each event contains a name, an identifier, and optional fields depending on its @section[#:tag "rktwebviewqt-internals-logging"]{Logging}
type. Events are delivered in FIFO order.
@section{Contexts and Webviews} The Qt backend writes its existing log messages to stderr. Racket forwards that
stream to its current error port. The @racket[rkt-webview-info] result reports
@tt{"stderr"} as the backend log destination and retains zero-valued
shared-memory metrics for compatibility with callers that display those fields.
The backend uses a two-level model consisting of contexts and webviews. @section[#:tag "rktwebviewqt-internals-development-override"]{Development Override}
A context represents a browser environment and corresponds to a Setting @tt{RKT_WEBVIEW_PRG} to a backend executable bypasses the installed
@tt{QWebEngineProfile}. It defines how pages run, including injected scripts and optional trust configuration using explicitly trusted self-signed certificates. release directory. This makes it possible to test a newly compiled backend
without repackaging or changing the downloader first.
Each context is identified by an integer handle.
Within a context, one or more webviews can be created. A webview represents a
window containing a browser view. Webviews are also identified by integer
handles.
A webview always belongs to exactly one context. When creating a webview, the
context handle must be provided.
Webviews may optionally have a parent webview. If a parent is specified, the
resulting window is created as a modal child of that parent; otherwise it is
created as a top-level window.
From the Racket side, this means that a context must be created first. That
context handle is then used to create webviews, which are subsequently addressed
through their own handles.
All Qt objects remain internal to the helper process; only these integer handles
cross the process boundary.
@section{JavaScript Bridge}
Each context installs a small JavaScript bridge into every page, allowing
JavaScript code to send structured data to the host via:
@centerline{@tt{window.rkt_send_event(obj)}}
The objects are collected and forwarded to the event queue.
@section{Navigation and Window Behavior}
User actions are not always executed immediately; navigation initiated by the
user may result in a @tt{"navigation-request"} event instead of being followed
automatically, and closing a window may result in a @tt{"can-close?"} event. The
Racket side is expected to decide how to handle these situations.
@section{Design Considerations}
@bold{Qt WebEngine lifecycle.}
Qt WebEngine cannot be safely reinitialized within a single process.
In practice, once a @tt{QApplication} using WebEngine has been started and shut
down, the WebEngine runtime cannot be started again. This is a known and
documented limitation (see for example QTBUG-70519, QTBUG-87460,
QTBUG-145033). The underlying cause is that WebEngine starts internal threads
and resources that are not fully released, even after application shutdown.
Attempts to reinitialize WebEngine in the same process result in undefined
behavior, including crashes, hangs, or inconsistent state.
In the DrRacket environment, where components may be restarted under a
custodian, this makes an in-process design fundamentally unsuitable. Even when
libraries are loaded and unloaded using @tt{#:custodian}, the WebEngine runtime
cannot be reset to a clean state.
By moving Qt and WebEngine into a separate process, this limitation is avoided
entirely: each start of the backend creates a fresh runtime, and terminating the
helper process guarantees that all associated threads and resources are released
by the operating system.
@bold{Event loop and threading.}
Qt requires that GUI operations are performed on the Qt GUI thread.
Instead of attempting to integrate Qts event loop with Racket, the design
isolates Qt completely and runs it in its own process.
Within that process, a worker thread receives commands and forwards them to the
GUI thread using Qts event mechanism (via @tt{postEvent}). The Racket side never
interacts with Qt objects directly.
@bold{Failure isolation.}
Qt WebEngine is a large subsystem with its own internal processes (including the
Chromium-based @tt{QtWebEngineProcess}) and is generally stable in practice.
Running the Qt side in a separate process provides isolation: if the helper
process terminates, the embedding Racket process remains unaffected and can
decide how to recover.
@bold{Shared memory communication.}
The communication pattern consists of commands, results, and events, mapped onto
shared memory FIFO queues, keeping the model simple and explicit.
@bold{JSON encoding.}
All payloads are encoded as JSON, providing a natural bridge between JavaScript,
Qt/C++, and Racket: JavaScript produces JSON natively, Qt maps it to variant
types, and Racket can decode it easily.
For control commands, payload sizes are small and infrequent, so serialization
cost is negligible compared to GUI-thread execution and WebEngine processing; for
dynamic data such as JavaScript results and custom events, JSON is the
appropriate representation. A binary protocol would reduce overhead but increase
complexity and reduce inspectability.
@section{Shared Memory Architecture}
Communication between the Racket process and @tt{rktwebview_prg} is implemented
using a shared memory region. This region serves three purposes at once: it
stores shared data structures, it provides a simple allocator, and it hosts the
FIFO queues used for message passing.
At the start of the shared memory block, a small administration area is stored,
including a pointer to the current end of allocated memory, a list of active
allocations, a free list, and a fixed slot table. The slot table acts as a
directory of shared objects; queues are created once, stored in slots, and can be
retrieved by both processes using only the slot number.
Memory allocation inside the shared block is intentionally simple. Each
allocation is preceded by a small header containing size information and links
for a double-linked list. Allocation first attempts to reuse a block from the
free list; if no suitable block is available, memory is taken from the unused
tail of the region. Freed blocks are returned to the free list and may later be
reused. Blocks are not compacted or coalesced. This is not a general-purpose
heap; it is a small, predictable allocator for queue items and payload strings.
Shared objects are referenced primarily through offsets (via @tt{ShmPlace})
rather than raw pointers. This makes the layout independent of the virtual
address at which the shared memory is mapped in each process.
Queues are built directly on top of this allocator. Each queue consists of a
small header containing the first item, the last item, and a count, followed by a
linked list of queue items. Each item stores a numeric command or event code, a
pointer to its payload in shared memory, and links to neighboring items.
Synchronization is split into two layers. A shared lock protects allocator and
queue metadata, while each queue has its own semaphore indicating whether items
are available. One mechanism protects the structure; the other tells you whether
there is anything worth reading.
On POSIX systems such as Linux, shared memory is implemented using
@tt{shm_open}, @tt{ftruncate}, and @tt{mmap}, with synchronization via named
POSIX semaphores created using @tt{sem_open}. The owner process initializes these
objects and removes them again using @tt{shm_unlink} and @tt{sem_unlink}.
On Windows, the same model is implemented using @tt{CreateFileMappingA} and
@tt{MapViewOfFile} for shared memory, and @tt{CreateSemaphoreA} or
@tt{OpenSemaphoreA} for synchronization. The design is identical, but the kernel
objects follow the Windows lifetime model and are released when the last handle
is closed.
The shared memory region has a fixed size (currently 10MB) and is not resized at
runtime. Although the use of @tt{ShmPlace} offsets would in principle allow
relocation, resizing would require coordinated remapping in both processes while
all activity is paused. The current design therefore treats the region as
fixed-size and relies on reuse of freed blocks.
This implies that the communication channel is bounded. Payloads such as
@tt{set_html} or large JavaScript results must fit within the available free
space in the shared memory block. In practice, the usable limit is somewhat below
the nominal 10MB due to allocator overhead, queue administration, and concurrent
messages.
This is a message transport, not an infinite sack of HTML.
+2 -2
View File
@@ -10,12 +10,12 @@
"../wv-context.rkt" "../wv-context.rkt"
)) ))
@title{wv-context} @title[#:tag "wv-context"]{wv-context}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/wv-context] @defmodule[racket-webview/wv-context]
@section{Overview} @section[#:tag "wv-context-overview"]{Overview}
The library is organized around two main concepts: contexts and windows. The library is organized around two main concepts: contexts and windows.
+10 -8
View File
@@ -8,7 +8,7 @@
"../wv-dialog.rkt" "../wv-dialog.rkt"
"../wv-window.rkt")) "../wv-window.rkt"))
@title{wv-dialog} @title[#:tag "wv-dialog"]{wv-dialog}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/wv-dialog] @defmodule[racket-webview/wv-dialog]
@@ -16,18 +16,18 @@
Dialog-window wrapper built on top of @racket[wv-window%]. Dialog-window wrapper built on top of @racket[wv-window%].
This module exports the @racket[wv-dialog%] class. It is a specialized window This module exports the @racket[wv-dialog%] class. It is a specialized window
class whose initial size and position are derived from its parent window. class whose initial size and position are derived from its parent window. Closing a dialog does not quit the application by default.
@section{Overview} @section[#:tag "wv-dialog-overview"]{Overview}
A @racket[wv-dialog%] object is a @racket[wv-window%] that initializes itself as A @racket[wv-dialog%] object is a @racket[wv-window%] that initializes itself as
a dialog relative to its parent window. a dialog relative to its parent window.
The class inherits the window lifecycle, event handling, navigation, and dialog The class inherits the window lifecycle, event handling, navigation, and dialog
support from @racket[wv-window%]. Its only specialization in the current source support from @racket[wv-window%]. Its only specialization in the current source
is the implementation of @racket[init-size]. is the implementation of @racket[init-size]. A dialog also changes the inherited @racket[quit-on-close] default to @racket[#f].
@section{Class: wv-dialog%} @section[#:tag "wv-dialog-class-wv-dialog"]{Class: wv-dialog%}
@defclass[wv-dialog% wv-window% ()]{ @defclass[wv-dialog% wv-window% ()]{
@@ -37,12 +37,14 @@ The class inherits the fields @racket[parent], @racket[settings],
@racket[wv-context], @racket[html-path], @racket[x], @racket[y], @racket[wv-context], @racket[html-path], @racket[x], @racket[y],
@racket[width], and @racket[height] from @racket[wv-window%]. @racket[width], and @racket[height] from @racket[wv-window%].
@defconstructor[()]{ @defconstructor[([quit-on-close any/c #f])]{
Creates a dialog window. Creates a dialog window.
The constructor does not define additional initialization arguments of its own. The inherited @racket[quit-on-close] initialization argument defaults to
Construction is delegated to @racket[wv-window%] through @racket[super-new]. @racket[#f] for dialogs. Closing a dialog therefore closes only that dialog and
does not release @racket[webview-wait-for-quit]. Pass @racket[#t] explicitly
only when closing this dialog should terminate the application.
} }
@defmethod[(init-size) any/c]{ @defmethod[(init-size) any/c]{
+3 -3
View File
@@ -10,7 +10,7 @@
"../racket-webview.rkt" "../racket-webview.rkt"
"../wv-element.rkt")) "../wv-element.rkt"))
@title{wv-element} @title[#:tag "wv-element"]{wv-element}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/wv-element] @defmodule[racket-webview/wv-element]
@@ -22,7 +22,7 @@ represent one DOM element within a @racket[wv-window%] and provide a small
object-oriented interface for event dispatch, content replacement, CSS class object-oriented interface for event dispatch, content replacement, CSS class
manipulation, style access, and attribute access. manipulation, style access, and attribute access.
@section{Overview} @section[#:tag "wv-element-overview"]{Overview}
A @racket[wv-element%] object is associated with: A @racket[wv-element%] object is associated with:
@@ -37,7 +37,7 @@ of its methods therefore follow the contracts of those lower-level functions.
The class also stores per-element event callbacks used by @racket[wv-window%] The class also stores per-element event callbacks used by @racket[wv-window%]
when dispatching JavaScript events received from the browser. when dispatching JavaScript events received from the browser.
@section{Class: wv-element%} @section[#:tag "wv-element-class-wv-element"]{Class: wv-element%}
@defclass[wv-element% object% ()]{ @defclass[wv-element% object% ()]{
+13 -13
View File
@@ -11,7 +11,7 @@
"../wv-input.rkt" "../wv-input.rkt"
"../rgba.rkt")) "../rgba.rkt"))
@title{wv-input} @title[#:tag "wv-input"]{wv-input}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/wv-input] @defmodule[racket-webview/wv-input]
@@ -22,7 +22,7 @@ This module exports a family of classes derived from @racket[wv-element%]. Each
class represents one DOM input element and provides a typed @racket[get] method class represents one DOM input element and provides a typed @racket[get] method
together with a @racket[set!] method. together with a @racket[set!] method.
@section{Overview} @section[#:tag "wv-input-overview"]{Overview}
All classes in this module inherit from @racket[wv-element%]. All classes in this module inherit from @racket[wv-element%].
@@ -39,7 +39,7 @@ lower-level DOM/value API from @racketmodname[racket-webview]. Their accepted
argument shapes and result values therefore follow the contracts of those argument shapes and result values therefore follow the contracts of those
lower-level functions. lower-level functions.
@section{Common Structure} @section[#:tag "wv-input-common-structure"]{Common Structure}
All input wrapper classes have the same constructor shape: All input wrapper classes have the same constructor shape:
@@ -56,7 +56,7 @@ Each class provides two public methods:
@item{@racket[get], returning the current typed value} @item{@racket[get], returning the current typed value}
@item{@racket[set!], writing a new value through @racket[webview-set-value!]}] @item{@racket[set!], writing a new value through @racket[webview-set-value!]}]
@section{Class: wv-input/text%} @section[#:tag "wv-input-class-wv-input-text"]{Class: wv-input/text%}
@defclass[wv-input/text% wv-element% ()]{ @defclass[wv-input/text% wv-element% ()]{
@@ -89,7 +89,7 @@ Writes @racket[v] by delegating to:
} }
} }
@section{Class: wv-input/number%} @section[#:tag "wv-input-class-wv-input-number"]{Class: wv-input/number%}
@defclass[wv-input/number% wv-element% ()]{ @defclass[wv-input/number% wv-element% ()]{
@@ -122,7 +122,7 @@ Writes @racket[v] by delegating to:
} }
} }
@section{Class: wv-input/boolean%} @section[#:tag "wv-input-class-wv-input-boolean"]{Class: wv-input/boolean%}
@defclass[wv-input/boolean% wv-element% ()]{ @defclass[wv-input/boolean% wv-element% ()]{
@@ -155,7 +155,7 @@ Writes @racket[v] by delegating to:
} }
} }
@section{Class: wv-input/date%} @section[#:tag "wv-input-class-wv-input-date"]{Class: wv-input/date%}
@defclass[wv-input/date% wv-element% ()]{ @defclass[wv-input/date% wv-element% ()]{
@@ -188,7 +188,7 @@ Writes @racket[v] by delegating to:
} }
} }
@section{Class: wv-input/time%} @section[#:tag "wv-input-class-wv-input-time"]{Class: wv-input/time%}
@defclass[wv-input/time% wv-element% ()]{ @defclass[wv-input/time% wv-element% ()]{
@@ -221,7 +221,7 @@ Writes @racket[v] by delegating to:
} }
} }
@section{Class: wv-input/datetime%} @section[#:tag "wv-input-class-wv-input-datetime"]{Class: wv-input/datetime%}
@defclass[wv-input/datetime% wv-element% ()]{ @defclass[wv-input/datetime% wv-element% ()]{
@@ -254,7 +254,7 @@ Writes @racket[v] by delegating to:
} }
} }
@section{Class: wv-input/range%} @section[#:tag "wv-input-class-wv-input-range"]{Class: wv-input/range%}
@defclass[wv-input/range% wv-element% ()]{ @defclass[wv-input/range% wv-element% ()]{
@@ -287,7 +287,7 @@ Writes @racket[v] by delegating to:
} }
} }
@section{Class: wv-input/check%} @section[#:tag "wv-input-class-wv-input-check"]{Class: wv-input/check%}
@defclass[wv-input/check% wv-element% ()]{ @defclass[wv-input/check% wv-element% ()]{
@@ -320,7 +320,7 @@ Writes @racket[v] by delegating to:
} }
} }
@section{Class: wv-input/radio%} @section[#:tag "wv-input-class-wv-input-radio"]{Class: wv-input/radio%}
@defclass[wv-input/radio% wv-element% ()]{ @defclass[wv-input/radio% wv-element% ()]{
@@ -353,7 +353,7 @@ Writes @racket[v] by delegating to:
} }
} }
@section{Class: wv-input/color%} @section[#:tag "wv-input-class-wv-input-color"]{Class: wv-input/color%}
@defclass[wv-input/color% wv-element% ()]{ @defclass[wv-input/color% wv-element% ()]{
+3 -3
View File
@@ -9,7 +9,7 @@
racket/file racket/file
"../wv-settings.rkt")) "../wv-settings.rkt"))
@title{wv-settings} @title[#:tag "wv-settings"]{wv-settings}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/wv-settings] @defmodule[racket-webview/wv-settings]
@@ -20,7 +20,7 @@ This module exports the @racket[wv-settings%] class, which provides a small
object-oriented interface over an @racket[ini] settings backend. Settings are object-oriented interface over an @racket[ini] settings backend. Settings are
accessed relative to a context. accessed relative to a context.
@section{Overview} @section[#:tag "wv-settings-overview"]{Overview}
A @racket[wv-settings%] object combines: A @racket[wv-settings%] object combines:
@@ -30,7 +30,7 @@ A @racket[wv-settings%] object combines:
Keys used in this class are symbols. Keys used in this class are symbols.
@section{Class: wv-settings%} @section[#:tag "wv-settings-class-wv-settings"]{Class: wv-settings%}
@defclass[wv-settings% object% ()]{ @defclass[wv-settings% object% ()]{
+1 -1
View File
@@ -6,7 +6,7 @@
"../wv-tray.rkt" "../wv-tray.rkt"
"../menu.rkt")) "../menu.rkt"))
@title{Tray Icons} @title[#:tag "wv-tray"]{Tray Icons}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
+6 -6
View File
@@ -15,7 +15,7 @@
"../rgba.rkt" "../rgba.rkt"
"../wv-window.rkt")) "../wv-window.rkt"))
@title{wv-window} @title[#:tag "wv-window"]{wv-window}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-webview/wv-window] @defmodule[racket-webview/wv-window]
@@ -26,7 +26,7 @@ This module exports the @racket[wv-window%] class and re-exports the APIs from
@racketmodname[wv-element], @racketmodname[wv-input], @racketmodname[rgba], and @racketmodname[wv-element], @racketmodname[wv-input], @racketmodname[rgba], and
@racketmodname[wv-settings]. @racketmodname[wv-settings].
@section{Overview} @section[#:tag "wv-window-overview"]{Overview}
A @racket[wv-window%] object represents one webview window. A @racket[wv-window%] object represents one webview window.
@@ -37,7 +37,7 @@ element wrappers through @racket[element].
The class also provides synchronous wrappers around the asynchronous dialog The class also provides synchronous wrappers around the asynchronous dialog
interface by using continuations internally. interface by using continuations internally.
@section{Class: wv-window%} @section[#:tag "wv-window-class-wv-window"]{Class: wv-window%}
@defclass[wv-window% object% ()]{ @defclass[wv-window% object% ()]{
@@ -478,7 +478,7 @@ The resulting geometry is then applied through @racket[move] and @racket[resize]
} }
} }
@section{Events} @section[#:tag "wv-window-events"]{Events}
The window installs an internal event handler when it is created. The window installs an internal event handler when it is created.
@@ -499,7 +499,7 @@ This handler reacts to the following event kinds produced by the lower layer:
Unhandled events are printed to the console by the current implementation. Unhandled events are printed to the console by the current implementation.
@section{Function: root-file-not-found-handler} @section[#:tag "wv-window-function-root-file-not-found-handler"]{Function: root-file-not-found-handler}
@defproc[(root-file-not-found-handler [standard-file string?] @defproc[(root-file-not-found-handler [standard-file string?]
[not-found-handler procedure?] ...) [not-found-handler procedure?] ...)
@@ -527,7 +527,7 @@ Its behavior is as follows:
Only the first optional @racket[not-found-handler] is used. Only the first optional @racket[not-found-handler] is used.
} }
@section{Re-exports} @section[#:tag "wv-window-re-exports"]{Re-exports}
This module also re-exports the public APIs from: This module also re-exports the public APIs from:
+2 -1
View File
@@ -14,9 +14,10 @@
(define wv-dialog% (define wv-dialog%
(class wv-window% (class wv-window%
(init [quit-on-close #f])
(inherit-field parent settings wv-context html-path x y width height) (inherit-field parent settings wv-context html-path x y width height)
(super-new) (super-new [quit-on-close quit-on-close])
(define/override (init-size) (define/override (init-size)
(dbg-webview "init-size") (dbg-webview "init-size")
+11 -1
View File
@@ -7,6 +7,8 @@
(provide wv-element%) (provide wv-element%)
(define displ display)
(define wv-element% (define wv-element%
(class object% (class object%
(init-field window (init-field window
@@ -50,7 +52,15 @@
(when (not (null? d)) (when (not (null? d))
(let ((d* (string->symbol (format "~a" (car d))))) (let ((d* (string->symbol (format "~a" (car d)))))
(webview-set-style! wv element-id (list 'display d*)))) (webview-set-style! wv element-id (list 'display d*))))
(string->symbol (hash-ref (webview-get-style wv element-id 'display) 'display))) (let ((style-hash (webview-get-style wv element-id 'display)))
;(displ "style-hash: ") (write style-hash) (newline)
(let ((display-style (hash-ref (if (eq? style-hash #f)
(make-hash)
style-hash) 'display #f)))
;(displayln display-style)
(if (eq? display-style #f)
#f
(string->symbol display-style)))))
(define/public (visibility . v) (define/public (visibility . v)
(when (not (null? v)) (when (not (null? v))