Skip to content

Commit 31715e6

Browse files
author
Dark Pink
committed
Added SetIcon method and new IconKind type
1 parent 56f456c commit 31715e6

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed

icon.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//go:build !windows
2+
// +build !windows
3+
4+
package webview
5+
6+
import (
7+
"image"
8+
"unsafe"
9+
)
10+
11+
type icons struct{}
12+
13+
func (*icons) setIcon(window unsafe.Pointer, icon image.Image, kind IconKind) {
14+
}
15+
16+
func (*icons) free() {
17+
}

icon_windows.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package webview
2+
3+
/*
4+
#cgo LDFLAGS: -lgdi32
5+
6+
#include <windows.h>
7+
8+
LONG_PTR hIconToLongPtr(HICON hIcon) {
9+
return (LONG_PTR)hIcon;
10+
}
11+
*/
12+
import "C"
13+
14+
import (
15+
"image"
16+
"sync"
17+
"unsafe"
18+
)
19+
20+
type icons struct {
21+
mutex sync.Mutex
22+
icons []C.HICON
23+
}
24+
25+
func (c *icons) setIcon(window unsafe.Pointer, icon image.Image, kind IconKind) {
26+
hIcon := prepareIcon(icon)
27+
c.mutex.Lock()
28+
defer c.mutex.Unlock()
29+
if c.icons == nil {
30+
c.icons = make([]C.HICON, maxIconKind)
31+
}
32+
previousHIcon := c.icons[kind]
33+
c.icons[kind] = hIcon
34+
C.SetClassLongPtr(C.HWND(window), prepareIconKind(kind), C.hIconToLongPtr(hIcon))
35+
if previousHIcon != nil {
36+
C.DestroyIcon(previousHIcon)
37+
}
38+
}
39+
40+
func (c *icons) free() {
41+
c.mutex.Lock()
42+
defer c.mutex.Unlock()
43+
for i, hIcon := range c.icons {
44+
if hIcon != nil {
45+
C.DestroyIcon(hIcon)
46+
c.icons[i] = nil
47+
}
48+
}
49+
}
50+
51+
func prepareIcon(icon image.Image) C.HICON {
52+
width, height, mask, color := prepareIconData(icon)
53+
iconInfo := C.ICONINFO{}
54+
iconInfo.fIcon = C.TRUE
55+
iconInfo.xHotspot = 0
56+
iconInfo.yHotspot = 0
57+
iconInfo.hbmMask = C.CreateBitmap(C.int(width), C.int(height), 1, 8, unsafe.Pointer(&mask[0]))
58+
iconInfo.hbmColor = C.CreateBitmap(C.int(width), C.int(height), 1, 32, unsafe.Pointer(&color[0]))
59+
hIcon := C.CreateIconIndirect(&iconInfo)
60+
C.DeleteObject(C.HGDIOBJ(iconInfo.hbmMask))
61+
C.DeleteObject(C.HGDIOBJ(iconInfo.hbmColor))
62+
return hIcon
63+
}
64+
65+
func prepareIconData(img image.Image) (width, height int, mask, color []byte) {
66+
bounds := img.Bounds()
67+
width, height = bounds.Dx(), bounds.Dy()
68+
mask = make([]byte, width*height)
69+
color = make([]byte, 4*width*height)
70+
for y, maskIndex, colorIndex := 0, 0, 0; y < height; y++ {
71+
for x := 0; x < width; x++ {
72+
r, g, b, a := img.At(x, y).RGBA()
73+
color[colorIndex] = byte(b >> 8)
74+
colorIndex++
75+
color[colorIndex] = byte(g >> 8)
76+
colorIndex++
77+
color[colorIndex] = byte(r >> 8)
78+
colorIndex++
79+
color[colorIndex] = byte(a >> 8)
80+
colorIndex++
81+
mask[maskIndex] = byte(a >> 8)
82+
maskIndex++
83+
}
84+
}
85+
return width, height, mask, color
86+
}
87+
88+
func prepareIconKind(kind IconKind) C.int {
89+
if kind == IconKindSmaller {
90+
return C.GCLP_HICONSM
91+
}
92+
return C.GCLP_HICON
93+
}

webview.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import "C"
2727
import (
2828
"encoding/json"
2929
"errors"
30+
"image"
3031
"reflect"
3132
"runtime"
3233
"sync"
@@ -38,6 +39,15 @@ func init() {
3839
runtime.LockOSThread()
3940
}
4041

42+
// IconKind is used to specify usage of icon.
43+
type IconKind int
44+
45+
const (
46+
IconKindDefault = IconKind(iota)
47+
IconKindSmaller
48+
maxIconKind
49+
)
50+
4151
// Hints are used to configure window sizing and resizing
4252
type Hint int
4353

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

91+
// SetIcon updates the icon of the native window. Must be called from the UI
92+
// thread.
93+
SetIcon(icon image.Image, kind IconKind)
94+
8195
// SetTitle updates the title of the native window. Must be called from the UI
8296
// thread.
8397
SetTitle(title string)
@@ -122,6 +136,7 @@ type WebView interface {
122136

123137
type webview struct {
124138
w C.webview_t
139+
i icons
125140
}
126141

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

157172
func (w *webview) Destroy() {
158173
C.webview_destroy(w.w)
174+
w.i.free()
159175
}
160176

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

201+
func (w *webview) SetIcon(icon image.Image, kind IconKind) {
202+
w.i.setIcon(w.Window(), icon, kind)
203+
}
204+
185205
func (w *webview) SetTitle(title string) {
186206
s := C.CString(title)
187207
defer C.free(unsafe.Pointer(s))

0 commit comments

Comments
 (0)