diff --git a/pkgs/clan-app/clan_app/app.py b/pkgs/clan-app/clan_app/app.py index d4a2d8bc9..1da360cbf 100644 --- a/pkgs/clan-app/clan_app/app.py +++ b/pkgs/clan-app/clan_app/app.py @@ -109,6 +109,7 @@ def app_run(app_opts: ClanAppOptions) -> int: title="Clan App", size=Size(1280, 1024, SizeHint.NONE), shared_threads=shared_threads, + app_id="org.clan.app", ) API.overwrite_fn(get_system_file) diff --git a/pkgs/clan-app/clan_app/deps/webview/_webview_ffi.py b/pkgs/clan-app/clan_app/deps/webview/_webview_ffi.py index 1c303d447..14578d16a 100644 --- a/pkgs/clan-app/clan_app/deps/webview/_webview_ffi.py +++ b/pkgs/clan-app/clan_app/deps/webview/_webview_ffi.py @@ -5,6 +5,11 @@ import platform from ctypes import CFUNCTYPE, c_char_p, c_int, c_void_p from pathlib import Path +# Native handle kinds +WEBVIEW_NATIVE_HANDLE_KIND_UI_WINDOW = 0 +WEBVIEW_NATIVE_HANDLE_KIND_UI_WIDGET = 1 +WEBVIEW_NATIVE_HANDLE_KIND_BROWSER_CONTROLLER = 2 + def _encode_c_string(s: str) -> bytes: return s.encode("utf-8") @@ -72,6 +77,10 @@ class _WebviewLibrary: self.webview_create.argtypes = [c_int, c_void_p] self.webview_create.restype = c_void_p + self.webview_create_with_app_id = self.lib.webview_create_with_app_id + self.webview_create_with_app_id.argtypes = [c_int, c_void_p, c_char_p] + self.webview_create_with_app_id.restype = c_void_p + self.webview_destroy = self.lib.webview_destroy self.webview_destroy.argtypes = [c_void_p] @@ -105,6 +114,10 @@ class _WebviewLibrary: self.webview_return = self.lib.webview_return self.webview_return.argtypes = [c_void_p, c_char_p, c_int, c_char_p] + self.webview_get_native_handle = self.lib.webview_get_native_handle + self.webview_get_native_handle.argtypes = [c_void_p, c_int] + self.webview_get_native_handle.restype = c_void_p + self.binding_callback_t = CFUNCTYPE(None, c_char_p, c_char_p, c_void_p) self.CFUNCTYPE = CFUNCTYPE diff --git a/pkgs/clan-app/clan_app/deps/webview/webview.py b/pkgs/clan-app/clan_app/deps/webview/webview.py index 6d648b1ae..96f27215c 100644 --- a/pkgs/clan-app/clan_app/deps/webview/webview.py +++ b/pkgs/clan-app/clan_app/deps/webview/webview.py @@ -1,6 +1,7 @@ import functools import json import logging +import platform import threading from collections.abc import Callable from dataclasses import dataclass, field @@ -11,7 +12,10 @@ from typing import TYPE_CHECKING, Any from clan_lib.api import MethodRegistry, message_queue from clan_lib.api.tasks import WebThread -from ._webview_ffi import _encode_c_string, _webview_lib +from ._webview_ffi import ( + _encode_c_string, + _webview_lib, +) from .webview_bridge import WebviewBridge if TYPE_CHECKING: @@ -32,6 +36,21 @@ class FuncStatus(IntEnum): FAILURE = 1 +class NativeHandleKind(IntEnum): + # Top-level window. @c GtkWindow pointer (GTK), @c NSWindow pointer (Cocoa) + # or @c HWND (Win32) + UI_WINDOW = 0 + + # Browser widget. @c GtkWidget pointer (GTK), @c NSView pointer (Cocoa) or + # @c HWND (Win32). + UI_WIDGET = 1 + + # Browser controller. @c WebKitWebView pointer (WebKitGTK), @c WKWebView + # pointer (Cocoa/WebKit) or @c ICoreWebView2Controller pointer + # (Win32/WebView2). + BROWSER_CONTROLLER = 2 + + @dataclass(frozen=True) class Size: width: int @@ -46,6 +65,7 @@ class Webview: size: Size | None = None window: int | None = None shared_threads: dict[str, WebThread] | None = None + app_id: str | None = None # initialized later _bridge: WebviewBridge | None = None @@ -56,7 +76,14 @@ class Webview: def _create_handle(self) -> None: # Initialize the webview handle with_debugger = True - handle = _webview_lib.webview_create(int(with_debugger), self.window) + + # Use webview_create_with_app_id only on Linux if app_id is provided + if self.app_id and platform.system() == "Linux": + handle = _webview_lib.webview_create_with_app_id( + int(with_debugger), self.window, _encode_c_string(self.app_id) + ) + else: + handle = _webview_lib.webview_create(int(with_debugger), self.window) callbacks: dict[str, Callable[..., Any]] = {} # Since we can't use object.__setattr__, we'll initialize differently @@ -217,6 +244,21 @@ class Webview: self._callbacks[name] = c_callback _webview_lib.webview_bind(self.handle, _encode_c_string(name), c_callback, None) + def get_native_handle( + self, kind: NativeHandleKind = NativeHandleKind.UI_WINDOW + ) -> int | None: + """Get the native handle (platform-dependent). + + Args: + kind: Handle kind - NativeHandleKind enum value + + Returns: + Native handle as integer, or None if failed + + """ + handle = _webview_lib.webview_get_native_handle(self.handle, kind.value) + return handle if handle else None + def unbind(self, name: str) -> None: if name in self._callbacks: _webview_lib.webview_unbind(self.handle, _encode_c_string(name)) diff --git a/pkgs/clan-app/webview-lib/default.nix b/pkgs/clan-app/webview-lib/default.nix index 812a70d22..8220770f4 100644 --- a/pkgs/clan-app/webview-lib/default.nix +++ b/pkgs/clan-app/webview-lib/default.nix @@ -24,19 +24,10 @@ clangStdenv.mkDerivation { domain = "git.clan.lol"; owner = "clan"; repo = "webview"; - rev = "ef481aca8e531f6677258ca911c61aaaf71d2214"; - hash = "sha256-KF9ESpo40z6VXyYsZCLWJAIh0RFe1Zy/Qw4k7cTpoYU="; + rev = "0ba936b247106219c363a855763ef06b2535363e"; + hash = "sha256-pyH5v7+ytkLOlXpW5WrvN0bqPCOnKnna8+1C0DANoDQ="; }; - # @Mic92: Where is this revision coming from? I can't see it in any of the branches. - # I removed the icon python code for now - # src = pkgs.fetchFromGitHub { - # owner = "clan-lol"; - # repo = "webview"; - # rev = "7d24f0192765b7e08f2d712fae90c046d08f318e"; - # hash = "sha256-yokVI9tFiEEU5M/S2xAeJOghqqiCvTelLo8WLKQZsSY="; - # }; - outputs = [ "out" "dev"