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