<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:base="en">
	<title>Kate Lee | WebKit Engineering</title>
	<subtitle>Igalia WebKit Engineering Blog.</subtitle>
	<link href="https://blogs.igalia.com/klee/feed/feed.xml" rel="self"/>
	<link href="https://blogs.igalia.com/klee/"/>
	<updated>2026-03-16T00:00:00Z</updated>
	<id>https://blogs.igalia.com</id>
	<author>
		<name>Kate Lee</name>
		<email>klee@igalia.com</email>
	</author>
	
	<entry>
		<title>Building a Custom HTML Context Menu with the New WPEPlatform API</title>
		<link href="https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/"/>
		<updated>2026-03-16T00:00:00Z</updated>
		<id>https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;https://wpewebkit.org/&quot;&gt;WPE WebKit&lt;/a&gt; is a WebKit port optimized for embedded devices — think set-top boxes, digital signage, kiosk displays, and in-vehicle infotainment systems. It is developed by &lt;a href=&quot;https://www.igalia.com/&quot;&gt;Igalia&lt;/a&gt; and powers web experiences on millions of devices worldwide, from set-top boxes to smart TVs and beyond.&lt;/p&gt;
&lt;p&gt;WPE WebKit has recently introduced a &lt;strong&gt;brand-new platform API called WPEPlatform&lt;/strong&gt;, which replaces the legacy &lt;code&gt;libwpe&lt;/code&gt; + &lt;code&gt;wpebackend-fdo&lt;/code&gt; stack. In this post, I will walk you through building a minimal WPE browser launcher using &lt;strong&gt;only the new WPEPlatform API&lt;/strong&gt;, and demonstrate one of its newly available features: the &lt;strong&gt;Context Menu API&lt;/strong&gt; — rendered entirely as an HTML overlay.&lt;/p&gt;
&lt;h2 id=&quot;why-a-new-api&quot; tabindex=&quot;-1&quot;&gt;Why a New API? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The legacy stack (&lt;code&gt;libwpe&lt;/code&gt; + &lt;code&gt;wpebackend-fdo&lt;/code&gt; + Cog platform plugins) had several pain points: nested Wayland compositor complexity, dependency on Mesa’s now-deprecated &lt;code&gt;EGL_WL_bind_wayland_display&lt;/code&gt; extension, rigid C function-pointer tables, and platform code scattered across three libraries.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;new WPEPlatform API&lt;/strong&gt; replaces all of this with a single, clean &lt;a href=&quot;https://docs.gtk.org/gobject/&quot;&gt;GObject&lt;/a&gt;-based layer — providing automatic backend creation, DMA-BUF direct buffer sharing, unified window management (fullscreen, maximize, resize, title), and easy language bindings via GObject Introspection.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Timeline&lt;/strong&gt;: The stable release of WPEPlatform is planned for &lt;strong&gt;September 2026&lt;/strong&gt;. At that point, the legacy API will be officially deprecated. We strongly recommend new projects to adopt the WPEPlatform API from the start.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;wpeplatform-launcher-a-minimal-browser-in-250-lines&quot; tabindex=&quot;-1&quot;&gt;WPEPlatform Launcher: A Minimal Browser in ~250 Lines &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To demonstrate the new API, I built &lt;strong&gt;WPEPlatformLauncher&lt;/strong&gt; — a minimal but functional WPE WebKit browser that uses only the WPEPlatform API. No legacy &lt;code&gt;libwpe&lt;/code&gt;, no &lt;code&gt;wpebackend-fdo&lt;/code&gt;, no Cog — just the new API.&lt;/p&gt;
&lt;p&gt;The full source code is available at:
&lt;strong&gt;&lt;a href=&quot;https://github.com/kate-k-lee/WebKit/commit/aed6402b267475f79ae7a8d417d18239b53be651&quot;&gt;kate-k-lee/WebKit@aed6402&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;how-simple-is-it&quot; tabindex=&quot;-1&quot;&gt;How Simple Is It? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here is the core of the launcher — creating a WebView with the new API:&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* WPEPlatform backend is created automatically — no manual setup needed */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; webView &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;WEBKIT_WEB_VIEW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;g_object_new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WEBKIT_TYPE_WEB_VIEW&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;web-context&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; webContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;network-session&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; networkSession&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;settings&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; settings&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;user-content-manager&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userContentManager&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;/* Get the WPEPlatform view — this is where the new API shines */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; wpeView &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;webkit_web_view_get_wpe_view&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;webView&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; toplevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wpe_view_get_toplevel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wpeView&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;/* Window management: fullscreen, resize, title — all built-in */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;wpe_toplevel_fullscreen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toplevel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;wpe_toplevel_resize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toplevel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1920&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1080&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;wpe_toplevel_set_title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toplevel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;WPEPlatform Launcher&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;/* Input events: just connect a GObject signal */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;g_signal_connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wpeView&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;event&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;G_CALLBACK&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;onViewEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; webView&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compare this with the legacy API, which required:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Manually creating a &lt;code&gt;WPEToolingBackends::ViewBackend&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Wrapping it in a &lt;code&gt;WebKitWebViewBackend&lt;/code&gt; with a destroy callback&lt;/li&gt;
&lt;li&gt;Creating a C++ &lt;code&gt;InputClient&lt;/code&gt; class and registering it&lt;/li&gt;
&lt;li&gt;Having no window management (no maximize, minimize, title, etc.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The new API handles backend creation, display detection, and input forwarding automatically.&lt;/p&gt;
&lt;h3 id=&quot;keyboard-shortcuts&quot; tabindex=&quot;-1&quot;&gt;Keyboard Shortcuts &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Handling keyboard events is straightforward with the WPEPlatform event system:&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; gboolean &lt;span class=&quot;token function&quot;&gt;onViewEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WPEView&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; view&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WPEEvent&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WebKitWebView&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; webView&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wpe_event_get_event_type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; WPE_EVENT_KEYBOARD_KEY_DOWN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; modifiers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wpe_event_get_modifiers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; keyval &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wpe_event_keyboard_get_keyval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/* Ctrl+Q: Quit */&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;modifiers &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; WPE_MODIFIER_KEYBOARD_CONTROL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; keyval &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; WPE_KEY_q&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token function&quot;&gt;g_application_quit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;g_application_get_default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/* F11: Toggle fullscreen via WPEToplevel */&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;keyval &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; WPE_KEY_F11&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; toplevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wpe_view_get_toplevel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wpe_toplevel_get_state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toplevel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; WPE_TOPLEVEL_STATE_FULLSCREEN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token function&quot;&gt;wpe_toplevel_unfullscreen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toplevel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token function&quot;&gt;wpe_toplevel_fullscreen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toplevel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;html-based-context-menu-solving-the-no-native-ui-challenge&quot; tabindex=&quot;-1&quot;&gt;HTML-Based Context Menu: Solving the “No Native UI” Challenge &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WPE WebKit is designed for embedded environments where there is &lt;strong&gt;no native UI toolkit&lt;/strong&gt; — no GTK, no Qt. This means features like context menus (right-click menus) that desktop browsers take for granted need to be implemented by the application.&lt;/p&gt;
&lt;p&gt;The approach: &lt;strong&gt;intercept WebKit’s &lt;code&gt;context-menu&lt;/code&gt; signal, read the menu items, and render them as an HTML/CSS overlay&lt;/strong&gt; injected into the page DOM.&lt;/p&gt;
&lt;h3 id=&quot;the-architecture&quot; tabindex=&quot;-1&quot;&gt;The Architecture &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;User right-clicks
  → WebKit emits &amp;quot;context-menu&amp;quot; signal
  → onContextMenu() handler:
      1. Reads menu items via webkit_context_menu_get_items()
      2. Gets position via webkit_context_menu_get_position()
      3. Builds JavaScript that creates DOM elements
      4. Injects via webkit_web_view_evaluate_javascript()
      5. Returns TRUE (suppresses default menu)

User clicks a menu item
  → JS: window.webkit.messageHandlers.contextMenuAction.postMessage(actionId)
  → C: onContextMenuAction() receives the action ID
      → Executes: webkit_web_view_go_back(), execute_editing_command(&amp;quot;Copy&amp;quot;), etc.

User clicks outside the menu
  → JS: overlay click handler removes the DOM elements
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;reading-context-menu-items&quot; tabindex=&quot;-1&quot;&gt;Reading Context Menu Items &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Context Menu API provides everything we need:&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; gboolean &lt;span class=&quot;token function&quot;&gt;onContextMenu&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WebKitWebView&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; webView&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    WebKitContextMenu&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; contextMenu&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; gpointer &lt;span class=&quot;token comment&quot;&gt;/* event */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    WebKitHitTestResult&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; hitTestResult&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; gpointer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/* Save hit test result for link-related actions */&lt;/span&gt;&lt;br&gt;    savedHitTestResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;WEBKIT_HIT_TEST_RESULT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;g_object_ref&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hitTestResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/* Iterate through menu items */&lt;/span&gt;&lt;br&gt;    GList&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; items &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;webkit_context_menu_get_items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;contextMenu&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;GList&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; l &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; l&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; l &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; l&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;next&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; item &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;WEBKIT_CONTEXT_MENU_ITEM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;l&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;webkit_context_menu_item_is_separator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token comment&quot;&gt;/* Render as a horizontal line */&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token keyword&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; title &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;webkit_context_menu_item_get_title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; action &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;webkit_context_menu_item_get_stock_action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;/* Build HTML element with title and action ID */&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/* Get position for menu placement */&lt;/span&gt;&lt;br&gt;    gint posX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; posY &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;webkit_context_menu_get_position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;contextMenu&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;posX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;posY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* Suppress default menu */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-html-menu-dark-theme-for-embedded&quot; tabindex=&quot;-1&quot;&gt;The HTML Menu: Dark Theme for Embedded &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The context menu is rendered with a dark theme CSS, designed for embedded/kiosk displays:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;#__wpe_ctx_menu&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fixed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 180px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #2b2b2b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px solid #505050&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 6px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 8px 24px &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0.4&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; system-ui&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sans-serif&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 13px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #e0e0e0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token selector&quot;&gt;.__wpe_ctx_item:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #0060df&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #ffffff&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;handling-actions-via-script-message-handler&quot; tabindex=&quot;-1&quot;&gt;Handling Actions via Script Message Handler &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Communication between the HTML menu and the C application uses WebKit’s script message handler mechanism:&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Register message handler */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; ucm &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;webkit_user_content_manager_new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;webkit_user_content_manager_register_script_message_handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;    ucm&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;contextMenuAction&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;g_signal_connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ucm&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;script-message-received::contextMenuAction&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;G_CALLBACK&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;onContextMenuAction&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// In the generated HTML menu item:&lt;/span&gt;&lt;br&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;webkit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;messageHandlers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contextMenuAction&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;postMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;actionId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Handle the action in C */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;onContextMenuAction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WebKitUserContentManager&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; JSCValue&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; gpointer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; actionId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;jsc_value_to_int32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;actionId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WEBKIT_CONTEXT_MENU_ACTION_RELOAD&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token function&quot;&gt;webkit_web_view_reload&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;webView&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WEBKIT_CONTEXT_MENU_ACTION_COPY&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token function&quot;&gt;webkit_web_view_execute_editing_command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;webView&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Copy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token function&quot;&gt;webkit_web_view_load_uri&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;webView&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token function&quot;&gt;webkit_hit_test_result_get_link_uri&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;savedHitTestResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/* ... more actions ... */&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;demo&quot; tabindex=&quot;-1&quot;&gt;Demo &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is the WPEPlatformLauncher in action, showing the HTML context menu with various actions:&lt;/p&gt;
&lt;img src=&quot;https://blogs.igalia.com/klee/blog/wpeplatform-launcher-context-menu/context-menu-demo.gif&quot; alt=&quot;WPEPlatformLauncher context menu demo&quot; style=&quot;max-width:100%;&quot;&gt;
&lt;p&gt;&lt;em&gt;Right-clicking shows the HTML context menu. Clicking “Reload” triggers an actual page reload.&lt;/em&gt;&lt;/p&gt;
&lt;img src=&quot;https://blogs.igalia.com/klee/blog/wpeplatform-launcher-context-menu/context-menu-link-demo.gif&quot; alt=&quot;Context menu on a link&quot; style=&quot;max-width:100%;&quot;&gt;
&lt;p&gt;&lt;em&gt;Right-clicking a link shows link-specific actions like “Open Link” and “Copy Link Address”.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;building-and-running&quot; tabindex=&quot;-1&quot;&gt;Building and Running &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I built and ran the WPEPlatformLauncher inside a container using the &lt;a href=&quot;https://github.com/Igalia/webkit-container-sdk&quot;&gt;WebKit Container SDK&lt;/a&gt;, which provides a pre-configured development environment with all the dependencies needed to build WPE WebKit.&lt;/p&gt;
&lt;p&gt;The WPEPlatformLauncher integrates into the WebKit build system:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Build WPE WebKit with the launcher&lt;/span&gt;&lt;br&gt;Tools/Scripts/build-webkit &lt;span class=&quot;token parameter variable&quot;&gt;--wpe&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--release&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;# Run&lt;/span&gt;&lt;br&gt;./WebKitBuild/WPE/Release/bin/WPEPlatformLauncher https://wpewebkit.org&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;# Run in fullscreen (kiosk mode)&lt;/span&gt;&lt;br&gt;./WebKitBuild/WPE/Release/bin/WPEPlatformLauncher &lt;span class=&quot;token parameter variable&quot;&gt;--fullscreen&lt;/span&gt; https://your-app.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The full source is a single &lt;code&gt;main.cpp&lt;/code&gt; file (~600 lines including the context menu), integrated into the WebKit tree alongside MiniBrowser:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WebKit/Tools/
├── MiniBrowser/wpe/          ← Existing (supports both old + new API)
├── WPEPlatformLauncher/      ← New (WPEPlatform API only)
│   ├── main.cpp
│   └── CMakeLists.txt
└── PlatformWPE.cmake         ← Modified to add WPEPlatformLauncher
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The new &lt;strong&gt;WPEPlatform API&lt;/strong&gt; makes building WPE WebKit applications significantly simpler:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No manual backend setup&lt;/strong&gt; — the platform is detected and configured automatically&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GObject-based&lt;/strong&gt; — signals, properties, and ref counting instead of C function pointers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DMA-BUF direct sharing&lt;/strong&gt; — no dependency on Mesa’s deprecated EGL extensions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unified window management&lt;/strong&gt; — fullscreen, maximize, minimize, resize, and title&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language binding friendly&lt;/strong&gt; — works with Python, JavaScript, and more via GObject Introspection&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For embedded browser developers building kiosk UIs, set-top box interfaces, or digital signage with WPE WebKit — now is the time to adopt the new API. The stable release is coming in September 2026, and the legacy stack (&lt;code&gt;libwpe&lt;/code&gt;, &lt;code&gt;wpebackend-fdo&lt;/code&gt;, Cog) will be deprecated at that point.&lt;/p&gt;
&lt;h2 id=&quot;resources&quot; tabindex=&quot;-1&quot;&gt;Resources &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/klee/building-a-custom-html-context-menu-with-the-new-wpeplatform-api/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wpewebkit.org/&quot;&gt;WPE WebKit official site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wpewebkit.org/reference/2.51.92/wpe-webkit-2.0/index.html&quot;&gt;WPE WebKit API Reference (2.51.92)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wpewebkit.org/reference/2.51.92/wpe-webkit-2.0/class.ContextMenu.html&quot;&gt;WebKitContextMenu API Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kate-k-lee/WebKit/commit/aed6402b267475f79ae7a8d417d18239b53be651&quot;&gt;WPEPlatformLauncher source code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.igalia.com/project/wpe&quot;&gt;Igalia — WPE WebKit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Igalia/cog&quot;&gt;Cog — WPE launcher (legacy)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
</feed>
