Skip to content

Commit

Permalink
Added SetIcon method and new IconKind type
Browse files Browse the repository at this point in the history
  • Loading branch information
Dark Pink committed Jun 8, 2024
1 parent 56f456c commit 31715e6
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 0 deletions.
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

0 comments on commit 31715e6

Please sign in to comment.