Icon fixes (windows), see #35.

This commit is contained in:
Nuno Cruces 2022-07-26 14:49:49 +01:00
parent ab2a08c75a
commit 566fbb4e60
6 changed files with 36 additions and 34 deletions

View file

@ -223,13 +223,11 @@ func pickFolders(opts options, multi bool) (string, []string, error) {
} }
} }
if opts.ctx != nil || opts.windowIcon != nil {
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
defer unhook() defer unhook()
}
err = dialog.Show(owner) err = dialog.Show(owner)
if opts.ctx != nil && opts.ctx.Err() != nil { if opts.ctx != nil && opts.ctx.Err() != nil {
@ -293,13 +291,11 @@ func browseForFolder(opts options) (string, []string, error) {
args.CallbackFunc = syscall.NewCallback(browseForFolderCallback) args.CallbackFunc = syscall.NewCallback(browseForFolderCallback)
} }
if opts.ctx != nil || opts.windowIcon != nil {
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
defer unhook() defer unhook()
}
ptr := win.SHBrowseForFolder(&args) ptr := win.SHBrowseForFolder(&args)
if opts.ctx != nil && opts.ctx.Err() != nil { if opts.ctx != nil && opts.ctx.Err() != nil {

View file

@ -380,7 +380,7 @@ type CWPRETSTRUCT struct {
} }
//sys CallNextHookEx(hk Handle, code int32, wparam uintptr, lparam unsafe.Pointer) (ret uintptr) = user32.CallNextHookEx //sys CallNextHookEx(hk Handle, code int32, wparam uintptr, lparam unsafe.Pointer) (ret uintptr) = user32.CallNextHookEx
//sys CreateIconFromResource(resBits []byte, icon bool, ver uint32) (ret Handle, err error) = user32.CreateIconFromResource //sys CreateIconFromResourceEx(resBits []byte, icon bool, ver uint32, cx int, cy int, flags int) (ret Handle, err error) = user32.CreateIconFromResourceEx
//sys CreateWindowEx(exStyle uint32, className *uint16, windowName *uint16, style uint32, x int, y int, width int, height int, parent HWND, menu Handle, instance Handle, param unsafe.Pointer) (ret HWND, err error) = user32.CreateWindowExW //sys CreateWindowEx(exStyle uint32, className *uint16, windowName *uint16, style uint32, x int, y int, width int, height int, parent HWND, menu Handle, instance Handle, param unsafe.Pointer) (ret HWND, err error) = user32.CreateWindowExW
//sys DefWindowProc(wnd HWND, msg uint32, wparam uintptr, lparam unsafe.Pointer) (ret uintptr) = user32.DefWindowProcW //sys DefWindowProc(wnd HWND, msg uint32, wparam uintptr, lparam unsafe.Pointer) (ret uintptr) = user32.DefWindowProcW
//sys DestroyIcon(icon Handle) (err error) = user32.DestroyIcon //sys DestroyIcon(icon Handle) (err error) = user32.DestroyIcon

View file

@ -70,7 +70,7 @@ var (
procSHGetPathFromIDListEx = modshell32.NewProc("SHGetPathFromIDListEx") procSHGetPathFromIDListEx = modshell32.NewProc("SHGetPathFromIDListEx")
procShell_NotifyIconW = modshell32.NewProc("Shell_NotifyIconW") procShell_NotifyIconW = modshell32.NewProc("Shell_NotifyIconW")
procCallNextHookEx = moduser32.NewProc("CallNextHookEx") procCallNextHookEx = moduser32.NewProc("CallNextHookEx")
procCreateIconFromResource = moduser32.NewProc("CreateIconFromResource") procCreateIconFromResourceEx = moduser32.NewProc("CreateIconFromResourceEx")
procCreateWindowExW = moduser32.NewProc("CreateWindowExW") procCreateWindowExW = moduser32.NewProc("CreateWindowExW")
procDefWindowProcW = moduser32.NewProc("DefWindowProcW") procDefWindowProcW = moduser32.NewProc("DefWindowProcW")
procDestroyIcon = moduser32.NewProc("DestroyIcon") procDestroyIcon = moduser32.NewProc("DestroyIcon")
@ -267,7 +267,7 @@ func CallNextHookEx(hk Handle, code int32, wparam uintptr, lparam unsafe.Pointer
return return
} }
func CreateIconFromResource(resBits []byte, icon bool, ver uint32) (ret Handle, err error) { func CreateIconFromResourceEx(resBits []byte, icon bool, ver uint32, cx int, cy int, flags int) (ret Handle, err error) {
var _p0 *byte var _p0 *byte
if len(resBits) > 0 { if len(resBits) > 0 {
_p0 = &resBits[0] _p0 = &resBits[0]
@ -276,7 +276,7 @@ func CreateIconFromResource(resBits []byte, icon bool, ver uint32) (ret Handle,
if icon { if icon {
_p1 = 1 _p1 = 1
} }
r0, _, e1 := syscall.Syscall6(procCreateIconFromResource.Addr(), 4, uintptr(unsafe.Pointer(_p0)), uintptr(len(resBits)), uintptr(_p1), uintptr(ver), 0, 0) r0, _, e1 := syscall.Syscall9(procCreateIconFromResourceEx.Addr(), 7, uintptr(unsafe.Pointer(_p0)), uintptr(len(resBits)), uintptr(_p1), uintptr(ver), uintptr(cx), uintptr(cy), uintptr(flags), 0, 0)
ret = Handle(r0) ret = Handle(r0)
if ret == 0 { if ret == 0 {
err = errnoErr(e1) err = errnoErr(e1)

View file

@ -82,8 +82,9 @@ func message(kind messageKind, text string, opts options) error {
} }
} }
func hookMessageDialog(opts options) (unhook context.CancelFunc, err error) { func hookMessageDialog(opts options) (context.CancelFunc, error) {
var init func(wnd win.HWND) var init func(wnd win.HWND)
var icon icon
if opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil || opts.icon != nil { if opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil || opts.icon != nil {
init = func(wnd win.HWND) { init = func(wnd win.HWND) {
if opts.okLabel != nil { if opts.okLabel != nil {
@ -97,13 +98,19 @@ func hookMessageDialog(opts options) (unhook context.CancelFunc, err error) {
win.SetDlgItemText(wnd, win.IDNO, strptr(*opts.extraButton)) win.SetDlgItemText(wnd, win.IDNO, strptr(*opts.extraButton))
} }
icon := getIcon(opts.icon)
if icon.handle != 0 { if icon.handle != 0 {
defer icon.delete()
ctl, _ := win.GetDlgItem(wnd, win.IDC_STATIC_OK) ctl, _ := win.GetDlgItem(wnd, win.IDC_STATIC_OK)
win.SendMessage(ctl, win.STM_SETICON, uintptr(icon.handle), 0) win.SendMessage(ctl, win.STM_SETICON, uintptr(icon.handle), 0)
} }
} }
} }
return hookDialog(opts.ctx, opts.windowIcon, nil, init) unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, init)
if err != nil || opts.icon == nil {
return unhook, err
}
icon = getIcon(opts.icon)
return func() {
icon.delete()
unhook()
}, nil
} }

View file

@ -41,7 +41,7 @@ func notify(text string, opts options) error {
icon := getIcon(opts.icon) icon := getIcon(opts.icon)
if icon.handle != 0 { if icon.handle != 0 {
defer icon.delete() defer icon.delete()
args.Icon = win.Handle(icon.handle) args.Icon = icon.handle
args.Flags |= win.NIF_ICON args.Flags |= win.NIF_ICON
args.InfoFlags |= win.NIIF_USER args.InfoFlags |= win.NIIF_USER
} }

View file

@ -75,7 +75,7 @@ func setupEnumCallback(wnd win.HWND, lparam *win.HWND) uintptr {
} }
func hookDialog(ctx context.Context, icon any, title *string, init func(wnd win.HWND)) (unhook context.CancelFunc, err error) { func hookDialog(ctx context.Context, icon any, title *string, init func(wnd win.HWND)) (unhook context.CancelFunc, err error) {
if ctx == nil && icon == nil && init == nil { if ctx == nil && icon == nil && title == nil && init == nil {
return func() {}, nil return func() {}, nil
} }
if ctx != nil && ctx.Err() != nil { if ctx != nil && ctx.Err() != nil {
@ -94,7 +94,7 @@ type dialogHook struct {
wnd uintptr wnd uintptr
hook win.Handle hook win.Handle
done chan struct{} done chan struct{}
icon any icon icon
title *string title *string
init func(wnd win.HWND) init func(wnd win.HWND)
} }
@ -111,7 +111,7 @@ func newDialogHook(ctx context.Context, icon any, title *string, init func(wnd w
ctx: ctx, ctx: ctx,
tid: tid, tid: tid,
hook: hk, hook: hk,
icon: icon, icon: getIcon(icon),
title: title, title: title,
init: init, init: init,
} }
@ -132,12 +132,8 @@ func dialogHookProc(code int32, wparam uintptr, lparam *win.CWPRETSTRUCT) uintpt
if hook.ctx != nil && hook.ctx.Err() != nil { if hook.ctx != nil && hook.ctx.Err() != nil {
win.SendMessage(lparam.Wnd, win.WM_SYSCOMMAND, win.SC_CLOSE, 0) win.SendMessage(lparam.Wnd, win.WM_SYSCOMMAND, win.SC_CLOSE, 0)
} else { } else {
if hook.icon != nil { if hook.icon.handle != 0 {
icon := getIcon(hook.icon) win.SendMessage(lparam.Wnd, win.WM_SETICON, 0, uintptr(hook.icon.handle))
if icon.handle != 0 {
defer icon.delete()
win.SendMessage(lparam.Wnd, win.WM_SETICON, 0, uintptr(icon.handle))
}
} }
if hook.title != nil { if hook.title != nil {
win.SetWindowText(lparam.Wnd, strptr(*hook.title)) win.SetWindowText(lparam.Wnd, strptr(*hook.title))
@ -155,6 +151,7 @@ func (h *dialogHook) unhook() {
if h.done != nil { if h.done != nil {
close(h.done) close(h.done)
} }
h.icon.delete()
win.UnhookWindowsHookEx(h.hook) win.UnhookWindowsHookEx(h.hook)
} }
@ -289,17 +286,19 @@ func getIcon(i any) icon {
res.handle, _ = win.LoadImage(0, res.handle, _ = win.LoadImage(0,
strptr(path), strptr(path),
win.IMAGE_ICON, 0, 0, win.IMAGE_ICON, 0, 0,
win.LR_LOADFROMFILE|win.LR_DEFAULTSIZE|win.LR_SHARED) win.LR_LOADFROMFILE|win.LR_DEFAULTSIZE)
res.destroy = true
case bytes.HasPrefix(data, []byte("\x89PNG\r\n\x1a\n")): case bytes.HasPrefix(data, []byte("\x89PNG\r\n\x1a\n")):
res.handle, err = win.CreateIconFromResource( res.handle, _ = win.CreateIconFromResourceEx(
data, true, 0x00030000) data, true, 0x00030000, 0, 0,
win.LR_DEFAULTSIZE)
res.destroy = true res.destroy = true
} }
return res return res
} }
func (i *icon) delete() { func (i *icon) delete() {
if i.handle != 0 { if i.destroy && i.handle != 0 {
win.DestroyIcon(i.handle) win.DestroyIcon(i.handle)
i.handle = 0 i.handle = 0
} }