clan-app: changed webui to webview lib

This commit is contained in:
Qubasa
2025-01-04 00:23:41 +01:00
parent 0fa1b4586d
commit ea5a2a9447
6 changed files with 241 additions and 78 deletions

View File

@@ -0,0 +1,134 @@
import ctypes
import sys
import os
import platform
import urllib.request
from pathlib import Path
from ctypes import c_int, c_char_p, c_void_p, CFUNCTYPE
import ctypes.util
def _encode_c_string(s: str) -> bytes:
return s.encode("utf-8")
def _get_webview_version():
"""Get webview version from environment variable or use default"""
return os.getenv("WEBVIEW_VERSION", "0.8.1")
def _get_lib_names():
"""Get platform-specific library names."""
system = platform.system().lower()
machine = platform.machine().lower()
if system == "windows":
if machine == "amd64" or machine == "x86_64":
return ["webview.dll", "WebView2Loader.dll"]
elif machine == "arm64":
raise Exception("arm64 is not supported on Windows")
elif system == "darwin":
if machine == "arm64":
return ["libwebview.aarch64.dylib"]
else:
return ["libwebview.x86_64.dylib"]
else: # linux
return ["libwebview.so"]
def _get_download_urls():
"""Get the appropriate download URLs based on the platform."""
version = _get_webview_version()
return [f"https://github.com/webview/webview_deno/releases/download/{version}/{lib_name}"
for lib_name in _get_lib_names()]
def _be_sure_libraries():
"""Ensure libraries exist and return paths."""
if getattr(sys, 'frozen', False):
if hasattr(sys, '_MEIPASS'):
base_dir = Path(sys._MEIPASS)
else:
base_dir = Path(sys.executable).parent / '_internal'
else:
base_dir = Path(__file__).parent
lib_dir = base_dir / "lib"
lib_names = _get_lib_names()
lib_paths = [lib_dir / lib_name for lib_name in lib_names]
# Check if any library is missing
missing_libs = [path for path in lib_paths if not path.exists()]
if not missing_libs:
return lib_paths
# Download missing libraries
download_urls = _get_download_urls()
system = platform.system().lower()
lib_dir.mkdir(parents=True, exist_ok=True)
for url, lib_path in zip(download_urls, lib_paths):
if lib_path.exists():
continue
print(f"Downloading library from {url}")
try:
req = urllib.request.Request(
url,
headers={'User-Agent': 'Mozilla/5.0'}
)
with urllib.request.urlopen(req) as response, open(lib_path, 'wb') as out_file:
out_file.write(response.read())
except Exception as e:
raise RuntimeError(f"Failed to download library: {e}")
return lib_paths
class _WebviewLibrary:
def __init__(self):
lib_names=_get_lib_names()
try:
library_path = ctypes.util.find_library(lib_names[0])
if not library_path:
library_paths = _be_sure_libraries()
self.lib = ctypes.cdll.LoadLibrary(str(library_paths[0]))
except Exception as e:
print(f"Failed to load webview library: {e}")
raise
# Define FFI functions
self.webview_create = self.lib.webview_create
self.webview_create.argtypes = [c_int, c_void_p]
self.webview_create.restype = c_void_p
self.webview_destroy = self.lib.webview_destroy
self.webview_destroy.argtypes = [c_void_p]
self.webview_run = self.lib.webview_run
self.webview_run.argtypes = [c_void_p]
self.webview_terminate = self.lib.webview_terminate
self.webview_terminate.argtypes = [c_void_p]
self.webview_set_title = self.lib.webview_set_title
self.webview_set_title.argtypes = [c_void_p, c_char_p]
self.webview_set_size = self.lib.webview_set_size
self.webview_set_size.argtypes = [c_void_p, c_int, c_int, c_int]
self.webview_navigate = self.lib.webview_navigate
self.webview_navigate.argtypes = [c_void_p, c_char_p]
self.webview_init = self.lib.webview_init
self.webview_init.argtypes = [c_void_p, c_char_p]
self.webview_eval = self.lib.webview_eval
self.webview_eval.argtypes = [c_void_p, c_char_p]
self.webview_bind = self.lib.webview_bind
self.webview_bind.argtypes = [c_void_p, c_char_p, c_void_p, c_void_p]
self.webview_unbind = self.lib.webview_unbind
self.webview_unbind.argtypes = [c_void_p, c_char_p]
self.webview_return = self.lib.webview_return
self.webview_return.argtypes = [c_void_p, c_char_p, c_int, c_char_p]
self.CFUNCTYPE = CFUNCTYPE
_webview_lib = _WebviewLibrary()

View File

@@ -0,0 +1,92 @@
from enum import IntEnum
from typing import Optional, Callable, Any
import json
import ctypes
from ._webview_ffi import _webview_lib, _encode_c_string
class SizeHint(IntEnum):
NONE = 0
MIN = 1
MAX = 2
FIXED = 3
class Size:
def __init__(self, width: int, height: int, hint: SizeHint):
self.width = width
self.height = height
self.hint = hint
class Webview:
def __init__(self, debug: bool = False, size: Optional[Size] = None, window: Optional[int] = None):
self._handle = _webview_lib.webview_create(int(debug), window)
self._callbacks = {}
if size:
self.size = size
@property
def size(self) -> Size:
return self._size
@size.setter
def size(self, value: Size):
_webview_lib.webview_set_size(self._handle, value.width, value.height, value.hint)
self._size = value
@property
def title(self) -> str:
return self._title
@title.setter
def title(self, value: str):
_webview_lib.webview_set_title(self._handle, _encode_c_string(value))
self._title = value
def destroy(self):
for name in list(self._callbacks.keys()):
self.unbind(name)
_webview_lib.webview_terminate(self._handle)
_webview_lib.webview_destroy(self._handle)
self._handle = None
def navigate(self, url: str):
_webview_lib.webview_navigate(self._handle, _encode_c_string(url))
def run(self):
_webview_lib.webview_run(self._handle)
self.destroy()
def bind(self, name: str, callback: Callable[..., Any]):
def wrapper(seq: bytes, req: bytes, arg: int):
args = json.loads(req.decode())
try:
result = callback(*args)
success = True
except Exception as e:
result = str(e)
success = False
self.return_(seq.decode(), 0 if success else 1, json.dumps(result))
c_callback = _webview_lib.CFUNCTYPE(None, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_void_p)(wrapper)
self._callbacks[name] = c_callback
_webview_lib.webview_bind(self._handle, _encode_c_string(name), c_callback, None)
def unbind(self, name: str):
if name in self._callbacks:
_webview_lib.webview_unbind(self._handle, _encode_c_string(name))
del self._callbacks[name]
def return_(self, seq: str, status: int, result: str):
_webview_lib.webview_return(self._handle, _encode_c_string(seq), status, _encode_c_string(result))
def eval(self, source: str):
_webview_lib.webview_eval(self._handle, _encode_c_string(source))
def init(self, source: str):
_webview_lib.webview_init(self._handle, _encode_c_string(source))
if __name__ == "__main__":
wv = Webview()
wv.title = "Hello, World!"
wv.navigate("https://www.google.com")
wv.run()

View File

@@ -1,56 +0,0 @@
{ lib
, buildPythonPackage
, fetchFromGitHub
# build-system dependencies
, setuptools
, wheel
, webview-wrapper
}:
buildPythonPackage rec {
pname = "python-webui";
version = "main";
src = fetchFromGitHub {
owner = "webui-dev";
repo = "python-webui";
rev = "fa961b5ee0752c9408ac01519097f5481a0fcecf"; # Replace with specific commit hash for reproducibility
# sha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Replace with actual hash via nix-prefetch-git
};
sourceRoot = "PyPI/Package";
# Indicate this is a recent Python project with PEP 517 support (pyproject.toml)
pyproject = true;
# Declare the build system (setuptools and wheel are common)
buildInputs = [
setuptools
wheel
];
# Declare required Python package dependencies
propagatedBuildInputs = [
];
# Native inputs for testing, if tests are included
nativeCheckInputs = [
];
# If tests don't work out of the box or need adjustments, patches can be applied here
postPatch = ''
# Example: Modify or patch some test files
echo "No postPatch modifications applied yet."
'';
meta = with lib; {
description = "A Python library for webui-dev";
homepage = "https://github.com/webui-dev/python-webui";
license = licenses.mit;
maintainers = [ maintainers.yourname ];
};
}

View File

@@ -1,39 +1,32 @@
{ pkgs }:
pkgs.stdenv.mkDerivation rec {
pname = "webui";
pkgs.stdenv.mkDerivation {
pname = "webview";
version = "nigthly";
src = pkgs.fetchFromGitHub {
owner = "webui-dev";
repo = "python-webui";
rev = "0ff3b1351b9e24be4463b1baf2c26966caeae74a"; # Use a specific commit sha or tag for reproducibility
sha256 = "sha256-xSOnCkW4iZkSSLKzk6r3hewC3bPJlV7L6aoGEchyEys="; # Replace with actual sha256
owner = "webview";
repo = "webview";
rev = "83a4b4a5bbcb4b0ba2ca3ee226c2da1414719106";
sha256 = "sha256-5R8kllvP2EBuDANIl07fxv/EcbPpYgeav8Wfz7Kt13c=";
};
outputs = [ "out" "dev" ];
# Dependencies used during the build process, if any
buildInputs = [
pkgs.gnumake
buildInputs = with pkgs; [
gnumake
cmake
pkg-config
webkitgtk_6_0
gtk4
];
# Commands to build and install the project
buildPhase = ''
make
'';
installPhase = ''
mkdir -p $out/lib
mkdir -p $out/include
cp -r dist/* $out/lib
cp -r include/* $out/include
'';
meta = with pkgs.lib; {
description = "Webui is a UI library for C/C++/Go/Rust to build portable desktop/web apps using WebView";
homepage = "https://github.com/webui-dev/webui";
description = "Tiny cross-platform webview library for C/C++. Uses WebKit (GTK/Cocoa) and Edge WebView2 (Windows)";
homepage = "https://github.com/webview/webview";
license = licenses.mit;
platforms = platforms.linux ++ platforms.darwin; # Adjust if needed
platforms = platforms.linux ++ platforms.darwin;
};
}