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 SetIcon method and new IconKind type #47

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
17 changes: 17 additions & 0 deletions icon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//go:build !windows
// +build !windows

package webview

import (
"image"
"unsafe"
)

type icons struct{}

func (*icons) setIcon(window unsafe.Pointer, icon image.Image, kind IconKind) {
}

func (*icons) free() {
}
93 changes: 93 additions & 0 deletions icon_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package webview

/*
#cgo LDFLAGS: -lgdi32

#include <windows.h>

LONG_PTR hIconToLongPtr(HICON hIcon) {
return (LONG_PTR)hIcon;
}
*/
import "C"

import (
"image"
"sync"
"unsafe"
)

type icons struct {
mutex sync.Mutex
icons []C.HICON
}

func (c *icons) setIcon(window unsafe.Pointer, icon image.Image, kind IconKind) {
hIcon := prepareIcon(icon)
c.mutex.Lock()
defer c.mutex.Unlock()
if c.icons == nil {
c.icons = make([]C.HICON, maxIconKind)
}
previousHIcon := c.icons[kind]
c.icons[kind] = hIcon
C.SetClassLongPtr(C.HWND(window), prepareIconKind(kind), C.hIconToLongPtr(hIcon))
if previousHIcon != nil {
C.DestroyIcon(previousHIcon)
}
}

func (c *icons) free() {
c.mutex.Lock()
defer c.mutex.Unlock()
for i, hIcon := range c.icons {
if hIcon != nil {
C.DestroyIcon(hIcon)
c.icons[i] = nil
}
}
}

func prepareIcon(icon image.Image) C.HICON {
width, height, mask, color := prepareIconData(icon)
iconInfo := C.ICONINFO{}
iconInfo.fIcon = C.TRUE
iconInfo.xHotspot = 0
iconInfo.yHotspot = 0
iconInfo.hbmMask = C.CreateBitmap(C.int(width), C.int(height), 1, 8, unsafe.Pointer(&mask[0]))
iconInfo.hbmColor = C.CreateBitmap(C.int(width), C.int(height), 1, 32, unsafe.Pointer(&color[0]))
hIcon := C.CreateIconIndirect(&iconInfo)
C.DeleteObject(C.HGDIOBJ(iconInfo.hbmMask))
C.DeleteObject(C.HGDIOBJ(iconInfo.hbmColor))
return hIcon
}

func prepareIconData(img image.Image) (width, height int, mask, color []byte) {
bounds := img.Bounds()
width, height = bounds.Dx(), bounds.Dy()
mask = make([]byte, width*height)
color = make([]byte, 4*width*height)
for y, maskIndex, colorIndex := 0, 0, 0; y < height; y++ {
for x := 0; x < width; x++ {
r, g, b, a := img.At(x, y).RGBA()
color[colorIndex] = byte(b >> 8)
colorIndex++
color[colorIndex] = byte(g >> 8)
colorIndex++
color[colorIndex] = byte(r >> 8)
colorIndex++
color[colorIndex] = byte(a >> 8)
colorIndex++
mask[maskIndex] = byte(a >> 8)
maskIndex++
}
}
return width, height, mask, color
}

func prepareIconKind(kind IconKind) C.int {
if kind == IconKindSmaller {
return C.GCLP_HICONSM
}
return C.GCLP_HICON
}
20 changes: 20 additions & 0 deletions webview.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import "C"
import (
"encoding/json"
"errors"
"image"
"reflect"
"runtime"
"sync"
Expand All @@ -38,6 +39,15 @@ func init() {
runtime.LockOSThread()
}

// IconKind is used to specify usage of icon.
type IconKind int

const (
IconKindDefault = IconKind(iota)
IconKindSmaller
maxIconKind
)

// Hints are used to configure window sizing and resizing
type Hint int

Expand Down Expand Up @@ -78,6 +88,10 @@ type WebView interface {
// NSWindow pointer, when using Win32 backend the pointer is HWND pointer.
Window() unsafe.Pointer

// SetIcon updates the icon of the native window. Must be called from the UI
// thread.
SetIcon(icon image.Image, kind IconKind)

// SetTitle updates the title of the native window. Must be called from the UI
// thread.
SetTitle(title string)
Expand Down Expand Up @@ -122,6 +136,7 @@ type WebView interface {

type webview struct {
w C.webview_t
i icons
}

var (
Expand Down Expand Up @@ -156,6 +171,7 @@ func NewWindow(debug bool, window unsafe.Pointer) WebView {

func (w *webview) Destroy() {
C.webview_destroy(w.w)
w.i.free()
}

func (w *webview) Run() {
Expand All @@ -182,6 +198,10 @@ func (w *webview) SetHtml(html string) {
C.webview_set_html(w.w, s)
}

func (w *webview) SetIcon(icon image.Image, kind IconKind) {
w.i.setIcon(w.Window(), icon, kind)
}

func (w *webview) SetTitle(title string) {
s := C.CString(title)
defer C.free(unsafe.Pointer(s))
Expand Down