From 8b899f9b8d852b5aa02dd8e8e948e28d42e6dc32 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Mon, 14 Jul 2025 21:14:21 +0200 Subject: [PATCH] add webview --- .../main/java/de/unixwork/ui/ArgFuncs.java | 48 ++++++ .../src/main/java/de/unixwork/ui/Context.java | 8 + .../src/main/java/de/unixwork/ui/WebView.java | 152 ++++++++++++++++++ .../java/de/unixwork/ui/WebViewBuilder.java | 144 +++++++++++++++++ .../java/de/unixwork/ui/WebViewFuncs.java | 70 ++++++++ 5 files changed, 422 insertions(+) create mode 100644 ui-java/src/main/java/de/unixwork/ui/WebView.java create mode 100644 ui-java/src/main/java/de/unixwork/ui/WebViewBuilder.java create mode 100644 ui-java/src/main/java/de/unixwork/ui/WebViewFuncs.java diff --git a/ui-java/src/main/java/de/unixwork/ui/ArgFuncs.java b/ui-java/src/main/java/de/unixwork/ui/ArgFuncs.java index d4d6647..f9706c9 100644 --- a/ui-java/src/main/java/de/unixwork/ui/ArgFuncs.java +++ b/ui-java/src/main/java/de/unixwork/ui/ArgFuncs.java @@ -241,6 +241,22 @@ class ArgFuncs { MethodHandle textfield_args_set_groups; MethodHandle textfield_args_free; + MethodHandle webview_args_new; + MethodHandle webview_args_set_fill; + MethodHandle webview_args_set_hexpand; + MethodHandle webview_args_set_vexpand; + MethodHandle webview_args_set_hfill; + MethodHandle webview_args_set_vfill; + MethodHandle webview_args_set_override_defaults; + MethodHandle webview_args_set_colspan; + MethodHandle webview_args_set_rowspan; + MethodHandle webview_args_set_name; + MethodHandle webview_args_set_style_class; + MethodHandle webview_args_set_varname; + MethodHandle webview_args_set_value; + MethodHandle webview_args_set_groups; + MethodHandle webview_args_free; + private ArgFuncs(Linker linker, SymbolLookup lib) { FunctionDescriptor sigm = FunctionDescriptor.of(ValueLayout.ADDRESS); FunctionDescriptor sigv_m = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS); @@ -484,6 +500,22 @@ class ArgFuncs { MemorySegment ui_textfield_args_set_groups_addr = lib.find("ui_textfield_args_set_groups").orElseThrow(); MemorySegment ui_textfield_args_free_addr = lib.find("ui_textfield_^args_free").orElseThrow(); + MemorySegment ui_webview_args_new_addr = lib.find("ui_webview_args_new").orElseThrow(); + MemorySegment ui_webview_args_set_fill_addr = lib.find("ui_webview_args_set_fill").orElseThrow(); + MemorySegment ui_webview_args_set_hexpand_addr = lib.find("ui_webview_args_set_hexpand").orElseThrow(); + MemorySegment ui_webview_args_set_vexpand_addr = lib.find("ui_webview_args_set_vexpand").orElseThrow(); + MemorySegment ui_webview_args_set_hfill_addr = lib.find("ui_webview_args_set_hfill").orElseThrow(); + MemorySegment ui_webview_args_set_vfill_addr = lib.find("ui_webview_args_set_vfill").orElseThrow(); + MemorySegment ui_webview_args_set_override_defaults_addr = lib.find("ui_webview_args_set_override_defaults").orElseThrow(); + MemorySegment ui_webview_args_set_colspan_addr = lib.find("ui_webview_args_set_colspan").orElseThrow(); + MemorySegment ui_webview_args_set_rowspan_addr = lib.find("ui_webview_args_set_rowspan").orElseThrow(); + MemorySegment ui_webview_args_set_name_addr = lib.find("ui_webview_args_set_name").orElseThrow(); + MemorySegment ui_webview_args_set_style_class_addr = lib.find("ui_webview_args_set_style_class").orElseThrow(); + MemorySegment ui_webview_args_set_varname_addr = lib.find("ui_webview_args_set_varname").orElseThrow(); + MemorySegment ui_webview_args_set_value_addr = lib.find("ui_webview_args_set_value").orElseThrow(); + MemorySegment ui_webview_args_set_groups_addr = lib.find("ui_webview_args_set_groups").orElseThrow(); + MemorySegment ui_webview_args_free_addr = lib.find("ui_webview_args_free").orElseThrow(); + menuitem_args_new = linker.downcallHandle(ui_menuitem_args_new_addr, sigm); menuitem_args_set_label = linker.downcallHandle(ui_menuitem_args_set_label_addr, sigv_mm); menuitem_args_set_stockid = linker.downcallHandle(ui_menuitem_args_set_stockid_addr, sigv_mm); @@ -718,6 +750,22 @@ class ArgFuncs { textfield_args_set_onactivatedata = linker.downcallHandle(ui_textfield_args_set_onactivatedata_addr, sigv_mm); textfield_args_set_groups = linker.downcallHandle(ui_textfield_args_set_groups_addr, sigv_mm); textfield_args_free = linker.downcallHandle(ui_textfield_args_free_addr, sigv_m); + + webview_args_new = linker.downcallHandle(ui_webview_args_new_addr, sigm); + webview_args_set_fill = linker.downcallHandle(ui_webview_args_set_fill_addr, sigm); + webview_args_set_hexpand = linker.downcallHandle(ui_webview_args_set_hexpand_addr, sigv_mb); + webview_args_set_vexpand = linker.downcallHandle(ui_webview_args_set_vexpand_addr, sigv_mb); + webview_args_set_hfill = linker.downcallHandle(ui_webview_args_set_hfill_addr, sigv_mb); + webview_args_set_vfill = linker.downcallHandle(ui_webview_args_set_vfill_addr, sigv_mb); + webview_args_set_override_defaults = linker.downcallHandle(ui_webview_args_set_override_defaults_addr, sigv_mb); + webview_args_set_colspan = linker.downcallHandle(ui_webview_args_set_colspan_addr, sigv_mi); + webview_args_set_rowspan = linker.downcallHandle(ui_webview_args_set_rowspan_addr, sigv_mi); + webview_args_set_name = linker.downcallHandle(ui_webview_args_set_name_addr, sigv_mm); + webview_args_set_style_class = linker.downcallHandle(ui_webview_args_set_style_class_addr, sigv_mm); + webview_args_set_varname = linker.downcallHandle(ui_webview_args_set_varname_addr, sigv_mm); + webview_args_set_value = linker.downcallHandle(ui_webview_args_set_value_addr, sigv_mm); + webview_args_set_groups = linker.downcallHandle(ui_webview_args_set_groups_addr, sigv_mm); + webview_args_free = linker.downcallHandle(ui_webview_args_free_addr, sigv_m); } static ArgFuncs getInstance() { diff --git a/ui-java/src/main/java/de/unixwork/ui/Context.java b/ui-java/src/main/java/de/unixwork/ui/Context.java index 9b6317f..89e2b95 100644 --- a/ui-java/src/main/java/de/unixwork/ui/Context.java +++ b/ui-java/src/main/java/de/unixwork/ui/Context.java @@ -64,6 +64,14 @@ public abstract class Context { return new UiSourceList(this, name); } + public WebView webView() { + return webView(null); + } + + public WebView webView(String name) { + return new WebView(this, name); + } + public MemorySegment registerValueConverter(ListValueConverter converter) { MemorySegment funcData = arena.allocate(ValueLayout.JAVA_LONG, 2); funcData.setAtIndex(ValueLayout.JAVA_LONG, 0, ptr.address()); diff --git a/ui-java/src/main/java/de/unixwork/ui/WebView.java b/ui-java/src/main/java/de/unixwork/ui/WebView.java new file mode 100644 index 0000000..4a13ff4 --- /dev/null +++ b/ui-java/src/main/java/de/unixwork/ui/WebView.java @@ -0,0 +1,152 @@ +package de.unixwork.ui; + +/* + * C type is UiGeneric + */ + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; + +public class WebView { + protected MemorySegment valuePtr; + + protected WebView(Context ctx, String name) { + ToolkitFuncs ui = ToolkitFuncs.getInstance(); + + MemorySegment nameCStr = MemorySegment.NULL; + try (Arena arena = Arena.ofConfined()) { + if(name != null) { + nameCStr = arena.allocateFrom(name); + } + + valuePtr = (MemorySegment) ui.generic_new.invoke(ctx.getCtx(), nameCStr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public void loadUrl(String uri) { + WebViewFuncs ui = WebViewFuncs.getInstance(); + try (Arena arena = Arena.ofConfined()) { + MemorySegment cstr = arena.allocateFrom(uri); + ui.webview_load_url.invoke(valuePtr, cstr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public void loadContent(String uri, String content, String mimeType, String encoding) { + WebViewFuncs ui = WebViewFuncs.getInstance(); + try (Arena arena = Arena.ofConfined()) { + MemorySegment uriCStr = MemorySegment.NULL; + MemorySegment contentCStr = MemorySegment.NULL; + MemorySegment mimeTypeCStr = MemorySegment.NULL; + MemorySegment encodingCStr = MemorySegment.NULL; + if(uri != null) { + uriCStr = arena.allocateFrom(uri); + } + if(content != null) { + contentCStr = arena.allocateFrom(content); + } + if(mimeType != null) { + mimeTypeCStr = arena.allocateFrom(mimeType); + } + if(encoding != null) { + encodingCStr = arena.allocateFrom(encoding); + } + ui.webview_load_content.invoke(valuePtr, uriCStr, contentCStr, mimeTypeCStr, encodingCStr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public void reload() { + WebViewFuncs ui = WebViewFuncs.getInstance(); + try { + ui.webview_reload.invoke(valuePtr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public boolean canGoBack() { + WebViewFuncs ui = WebViewFuncs.getInstance(); + try { + return (boolean) ui.webview_can_go_back.invoke(valuePtr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public boolean canGoForward() { + WebViewFuncs ui = WebViewFuncs.getInstance(); + try { + return (boolean) ui.webview_can_go_forward.invoke(valuePtr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public void goBack() { + WebViewFuncs ui = WebViewFuncs.getInstance(); + try { + ui.webview_go_back.invoke(valuePtr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public void goForward() { + WebViewFuncs ui = WebViewFuncs.getInstance(); + try { + ui.webview_go_forward.invoke(valuePtr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public String getUri() { + WebViewFuncs ui = WebViewFuncs.getInstance(); + try { + MemorySegment cstr = (MemorySegment) ui.webview_get_uri.invoke(valuePtr); + if (cstr != null && cstr.address() != 0) { + return cstr.getString(0); + } + } catch (Throwable e) { + throw new RuntimeException(e); + } + return null; + } + + public void enableJavaScript(boolean enable) { + WebViewFuncs ui = WebViewFuncs.getInstance(); + try { + ui.webview_enable_javascript.invoke(valuePtr, enable); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public void setZoom(double zoom) { + WebViewFuncs ui = WebViewFuncs.getInstance(); + try { + ui.webview_set_zoom.invoke(valuePtr, zoom); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public double getZoom() { + WebViewFuncs ui = WebViewFuncs.getInstance(); + try { + return (Double) ui.webview_get_zoom.invoke(valuePtr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + + public static WebViewBuilder webview(UiObject obj) { + return new WebViewBuilder(obj); + } +} diff --git a/ui-java/src/main/java/de/unixwork/ui/WebViewBuilder.java b/ui-java/src/main/java/de/unixwork/ui/WebViewBuilder.java new file mode 100644 index 0000000..35696b5 --- /dev/null +++ b/ui-java/src/main/java/de/unixwork/ui/WebViewBuilder.java @@ -0,0 +1,144 @@ +package de.unixwork.ui; + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class WebViewBuilder extends AbstractWidgetBuilder { + private boolean fill; + private boolean hexpand; + private boolean vexpand; + private boolean hfill; + private boolean vfill; + private boolean overrideDefaults; + private int colspan; + private int rowspan; + private String name; + private String styleClass; + private UiText value; + private String varname; + private int[] states; + + public WebViewBuilder(UiObject obj) { + this.obj = obj; + this.widgetConstructor = WebViewFuncs.getInstance().webview_create; + this.argsFree = ArgFuncs.getInstance().webview_args_free; + } + + public WebViewBuilder fill(boolean fill) { + this.fill = fill; + return this; + } + + public WebViewBuilder hexpand(boolean hexpand) { + this.hexpand = hexpand; + return this; + } + + public WebViewBuilder vexpand(boolean vexpand) { + this.vexpand = vexpand; + return this; + } + + public WebViewBuilder hfill(boolean hfill) { + this.hfill = hfill; + return this; + } + + public WebViewBuilder vfill(boolean vfill) { + this.vfill = vfill; + return this; + } + + public WebViewBuilder overrideDefaults(boolean overrideDefaults) { + this.overrideDefaults = overrideDefaults; + return this; + } + + public WebViewBuilder colspan(int colspan) { + this.colspan = colspan; + return this; + } + + public WebViewBuilder rowspan(int rowspan) { + this.rowspan = rowspan; + return this; + } + + public WebViewBuilder name(String name) { + this.name = name; + return this; + } + + public WebViewBuilder styleClass(String styleClass) { + this.styleClass = styleClass; + return this; + } + + public WebViewBuilder value(UiText value) { + this.value = value; + return this; + } + + public WebViewBuilder varname(String varname) { + this.varname = varname; + return this; + } + + public WebViewBuilder states(int... states) { + this.states = states; + return this; + } + + public MemorySegment createArgs(Arena arena) throws Throwable { + ArgFuncs ui = ArgFuncs.getInstance(); + + args = (MemorySegment)ui.webview_args_new.invoke(); + if(fill) { + ui.webview_args_set_fill.invoke(args, fill); + } + if(hexpand) { + ui.webview_args_set_hexpand.invoke(args, hexpand); + } + if(vexpand) { + ui.webview_args_set_vexpand.invoke(args, vexpand); + } + if(hfill) { + ui.webview_args_set_hfill.invoke(args, hfill); + } + if(vfill) { + ui.webview_args_set_vfill.invoke(args, vfill); + } + if(overrideDefaults) { + ui.webview_args_set_override_defaults.invoke(args, overrideDefaults); + } + if(colspan > 0) { + ui.webview_args_set_colspan.invoke(args, colspan); + } + if(rowspan > 0) { + ui.webview_args_set_rowspan.invoke(args, rowspan); + } + if(name != null) { + MemorySegment cstr = arena.allocateFrom(name); + ui.webview_args_set_name.invoke(args, cstr); + } + if(styleClass != null) { + MemorySegment cstr = arena.allocateFrom(styleClass); + ui.webview_args_set_style_class.invoke(args, cstr); + } + + if(varname != null) { + MemorySegment cstr = arena.allocateFrom(varname); + ui.webview_args_set_varname.invoke(args, cstr); + } + if(value != null) { + ui.webview_args_set_value.invoke(args, value.valuePtr); + } + + return args; + } +} diff --git a/ui-java/src/main/java/de/unixwork/ui/WebViewFuncs.java b/ui-java/src/main/java/de/unixwork/ui/WebViewFuncs.java new file mode 100644 index 0000000..5ecba20 --- /dev/null +++ b/ui-java/src/main/java/de/unixwork/ui/WebViewFuncs.java @@ -0,0 +1,70 @@ +package de.unixwork.ui; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; + +public class WebViewFuncs { + static WebViewFuncs instance; + + public MethodHandle webview_create; + public MethodHandle webview_load_url; + public MethodHandle webview_load_content; + public MethodHandle webview_reload; + public MethodHandle webview_can_go_back; + public MethodHandle webview_can_go_forward; + public MethodHandle webview_go_back; + public MethodHandle webview_go_forward; + public MethodHandle webview_get_uri; + public MethodHandle webview_enable_javascript; + public MethodHandle webview_set_zoom; + public MethodHandle webview_get_zoom; + + private WebViewFuncs(Linker linker, SymbolLookup lib) { + // void* func(void*, void*) + FunctionDescriptor sigm_mm = FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS); + FunctionDescriptor sigb_m = FunctionDescriptor.of(ValueLayout.JAVA_BOOLEAN, ValueLayout.ADDRESS); + FunctionDescriptor sigm_m = FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS); + FunctionDescriptor sigv_m = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS); + FunctionDescriptor sigv_mb = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.JAVA_BOOLEAN); + FunctionDescriptor sigv_mm = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS); + FunctionDescriptor sigv_md = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_DOUBLE); + FunctionDescriptor sigd_m = FunctionDescriptor.of(ValueLayout.JAVA_DOUBLE, ValueLayout.ADDRESS); + + MemorySegment ui_webview_create_addr = lib.find("ui_webview_create").orElseThrow(); + MemorySegment ui_webview_load_url_addr = lib.find("ui_webview_load_url").orElseThrow(); + MemorySegment ui_webview_load_content_addr = lib.find("ui_webview_load_content").orElseThrow(); + MemorySegment ui_webview_reload_addr = lib.find("ui_webview_reload").orElseThrow(); + MemorySegment ui_webview_can_go_back_addr = lib.find("ui_webview_can_go_back").orElseThrow(); + MemorySegment ui_webview_can_go_forward_addr = lib.find("ui_webview_can_go_forward").orElseThrow(); + MemorySegment ui_webview_go_back_addr = lib.find("ui_webview_go_back").orElseThrow(); + MemorySegment ui_webview_go_forward_addr = lib.find("ui_webview_go_forward").orElseThrow(); + MemorySegment ui_webview_get_uri_addr = lib.find("ui_webview_get_uri").orElseThrow(); + MemorySegment ui_webview_enable_javascript_addr = lib.find("ui_webview_enable_javascript").orElseThrow(); + MemorySegment ui_webview_set_zoom_addr = lib.find("ui_webview_set_zoom").orElseThrow(); + MemorySegment ui_webview_get_zoom_addr = lib.find("ui_webview_get_zoom").orElseThrow(); + + webview_create = linker.downcallHandle(ui_webview_create_addr, sigm_mm); + webview_load_url = linker.downcallHandle(ui_webview_load_url_addr, sigv_mm); + webview_load_content = linker.downcallHandle( + ui_webview_load_content_addr, + FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, + ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS)); + webview_reload = linker.downcallHandle(ui_webview_reload_addr, sigv_m); + webview_can_go_back = linker.downcallHandle(ui_webview_can_go_back_addr, sigb_m); + webview_can_go_forward = linker.downcallHandle(ui_webview_can_go_forward_addr, sigb_m); + webview_go_back = linker.downcallHandle(ui_webview_go_back_addr, sigv_m); + webview_go_forward = linker.downcallHandle(ui_webview_go_forward_addr, sigv_m); + webview_get_uri = linker.downcallHandle(ui_webview_get_uri_addr, sigm_m); + webview_enable_javascript = linker.downcallHandle(ui_webview_enable_javascript_addr, sigv_mb); + webview_set_zoom = linker.downcallHandle(ui_webview_set_zoom_addr, sigv_md); + webview_get_zoom = linker.downcallHandle(ui_webview_get_zoom_addr, sigd_m); + } + + static WebViewFuncs getInstance() { + if (instance == null) { + Toolkit toolkit = Toolkit.getInstance(); + instance = new WebViewFuncs(toolkit.getLinker(), toolkit.getSymbolLookup()); + } + return instance; + } +} -- 2.47.3