Icon from EXE (windows), see #35.
This commit is contained in:
parent
566fbb4e60
commit
fc4cc53c87
10 changed files with 54 additions and 23 deletions
|
@ -41,7 +41,7 @@ func (dlg *calendarDialog) setup(text string, opts options) (time.Time, error) {
|
|||
defer setup(owner)()
|
||||
dlg.font = getFont()
|
||||
defer dlg.font.delete()
|
||||
icon := getIcon(opts.windowIcon)
|
||||
icon, _ := getIcon(opts.windowIcon)
|
||||
defer icon.delete()
|
||||
|
||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||
|
|
|
@ -40,7 +40,7 @@ func (dlg *entryDialog) setup(text string, opts options) (string, error) {
|
|||
defer setup(owner)()
|
||||
dlg.font = getFont()
|
||||
defer dlg.font.delete()
|
||||
icon := getIcon(opts.windowIcon)
|
||||
icon, _ := getIcon(opts.windowIcon)
|
||||
defer icon.delete()
|
||||
|
||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||
|
|
|
@ -284,6 +284,7 @@ func (u *IShellItemArray) GetItemAt(index uint32) (item *IShellItem, err error)
|
|||
return
|
||||
}
|
||||
|
||||
//sys ExtractAssociatedIcon(instance Handle, path *uint16, icon *uint16) (ret Handle, err error) = shell32.ExtractAssociatedIconW
|
||||
//sys SHBrowseForFolder(bi *BROWSEINFO) (ret *IDLIST) = shell32.SHBrowseForFolder
|
||||
//sys SHCreateItemFromParsingName(path *uint16, bc *IBindCtx, iid uintptr, item **IShellItem) (res error) = shell32.SHCreateItemFromParsingName
|
||||
//sys ShellNotifyIcon(message uint32, data *NOTIFYICONDATA) (ok bool) = shell32.Shell_NotifyIconW
|
||||
|
|
|
@ -65,6 +65,7 @@ var (
|
|||
procGlobalFree = modkernel32.NewProc("GlobalFree")
|
||||
procReleaseActCtx = modkernel32.NewProc("ReleaseActCtx")
|
||||
procCoCreateInstance = modole32.NewProc("CoCreateInstance")
|
||||
procExtractAssociatedIconW = modshell32.NewProc("ExtractAssociatedIconW")
|
||||
procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolder")
|
||||
procSHCreateItemFromParsingName = modshell32.NewProc("SHCreateItemFromParsingName")
|
||||
procSHGetPathFromIDListEx = modshell32.NewProc("SHGetPathFromIDListEx")
|
||||
|
@ -235,6 +236,15 @@ func CoCreateInstance(clsid uintptr, unkOuter *IUnknown, clsContext int32, iid u
|
|||
return
|
||||
}
|
||||
|
||||
func ExtractAssociatedIcon(instance Handle, path *uint16, icon *uint16) (ret Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procExtractAssociatedIconW.Addr(), 3, uintptr(instance), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(icon)))
|
||||
ret = Handle(r0)
|
||||
if ret == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SHBrowseForFolder(bi *BROWSEINFO) (ret *IDLIST) {
|
||||
r0, _, _ := syscall.Syscall(procSHBrowseForFolder.Addr(), 1, uintptr(unsafe.Pointer(bi)), 0, 0)
|
||||
ret = (*IDLIST)(unsafe.Pointer(r0))
|
||||
|
|
|
@ -57,7 +57,7 @@ func (dlg *listDialog) setup(text string, opts options) ([]string, error) {
|
|||
defer setup(owner)()
|
||||
dlg.font = getFont()
|
||||
defer dlg.font.delete()
|
||||
icon := getIcon(opts.windowIcon)
|
||||
icon, _ := getIcon(opts.windowIcon)
|
||||
defer icon.delete()
|
||||
|
||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||
|
|
|
@ -104,11 +104,15 @@ func hookMessageDialog(opts options) (context.CancelFunc, error) {
|
|||
}
|
||||
}
|
||||
}
|
||||
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, init)
|
||||
if err != nil || opts.icon == nil {
|
||||
return unhook, err
|
||||
icon, err := getIcon(opts.icon)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, init)
|
||||
if err != nil {
|
||||
icon.delete()
|
||||
return nil, err
|
||||
}
|
||||
icon = getIcon(opts.icon)
|
||||
return func() {
|
||||
icon.delete()
|
||||
unhook()
|
||||
|
|
|
@ -38,7 +38,7 @@ func notify(text string, opts options) error {
|
|||
case ErrorIcon:
|
||||
args.InfoFlags |= win.NIIF_ERROR
|
||||
default:
|
||||
icon := getIcon(opts.icon)
|
||||
icon, _ := getIcon(opts.icon)
|
||||
if icon.handle != 0 {
|
||||
defer icon.delete()
|
||||
args.Icon = icon.handle
|
||||
|
|
|
@ -120,7 +120,7 @@ func (dlg *progressDialog) setup(opts options) error {
|
|||
defer setup(owner)()
|
||||
dlg.font = getFont()
|
||||
defer dlg.font.delete()
|
||||
icon := getIcon(opts.windowIcon)
|
||||
icon, _ := getIcon(opts.windowIcon)
|
||||
defer icon.delete()
|
||||
|
||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||
|
|
|
@ -50,7 +50,7 @@ func (dlg *passwordDialog) setup(opts options) (string, string, error) {
|
|||
defer setup(owner)()
|
||||
dlg.font = getFont()
|
||||
defer dlg.font.delete()
|
||||
icon := getIcon(opts.windowIcon)
|
||||
icon, _ := getIcon(opts.windowIcon)
|
||||
defer icon.delete()
|
||||
|
||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
@ -12,6 +13,7 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"github.com/ncruces/zenity/internal/win"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -106,12 +108,13 @@ func newDialogHook(ctx context.Context, icon any, title *string, init func(wnd w
|
|||
if hk == 0 {
|
||||
return nil, err
|
||||
}
|
||||
ico, _ := getIcon(icon)
|
||||
|
||||
hook := dialogHook{
|
||||
ctx: ctx,
|
||||
tid: tid,
|
||||
hook: hk,
|
||||
icon: getIcon(icon),
|
||||
icon: ico,
|
||||
title: title,
|
||||
init: init,
|
||||
}
|
||||
|
@ -253,8 +256,7 @@ type icon struct {
|
|||
destroy bool
|
||||
}
|
||||
|
||||
func getIcon(i any) icon {
|
||||
var res icon
|
||||
func getIcon(i any) (icon icon, err error) {
|
||||
var resource uintptr
|
||||
switch i {
|
||||
case ErrorIcon:
|
||||
|
@ -267,38 +269,52 @@ func getIcon(i any) icon {
|
|||
resource = win.IDI_INFORMATION
|
||||
}
|
||||
if resource != 0 {
|
||||
res.handle, _ = win.LoadIcon(0, resource)
|
||||
return res
|
||||
icon.handle, err = win.LoadIcon(0, resource)
|
||||
return icon, err
|
||||
}
|
||||
|
||||
path, ok := i.(string)
|
||||
if !ok {
|
||||
return res
|
||||
return icon, nil
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return res
|
||||
return icon, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case bytes.HasPrefix(data, []byte("\x00\x00\x01\x00")):
|
||||
res.handle, _ = win.LoadImage(0,
|
||||
icon.handle, err = win.LoadImage(0,
|
||||
strptr(path),
|
||||
win.IMAGE_ICON, 0, 0,
|
||||
win.LR_LOADFROMFILE|win.LR_DEFAULTSIZE)
|
||||
res.destroy = true
|
||||
icon.destroy = true
|
||||
case bytes.HasPrefix(data, []byte("\x89PNG\r\n\x1a\n")):
|
||||
res.handle, _ = win.CreateIconFromResourceEx(
|
||||
icon.handle, err = win.CreateIconFromResourceEx(
|
||||
data, true, 0x00030000, 0, 0,
|
||||
win.LR_DEFAULTSIZE)
|
||||
res.destroy = true
|
||||
icon.destroy = true
|
||||
case bytes.HasPrefix(data, []byte("MZ")):
|
||||
var instance windows.Handle
|
||||
instance, err = win.GetModuleHandle(nil)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
return res
|
||||
path, err = filepath.Abs(path)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
var i uint16
|
||||
icon.handle, err = win.ExtractAssociatedIcon(
|
||||
instance, strptr(path), &i)
|
||||
icon.destroy = true
|
||||
}
|
||||
return icon, err
|
||||
}
|
||||
|
||||
func (i *icon) delete() {
|
||||
if i.destroy && i.handle != 0 {
|
||||
if i.handle != 0 && i.destroy {
|
||||
win.DestroyIcon(i.handle)
|
||||
i.handle = 0
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue