Window icons (windows).
This commit is contained in:
parent
af8627dee2
commit
b988db5bd2
5 changed files with 72 additions and 52 deletions
|
@ -49,7 +49,7 @@ func selectColor(opts options) (color.Color, error) {
|
|||
defer setup()()
|
||||
|
||||
if opts.ctx != nil || opts.title != nil {
|
||||
unhook, err := hookDialogTitle(opts.ctx, opts.title)
|
||||
unhook, err := hookDialog(opts.ctx, opts.windowIcon, opts.title, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ const (
|
|||
_WM_DESTROY = 0x0002
|
||||
_WM_CLOSE = 0x0010
|
||||
_WM_SETFONT = 0x0030
|
||||
_WM_SETICON = 0x0080
|
||||
_WM_NCCREATE = 0x0081
|
||||
_WM_NCDESTROY = 0x0082
|
||||
_WM_COMMAND = 0x0111
|
||||
|
@ -74,6 +75,7 @@ const (
|
|||
_PBM_SETPOS = _WM_USER + 2
|
||||
_PBM_SETRANGE32 = _WM_USER + 6
|
||||
_PBM_SETMARQUEE = _WM_USER + 10
|
||||
_STM_SETICON = 0x0170
|
||||
|
||||
_GWL_STYLE = -16
|
||||
|
||||
|
|
|
@ -13,8 +13,26 @@ var (
|
|||
getOpenFileName = comdlg32.NewProc("GetOpenFileNameW")
|
||||
getSaveFileName = comdlg32.NewProc("GetSaveFileNameW")
|
||||
shBrowseForFolder = shell32.NewProc("SHBrowseForFolderW")
|
||||
shGetPathFromIDListEx = shell32.NewProc("SHGetPathFromIDListEx")
|
||||
shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName")
|
||||
shGetPathFromIDListEx = shell32.NewProc("SHGetPathFromIDListEx")
|
||||
)
|
||||
|
||||
const (
|
||||
_OFN_OVERWRITEPROMPT = 0x00000002
|
||||
_OFN_NOCHANGEDIR = 0x00000008
|
||||
_OFN_ALLOWMULTISELECT = 0x00000200
|
||||
_OFN_PATHMUSTEXIST = 0x00000800
|
||||
_OFN_FILEMUSTEXIST = 0x00001000
|
||||
_OFN_CREATEPROMPT = 0x00002000
|
||||
_OFN_NOREADONLYRETURN = 0x00008000
|
||||
_OFN_EXPLORER = 0x00080000
|
||||
_OFN_FORCESHOWHIDDEN = 0x10000000
|
||||
|
||||
_FOS_NOCHANGEDIR = 0x00000008
|
||||
_FOS_PICKFOLDERS = 0x00000020
|
||||
_FOS_FORCEFILESYSTEM = 0x00000040
|
||||
_FOS_ALLOWMULTISELECT = 0x00000200
|
||||
_FOS_FORCESHOWHIDDEN = 0x10000000
|
||||
)
|
||||
|
||||
func selectFile(opts options) (string, error) {
|
||||
|
@ -25,13 +43,13 @@ func selectFile(opts options) (string, error) {
|
|||
|
||||
var args _OPENFILENAME
|
||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||
args.Flags = 0x81008 // OFN_NOCHANGEDIR|OFN_FILEMUSTEXIST|OFN_EXPLORER
|
||||
args.Flags = _OFN_NOCHANGEDIR | _OFN_FILEMUSTEXIST | _OFN_EXPLORER
|
||||
|
||||
if opts.title != nil {
|
||||
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||
}
|
||||
if opts.showHidden {
|
||||
args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN
|
||||
args.Flags |= _OFN_FORCESHOWHIDDEN
|
||||
}
|
||||
if opts.fileFilters != nil {
|
||||
args.Filter = &initFilters(opts.fileFilters)[0]
|
||||
|
@ -45,7 +63,7 @@ func selectFile(opts options) (string, error) {
|
|||
defer setup()()
|
||||
|
||||
if opts.ctx != nil {
|
||||
unhook, err := hookDialog(opts.ctx, nil)
|
||||
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -70,13 +88,13 @@ func selectFileMultiple(opts options) ([]string, error) {
|
|||
|
||||
var args _OPENFILENAME
|
||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||
args.Flags = 0x81208 // OFN_NOCHANGEDIR|OFN_ALLOWMULTISELECT|OFN_FILEMUSTEXIST|OFN_EXPLORER
|
||||
args.Flags = _OFN_NOCHANGEDIR | _OFN_ALLOWMULTISELECT | _OFN_FILEMUSTEXIST | _OFN_EXPLORER
|
||||
|
||||
if opts.title != nil {
|
||||
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||
}
|
||||
if opts.showHidden {
|
||||
args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN
|
||||
args.Flags |= _OFN_FORCESHOWHIDDEN
|
||||
}
|
||||
if opts.fileFilters != nil {
|
||||
args.Filter = &initFilters(opts.fileFilters)[0]
|
||||
|
@ -90,7 +108,7 @@ func selectFileMultiple(opts options) ([]string, error) {
|
|||
defer setup()()
|
||||
|
||||
if opts.ctx != nil {
|
||||
unhook, err := hookDialog(opts.ctx, nil)
|
||||
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -140,19 +158,19 @@ func selectFileSave(opts options) (string, error) {
|
|||
|
||||
var args _OPENFILENAME
|
||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||
args.Flags = 0x88808 // OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST|OFN_NOREADONLYRETURN|OFN_EXPLORER
|
||||
args.Flags = _OFN_NOCHANGEDIR | _OFN_PATHMUSTEXIST | _OFN_NOREADONLYRETURN | _OFN_EXPLORER
|
||||
|
||||
if opts.title != nil {
|
||||
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||
}
|
||||
if opts.confirmOverwrite {
|
||||
args.Flags |= 0x2 // OFN_OVERWRITEPROMPT
|
||||
args.Flags |= _OFN_OVERWRITEPROMPT
|
||||
}
|
||||
if opts.confirmCreate {
|
||||
args.Flags |= 0x2000 // OFN_CREATEPROMPT
|
||||
args.Flags |= _OFN_CREATEPROMPT
|
||||
}
|
||||
if opts.showHidden {
|
||||
args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN
|
||||
args.Flags |= _OFN_FORCESHOWHIDDEN
|
||||
}
|
||||
if opts.fileFilters != nil {
|
||||
args.Filter = &initFilters(opts.fileFilters)[0]
|
||||
|
@ -166,7 +184,7 @@ func selectFileSave(opts options) (string, error) {
|
|||
defer setup()()
|
||||
|
||||
if opts.ctx != nil {
|
||||
unhook, err := hookDialog(opts.ctx, nil)
|
||||
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -211,13 +229,14 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
|||
if int32(hr) < 0 {
|
||||
return "", nil, syscall.Errno(hr)
|
||||
}
|
||||
flgs |= _FOS_NOCHANGEDIR | _FOS_PICKFOLDERS | _FOS_FORCEFILESYSTEM
|
||||
if multi {
|
||||
flgs |= 0x200 // FOS_ALLOWMULTISELECT
|
||||
flgs |= _FOS_ALLOWMULTISELECT
|
||||
}
|
||||
if opts.showHidden {
|
||||
flgs |= 0x10000000 // FOS_FORCESHOWHIDDEN
|
||||
flgs |= _FOS_FORCESHOWHIDDEN
|
||||
}
|
||||
hr, _, _ = dialog.Call(dialog.SetOptions, uintptr(flgs|0x68)) // FOS_NOCHANGEDIR|FOS_PICKFOLDERS|FOS_FORCEFILESYSTEM
|
||||
hr, _, _ = dialog.Call(dialog.SetOptions, uintptr(flgs))
|
||||
if int32(hr) < 0 {
|
||||
return "", nil, syscall.Errno(hr)
|
||||
}
|
||||
|
@ -242,7 +261,7 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
|||
}
|
||||
|
||||
if opts.ctx != nil {
|
||||
unhook, err := hookDialog(opts.ctx, nil)
|
||||
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -320,7 +339,7 @@ func browseForFolder(opts options) (string, []string, error) {
|
|||
}
|
||||
|
||||
if opts.ctx != nil {
|
||||
unhook, err := hookDialog(opts.ctx, nil)
|
||||
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
|
|
@ -88,14 +88,7 @@ func message(kind messageKind, text string, opts options) error {
|
|||
}
|
||||
|
||||
func hookMessageDialog(kind messageKind, opts options) (unhook context.CancelFunc, err error) {
|
||||
return hookDialog(opts.ctx, func(wnd uintptr) {
|
||||
if opts.windowIcon != nil {
|
||||
icon := getIcon(opts.windowIcon)
|
||||
if icon.handle != 0 {
|
||||
defer icon.delete()
|
||||
sendMessage.Call(wnd, 0x0080 /*WM_SETICON*/, 0, icon.handle)
|
||||
}
|
||||
}
|
||||
return hookDialog(opts.ctx, opts.windowIcon, nil, func(wnd uintptr) {
|
||||
enumChildWindows.Call(wnd,
|
||||
syscall.NewCallback(hookMessageDialogCallback),
|
||||
uintptr(unsafe.Pointer(&opts)))
|
||||
|
@ -122,7 +115,7 @@ func hookMessageDialogCallback(wnd uintptr, lparam *options) uintptr {
|
|||
icon := getIcon(lparam.icon)
|
||||
if icon.handle != 0 {
|
||||
defer icon.delete()
|
||||
sendMessage.Call(wnd, 0x0170 /*STM_SETICON*/, icon.handle, 0)
|
||||
sendMessage.Call(wnd, _STM_SETICON, icon.handle, 0)
|
||||
}
|
||||
}
|
||||
return 1
|
||||
|
|
|
@ -156,11 +156,11 @@ func commDlgError() error {
|
|||
}
|
||||
}
|
||||
|
||||
func hookDialog(ctx context.Context, initDialog func(wnd uintptr)) (unhook context.CancelFunc, err error) {
|
||||
func hookDialog(ctx context.Context, icon any, title *string, init func(wnd uintptr)) (unhook context.CancelFunc, err error) {
|
||||
if ctx != nil && ctx.Err() != nil {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
hook, err := newDialogHook(ctx, initDialog)
|
||||
hook, err := newDialogHook(ctx, icon, title, init)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -173,10 +173,12 @@ type dialogHook struct {
|
|||
wnd uintptr
|
||||
hook uintptr
|
||||
done chan struct{}
|
||||
icon any
|
||||
title *string
|
||||
init func(wnd uintptr)
|
||||
}
|
||||
|
||||
func newDialogHook(ctx context.Context, initDialog func(wnd uintptr)) (*dialogHook, error) {
|
||||
func newDialogHook(ctx context.Context, icon any, title *string, init func(wnd uintptr)) (*dialogHook, error) {
|
||||
tid, _, _ := getCurrentThreadId.Call()
|
||||
hk, _, err := setWindowsHookEx.Call(5, // WH_CBT
|
||||
syscall.NewCallback(dialogHookProc), 0, tid)
|
||||
|
@ -188,7 +190,9 @@ func newDialogHook(ctx context.Context, initDialog func(wnd uintptr)) (*dialogHo
|
|||
ctx: ctx,
|
||||
tid: tid,
|
||||
hook: hk,
|
||||
init: initDialog,
|
||||
icon: icon,
|
||||
title: title,
|
||||
init: init,
|
||||
}
|
||||
if ctx != nil {
|
||||
hook.done = make(chan struct{})
|
||||
|
@ -206,10 +210,22 @@ func dialogHookProc(code int32, wparam, lparam uintptr) uintptr {
|
|||
atomic.StoreUintptr(&hook.wnd, wparam)
|
||||
if hook.ctx != nil && hook.ctx.Err() != nil {
|
||||
sendMessage.Call(wparam, _WM_SYSCOMMAND, _SC_CLOSE, 0)
|
||||
} else if hook.init != nil {
|
||||
} else {
|
||||
if hook.icon != nil {
|
||||
icon := getIcon(hook.icon)
|
||||
if icon.handle != 0 {
|
||||
defer icon.delete()
|
||||
sendMessage.Call(wparam, _WM_SETICON, 0, icon.handle)
|
||||
}
|
||||
}
|
||||
if hook.title != nil {
|
||||
setWindowText.Call(wparam, strptr(*hook.title))
|
||||
}
|
||||
if hook.init != nil {
|
||||
hook.init(wparam)
|
||||
}
|
||||
}
|
||||
}
|
||||
next, _, _ := callNextHookEx.Call(
|
||||
0, uintptr(code), wparam, lparam)
|
||||
return next
|
||||
|
@ -233,16 +249,6 @@ func (h *dialogHook) wait() {
|
|||
}
|
||||
}
|
||||
|
||||
func hookDialogTitle(ctx context.Context, title *string) (unhook context.CancelFunc, err error) {
|
||||
var init func(wnd uintptr)
|
||||
if title != nil {
|
||||
init = func(wnd uintptr) {
|
||||
setWindowText.Call(wnd, strptr(*title))
|
||||
}
|
||||
}
|
||||
return hookDialog(ctx, init)
|
||||
}
|
||||
|
||||
var backRefs struct {
|
||||
sync.Mutex
|
||||
m map[uintptr]unsafe.Pointer
|
||||
|
|
Loading…
Reference in a new issue