fpwebview embedded in Lazarus GUI

22 Nov 2022

Lazarus is an IDE-cum-widget set interface for developing cross platform GUI applications. I've now implemented a demo of using fpwebview with Lazarus, i.e., embedding webview in a desktop Lazarus GUI application.

Here's a macOS screenshot:

fpwebview embedded in Lazarus Cocoa app demo

In the screenshot, the three buttons above the web content are outside of the webview display area, and are Lazarus components making up the GUI application. The 'Say Yo To Webview' button demonstrates updating content shown by webview in response to GUI action, while the 'Lazarus Say Hello' button demonstrates standard GUI functionality.

Technically, this application demonstrates concurrent execution of the Lazarus GUI event loop managing the application's windows, and webview's own event loop that manages the Lazarus window in which webview is embedded.

The demo works on macOS (using Lazarus Cocoa widget set) and Windows (using Lazarus Windows widget set).

For Linux:

  • with Lazarus GTK2: Impossible, as GTK2 and GTK3 (which webview on Linux uses) cannot coexist in one application (that executes as one operating system process).

  • with Lazarus GTK3: Should be trivial. Note that at present Lazarus GTK3 is work-in-progress and not mature.

  • with Lazarus Qt5/Qt6: Possible, potentially tricky. The basic requirement is to convert a Qt window handle into a GTK3 window suitable for use with webview.

Tags: fpwebview, Pascal

fpwebview Embedded Web Server

17 Feb 2022

I've implemented an embedded localhost web server demo for fpwebview. The demo runs on Linux macOS, and Windows 10. Here's a Linux screenshot:

fpwebview Embedded Server Demo

The program consists of a multi-threaded web server listening on localhost:8000, and the web browser widget showing the content, styled by CSS, all loaded from said web server.

Because the embedded web server is listening on localhost:8000, you could visit it with a regular web browser running on the same machine. However, in the demo program, the buttons work by using webview APIs to perform what is effectively in-process RPC between Javascript and Pascal. From a regular web browser, clicking those buttons will have no effect, since the browser's Javascript runtime has nothing to do with the Pascal procedures implementing the buttons' functionalities.

For serious usage beyond a demo, additional security measures are possible to ensure that the embedded web server serves only the web browser widget and no other client.

Tags: fpwebview, Pascal

fpwebview Bidirectional Javascript-Pascal Calling

16 Feb 2022

I've implemented bidirectional Javascript-Pascal calling for fpwebview. Here's the demo program:

program js_bidir;

{$linklib libwebview}

{$mode objfpc}{$H+}

uses
  {$ifdef unix}cthreads,{$endif}
  math,
  webview;

var
  w: PWebView;
  html: String;

procedure SayHello(const seq: PAnsiChar; const req: PAnsiChar; arg: Pointer); cdecl;
var
  s: String;
begin
  s := 'var p = document.createElement("p")' + LineEnding +
    'p.innerHTML = "Yo again!"' + LineEnding +
    'document.body.appendChild(p)';
  webview_eval(w, PAnsiChar(s));
  webview_return(w, seq, WebView_Return_Ok, '{result: "<p>Yo!</p>"}');
end;

begin
  { Set math masks. libwebview throws at least one of these from somewhere deep inside. }
  SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);

  html := 'data:text/html,<html>' + LineEnding +
    '<head></head>' + LineEnding +
    '<body><button onClick="SayHello()">Say Hello</button>' + LineEnding +
    '<div id="greeting"></div>' + LineEnding +
    '<script>var SayHello = function() {' + LineEnding +
    '  HostSayHello().then((x) => document.getElementById("greeting").innerHTML = x.result)' + LineEnding +
    '}</script>' + LineEnding +
    '</body>' + LineEnding +
    '</html>';

  w := webview_create(WebView_DevTools, nil);
  webview_set_size(w, 700, 200, WebView_Hint_None);
  webview_set_title(w, PAnsiChar('WebView - Pascal Javascript Bidirectional'));
  webview_bind(w, PAnsiChar('HostSayHello'), @SayHello, nil);
  webview_navigate(w, PAnsiChar(html));
  webview_run(w);
  webview_destroy(w);
end.

In the program, the Pascal procedure SayHello is made accessible to Javascript as HostSayHello. When Javascript calls HostSayHello, the Pascal code in turns invokes Javascript to update the DOM, then returns a response to the Javascript caller.

Next up, an embedded web server to serve HTML, CSS and other content including Javascript source.

Tags: fpwebview, Pascal

fpwebview - webview in Pascal

14 Feb 2022

Webview is a "tiny cross-platform webview library for C/C++/Golang to build modern cross-platform GUIs." Webview uses Cocoa/WebKit on macOS, gtk-webkit2 on Linux, and Edge on Windows 10.

There exist various language bindings for Webview, as listed on Webview's Github page. I've just published my Free Pascal binding here.

Here's a simple Pascal program that uses Webview to implement a web browser.

program browser_cli;

{$linklib libwebview}

uses
  {$ifdef unix}cthreads,{$endif}
  math,
  webview;

var
  w: PWebView;

begin
  { Set math masks. libwebview throws at least one of these from somewhere deep inside. }
  SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);

  writeln('Hello, webview, from Pascal!');
  w := webview_create(WebView_DevTools, nil);
  webview_set_size(w, 1024, 768, WebView_Hint_None);
  webview_set_title(w, PAnsiChar('WebView Free Pascal'));
  webview_navigate(w, PAnsiChar('https://www.freepascal.org/'));
  webview_run(w);
  webview_destroy(w);
  writeln('Goodbye, webview.');
end.

Coincidentally, Toma┼ż Turk recently announced Pharo-WebView.

Tags: fpwebview, Pascal