Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added basic icon support for webview #24

Merged
merged 14 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/icon.ico
Binary file not shown.
Binary file added assets/icon_2.ico
Binary file not shown.
27 changes: 27 additions & 0 deletions src/icon.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "icon.h"

void set_window_icon(const wchar_t *applicationTitle, const wchar_t *iconFilePath)
{

// Load the icon from the specified file
HICON hIcon = LoadImageW(NULL, iconFilePath, IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
if (hIcon == NULL)
{
MessageBoxW(NULL, L"Failed to load icon from file!", L"Error", MB_ICONERROR);
}
// Get the current application's main window using the application's title
// This can be handled better, for instance using a pointer to webview to
// get the application, but for now this works fine.
HWND hwnd = FindWindowW(NULL, applicationTitle);

if (hwnd == NULL)
{
MessageBoxW(NULL, L"Failed to find the application window!", L"Error", MB_ICONERROR);
DestroyIcon(hIcon);
}
// Set the application icon
SendMessageW(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);

// Cleanup
DestroyIcon(hIcon);
}
6 changes: 6 additions & 0 deletions src/icon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once
#include <windows.h>
#include <stdio.h>
#include <tchar.h>

void set_window_icon(const wchar_t *applicationTitle, const wchar_t *iconFilePath);
15 changes: 15 additions & 0 deletions src/icon_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module webview

fn test_set_icon() {
mut w := create(debug: false)
w.set_title('webview')
w.set_size(600, 400, .@none)
w.set_html('<html style="background: #1B2845; color: #eee">
<samp>${@FILE}</samp>
<h2>Testing set_icon</h2>
</html>')
w.set_window_icon('${@VMODROOT}/assets/icon_2.ico')
w.run()

w.destroy()
}
13 changes: 12 additions & 1 deletion src/lib.c.v
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
module webview

import builtin.wchar

#flag linux -DWEBVIEW_GTK -lstdc++
#flag darwin -DWEBVIEW_COCOA -framework WebKit -stdlib=libc++ -lstdc++
#flag windows -DWEBVIEW_EDGE -static -ladvapi32 -lole32 -lshell32 -lshlwapi -luser32 -lversion -lstdc++

$if windows {
#flag -I @VMODROOT/src/icon.h
#flag @VMODROOT/src/icon.c
}

#flag @VMODROOT/src/webview.o
#include "@VMODROOT/src/webview.h"

$if windows {
#include "@VMODROOT/src/icon.h"
}
$if linux {
#pkgconfig gtk+-3.0
#pkgconfig webkit2gtk-4.0
Expand All @@ -26,6 +35,8 @@ fn C.webview_dispatch(w &C.webview_t, func fn (w &C.webview_t, ctx voidptr), ctx

fn C.webview_get_window(w &C.webview_t) voidptr

fn C.set_window_icon(application_title &wchar.Character, ico_file_path &wchar.Character) bool

fn C.webview_set_title(w &C.webview_t, title &char)

fn C.webview_set_size(w &C.webview_t, width int, height int, hints int)
Expand Down
94 changes: 58 additions & 36 deletions src/lib.v
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@ Source webview C library: https://github.com/webview/webview
module webview

import json
import builtin.wchar

pub type Webview = C.webview_t

pub struct WebviewContext {
pub:
ctx &C.webview_t
pub mut:
title string
}

pub struct Event {
pub:
instance &Webview // Pointer to the webview instance
Expand Down Expand Up @@ -45,9 +53,9 @@ pub enum Hint {
// Window size can not be changed by a user
fixed = C.WEBVIEW_HINT_FIXED
// Width and height are minimum bounds
min = C.WEBVIEW_HINT_MIN
min = C.WEBVIEW_HINT_MIN
// Width and height are maximum bounds
max = C.WEBVIEW_HINT_MAX
max = C.WEBVIEW_HINT_MAX
}

// create creates a new webview instance. If `debug` is `true` - developer tools
Expand All @@ -58,108 +66,122 @@ pub enum Hint {
// passed here. Returns null on failure. Creation can fail for various reasons
// such as when required runtime dependencies are missing or when window creation
// fails.
pub fn create(opts CreateOptions) &Webview {
return C.webview_create(int(opts.debug), opts.window)
pub fn create(opts CreateOptions) &WebviewContext {
ctx := C.webview_create(int(opts.debug), opts.window)
mut s := &WebviewContext{
ctx: ctx
title: 'webview'
}
s.set_title(s.title)
s.set_window_icon('${@VMODROOT}/assets/icon.ico')
return s
}

// destroy destroys a webview and closes the native window.
pub fn (w &Webview) destroy() {
C.webview_destroy(w)
pub fn (w &WebviewContext) destroy() {
C.webview_destroy(w.ctx)
}

// run runs the main loop until it's terminated. After this function exits - you
// must destroy the webview.
pub fn (w &Webview) run() {
C.webview_run(w)
pub fn (w &WebviewContext) run() {
C.webview_run(w.ctx)
}

// terminate stops the main loop. It is safe to call this function from another
// other background thread.
pub fn (w &Webview) terminate() {
C.webview_terminate(w)
pub fn (w &WebviewContext) terminate() {
C.webview_terminate(w.ctx)
}

// dispatch posts a function to be executed on the main thread. You normally do
// not need to call this function, unless you want to tweak the native window.
pub fn (w &Webview) dispatch(func fn ()) {
C.webview_dispatch(w, fn [func] (w &Webview, ctx voidptr) {
pub fn (w &WebviewContext) dispatch(func fn ()) {
C.webview_dispatch(w.ctx, fn [func] (w &Webview, ctx voidptr) {
func()
}, 0)
}

// dispatch_ctx posts a function to be executed on the main thread. You normally do
// not need to call this function, unless you want to tweak the native window.
pub fn (w &Webview) dispatch_ctx(func fn (ctx voidptr), ctx voidptr) {
C.webview_dispatch(w, fn [func] (w &Webview, ctx voidptr) {
pub fn (w &WebviewContext) dispatch_ctx(func fn (ctx voidptr), ctx voidptr) {
C.webview_dispatch(w.ctx, fn [func] (w &Webview, ctx voidptr) {
func(ctx)
}, ctx)
}

// get_window returns a native window handle pointer. When using a GTK backend
// the pointer is a GtkWindow pointer, when using a Cocoa backend the pointer is
// a NSWindow pointer, when using a Win32 backend the pointer is a HWND pointer.
pub fn (w &Webview) get_window() voidptr {
return C.webview_get_window(w)
pub fn (w &WebviewContext) get_window() voidptr {
return C.webview_get_window(w.ctx)
}

// set_window_icon change the default icon for webview.
// FIXME: Currently only Windows is supported.
pub fn (w &WebviewContext) set_window_icon(icon_file_path string) {
C.set_window_icon(wchar.from_string(w.title), wchar.from_string(icon_file_path))
}

// set_title updates the title of the native window. Must be called from the UI thread.
pub fn (w &Webview) set_title(title string) {
C.webview_set_title(w, &char(title.str))
pub fn (mut w WebviewContext) set_title(title string) {
w.title = title
C.webview_set_title(w.ctx, &char(title.str))
}

// set_size updates the size of the native window. See WEBVIEW_HINT constants.
pub fn (w &Webview) set_size(width int, height int, hint Hint) {
C.webview_set_size(w, width, height, int(hint))
pub fn (w &WebviewContext) set_size(width int, height int, hint Hint) {
C.webview_set_size(w.ctx, width, height, int(hint))
}

// navigate navigates webview to the given URL. URL may be a properly encoded data URI.
// Example: w.navigate('https://github.com/webview/webview') {
// Example: w.navigate('data:text/html,%3Ch1%3EHello%3C%2Fh1%3E')
// Example: w.navigate('file://${@VMODROOT}/index.html')
pub fn (w &Webview) navigate(url string) {
C.webview_navigate(w, &char(url.str))
pub fn (w &WebviewContext) navigate(url string) {
C.webview_navigate(w.ctx, &char(url.str))
}

// set_html set webview HTML directly.
pub fn (w &Webview) set_html(html string) {
C.webview_set_html(w, &char(html.str))
pub fn (w &WebviewContext) set_html(html string) {
C.webview_set_html(w.ctx, &char(html.str))
}

// init injects JavaScript code at the initialization of the new page. Every time
// the webview will open a new page - this initialization code will be executed.
// It is guaranteed that code is executed before window.onload.
pub fn (w &Webview) init(code string) {
C.webview_init(w, &char(code.str))
pub fn (w &WebviewContext) init(code string) {
C.webview_init(w.ctx, &char(code.str))
}

// eval evaluates arbitrary JavaScript code. Evaluation happens asynchronously, also
// the result of the expression is ignored. Use RPC bindings if you want to
// receive notifications about the results of the evaluation.
pub fn (w &Webview) eval(code string) {
C.webview_eval(w, &char(code.str))
pub fn (w &WebviewContext) eval(code string) {
C.webview_eval(w.ctx, &char(code.str))
}

// bind binds a callback so that it will appear under the given name as a
// global JavaScript function. Internally it uses webview_init().
// The callback receives an `&Event` pointer.
pub fn (w &Webview) bind(name string, func fn (&Event)) {
C.webview_bind(w, &char(name.str), fn [w, func] (event_id &char, args &char, ctx voidptr) {
func(unsafe { &Event{w, event_id, args} })
pub fn (w &WebviewContext) bind(name string, func fn (&Event)) {
C.webview_bind(w.ctx, &char(name.str), fn [w, func] (event_id &char, args &char, ctx voidptr) {
func(unsafe { &Event{w.ctx, event_id, args} })
}, 0)
}

// bind_ctx binds a callback so that it will appear under the given name as a
// global JavaScript function. Internally it uses webview_init().
// The callback receives an `7Event` pointer and a user-provided ctx pointer.
pub fn (w &Webview) bind_ctx(name string, func fn (e &Event, ctx voidptr), ctx voidptr) {
C.webview_bind(w, &char(name.str), fn [w, func] (event_id &char, args &char, ctx voidptr) {
func(unsafe { &Event{w, event_id, args} }, ctx)
pub fn (w &WebviewContext) bind_ctx(name string, func fn (e &Event, ctx voidptr), ctx voidptr) {
C.webview_bind(w.ctx, &char(name.str), fn [w, func] (event_id &char, args &char, ctx voidptr) {
func(unsafe { &Event{w.ctx, event_id, args} }, ctx)
}, ctx)
}

// unbind removes a native C callback that was previously set by webview_bind.
pub fn (w &Webview) unbind(name string) {
C.webview_unbind(w, &char(name.str))
pub fn (w &WebviewContext) unbind(name string) {
C.webview_unbind(w.ctx, &char(name.str))
}

// @return allows to return a value from the native binding. A request id pointer must
Expand Down
9 changes: 5 additions & 4 deletions tests/v_fn_call_test.v → src/v_fn_call_test.v
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import webview
module webview

import time

struct Person {
Expand All @@ -7,7 +8,7 @@ struct Person {
}

fn test_fn_call() {
w := webview.create(debug: true)
w := create(debug: true)

mut fns_called := 0
mut ref := &fns_called
Expand All @@ -27,11 +28,11 @@ fn test_fn_call() {
assert false
}()

w.bind_ctx('v_fn', fn (e &webview.Event, mut fns_called &int) {
w.bind_ctx('v_fn', fn (e &Event, mut fns_called &int) {
fns_called++
assert e.string(0) == 'foo'
}, fns_called)
w.bind_ctx('v_fn_with_obj_arg', fn (e &webview.Event, mut fns_called &int) {
w.bind_ctx('v_fn_with_obj_arg', fn (e &Event, mut fns_called &int) {
fns_called++
p := e.decode[Person](0) or {
eprintln(err)
Expand Down