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()()
|
defer setup()()
|
||||||
|
|
||||||
if opts.ctx != nil || opts.title != nil {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ const (
|
||||||
_WM_DESTROY = 0x0002
|
_WM_DESTROY = 0x0002
|
||||||
_WM_CLOSE = 0x0010
|
_WM_CLOSE = 0x0010
|
||||||
_WM_SETFONT = 0x0030
|
_WM_SETFONT = 0x0030
|
||||||
|
_WM_SETICON = 0x0080
|
||||||
_WM_NCCREATE = 0x0081
|
_WM_NCCREATE = 0x0081
|
||||||
_WM_NCDESTROY = 0x0082
|
_WM_NCDESTROY = 0x0082
|
||||||
_WM_COMMAND = 0x0111
|
_WM_COMMAND = 0x0111
|
||||||
|
@ -74,6 +75,7 @@ const (
|
||||||
_PBM_SETPOS = _WM_USER + 2
|
_PBM_SETPOS = _WM_USER + 2
|
||||||
_PBM_SETRANGE32 = _WM_USER + 6
|
_PBM_SETRANGE32 = _WM_USER + 6
|
||||||
_PBM_SETMARQUEE = _WM_USER + 10
|
_PBM_SETMARQUEE = _WM_USER + 10
|
||||||
|
_STM_SETICON = 0x0170
|
||||||
|
|
||||||
_GWL_STYLE = -16
|
_GWL_STYLE = -16
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,26 @@ var (
|
||||||
getOpenFileName = comdlg32.NewProc("GetOpenFileNameW")
|
getOpenFileName = comdlg32.NewProc("GetOpenFileNameW")
|
||||||
getSaveFileName = comdlg32.NewProc("GetSaveFileNameW")
|
getSaveFileName = comdlg32.NewProc("GetSaveFileNameW")
|
||||||
shBrowseForFolder = shell32.NewProc("SHBrowseForFolderW")
|
shBrowseForFolder = shell32.NewProc("SHBrowseForFolderW")
|
||||||
shGetPathFromIDListEx = shell32.NewProc("SHGetPathFromIDListEx")
|
|
||||||
shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName")
|
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) {
|
func selectFile(opts options) (string, error) {
|
||||||
|
@ -25,13 +43,13 @@ func selectFile(opts options) (string, error) {
|
||||||
|
|
||||||
var args _OPENFILENAME
|
var args _OPENFILENAME
|
||||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
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 {
|
if opts.title != nil {
|
||||||
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||||
}
|
}
|
||||||
if opts.showHidden {
|
if opts.showHidden {
|
||||||
args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN
|
args.Flags |= _OFN_FORCESHOWHIDDEN
|
||||||
}
|
}
|
||||||
if opts.fileFilters != nil {
|
if opts.fileFilters != nil {
|
||||||
args.Filter = &initFilters(opts.fileFilters)[0]
|
args.Filter = &initFilters(opts.fileFilters)[0]
|
||||||
|
@ -45,7 +63,7 @@ func selectFile(opts options) (string, error) {
|
||||||
defer setup()()
|
defer setup()()
|
||||||
|
|
||||||
if opts.ctx != nil {
|
if opts.ctx != nil {
|
||||||
unhook, err := hookDialog(opts.ctx, nil)
|
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -70,13 +88,13 @@ func selectFileMultiple(opts options) ([]string, error) {
|
||||||
|
|
||||||
var args _OPENFILENAME
|
var args _OPENFILENAME
|
||||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
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 {
|
if opts.title != nil {
|
||||||
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||||
}
|
}
|
||||||
if opts.showHidden {
|
if opts.showHidden {
|
||||||
args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN
|
args.Flags |= _OFN_FORCESHOWHIDDEN
|
||||||
}
|
}
|
||||||
if opts.fileFilters != nil {
|
if opts.fileFilters != nil {
|
||||||
args.Filter = &initFilters(opts.fileFilters)[0]
|
args.Filter = &initFilters(opts.fileFilters)[0]
|
||||||
|
@ -90,7 +108,7 @@ func selectFileMultiple(opts options) ([]string, error) {
|
||||||
defer setup()()
|
defer setup()()
|
||||||
|
|
||||||
if opts.ctx != nil {
|
if opts.ctx != nil {
|
||||||
unhook, err := hookDialog(opts.ctx, nil)
|
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -140,19 +158,19 @@ func selectFileSave(opts options) (string, error) {
|
||||||
|
|
||||||
var args _OPENFILENAME
|
var args _OPENFILENAME
|
||||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
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 {
|
if opts.title != nil {
|
||||||
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||||
}
|
}
|
||||||
if opts.confirmOverwrite {
|
if opts.confirmOverwrite {
|
||||||
args.Flags |= 0x2 // OFN_OVERWRITEPROMPT
|
args.Flags |= _OFN_OVERWRITEPROMPT
|
||||||
}
|
}
|
||||||
if opts.confirmCreate {
|
if opts.confirmCreate {
|
||||||
args.Flags |= 0x2000 // OFN_CREATEPROMPT
|
args.Flags |= _OFN_CREATEPROMPT
|
||||||
}
|
}
|
||||||
if opts.showHidden {
|
if opts.showHidden {
|
||||||
args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN
|
args.Flags |= _OFN_FORCESHOWHIDDEN
|
||||||
}
|
}
|
||||||
if opts.fileFilters != nil {
|
if opts.fileFilters != nil {
|
||||||
args.Filter = &initFilters(opts.fileFilters)[0]
|
args.Filter = &initFilters(opts.fileFilters)[0]
|
||||||
|
@ -166,7 +184,7 @@ func selectFileSave(opts options) (string, error) {
|
||||||
defer setup()()
|
defer setup()()
|
||||||
|
|
||||||
if opts.ctx != nil {
|
if opts.ctx != nil {
|
||||||
unhook, err := hookDialog(opts.ctx, nil)
|
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -211,13 +229,14 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
||||||
if int32(hr) < 0 {
|
if int32(hr) < 0 {
|
||||||
return "", nil, syscall.Errno(hr)
|
return "", nil, syscall.Errno(hr)
|
||||||
}
|
}
|
||||||
|
flgs |= _FOS_NOCHANGEDIR | _FOS_PICKFOLDERS | _FOS_FORCEFILESYSTEM
|
||||||
if multi {
|
if multi {
|
||||||
flgs |= 0x200 // FOS_ALLOWMULTISELECT
|
flgs |= _FOS_ALLOWMULTISELECT
|
||||||
}
|
}
|
||||||
if opts.showHidden {
|
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 {
|
if int32(hr) < 0 {
|
||||||
return "", nil, syscall.Errno(hr)
|
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 {
|
if opts.ctx != nil {
|
||||||
unhook, err := hookDialog(opts.ctx, nil)
|
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
@ -320,7 +339,7 @@ func browseForFolder(opts options) (string, []string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.ctx != nil {
|
if opts.ctx != nil {
|
||||||
unhook, err := hookDialog(opts.ctx, nil)
|
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
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) {
|
func hookMessageDialog(kind messageKind, opts options) (unhook context.CancelFunc, err error) {
|
||||||
return hookDialog(opts.ctx, func(wnd uintptr) {
|
return hookDialog(opts.ctx, opts.windowIcon, nil, 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enumChildWindows.Call(wnd,
|
enumChildWindows.Call(wnd,
|
||||||
syscall.NewCallback(hookMessageDialogCallback),
|
syscall.NewCallback(hookMessageDialogCallback),
|
||||||
uintptr(unsafe.Pointer(&opts)))
|
uintptr(unsafe.Pointer(&opts)))
|
||||||
|
@ -122,7 +115,7 @@ func hookMessageDialogCallback(wnd uintptr, lparam *options) uintptr {
|
||||||
icon := getIcon(lparam.icon)
|
icon := getIcon(lparam.icon)
|
||||||
if icon.handle != 0 {
|
if icon.handle != 0 {
|
||||||
defer icon.delete()
|
defer icon.delete()
|
||||||
sendMessage.Call(wnd, 0x0170 /*STM_SETICON*/, icon.handle, 0)
|
sendMessage.Call(wnd, _STM_SETICON, icon.handle, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1
|
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 {
|
if ctx != nil && ctx.Err() != nil {
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
}
|
}
|
||||||
hook, err := newDialogHook(ctx, initDialog)
|
hook, err := newDialogHook(ctx, icon, title, init)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -168,15 +168,17 @@ func hookDialog(ctx context.Context, initDialog func(wnd uintptr)) (unhook conte
|
||||||
}
|
}
|
||||||
|
|
||||||
type dialogHook struct {
|
type dialogHook struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
tid uintptr
|
tid uintptr
|
||||||
wnd uintptr
|
wnd uintptr
|
||||||
hook uintptr
|
hook uintptr
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
init func(wnd uintptr)
|
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()
|
tid, _, _ := getCurrentThreadId.Call()
|
||||||
hk, _, err := setWindowsHookEx.Call(5, // WH_CBT
|
hk, _, err := setWindowsHookEx.Call(5, // WH_CBT
|
||||||
syscall.NewCallback(dialogHookProc), 0, tid)
|
syscall.NewCallback(dialogHookProc), 0, tid)
|
||||||
|
@ -185,10 +187,12 @@ func newDialogHook(ctx context.Context, initDialog func(wnd uintptr)) (*dialogHo
|
||||||
}
|
}
|
||||||
|
|
||||||
hook := dialogHook{
|
hook := dialogHook{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
tid: tid,
|
tid: tid,
|
||||||
hook: hk,
|
hook: hk,
|
||||||
init: initDialog,
|
icon: icon,
|
||||||
|
title: title,
|
||||||
|
init: init,
|
||||||
}
|
}
|
||||||
if ctx != nil {
|
if ctx != nil {
|
||||||
hook.done = make(chan struct{})
|
hook.done = make(chan struct{})
|
||||||
|
@ -206,8 +210,20 @@ func dialogHookProc(code int32, wparam, lparam uintptr) uintptr {
|
||||||
atomic.StoreUintptr(&hook.wnd, wparam)
|
atomic.StoreUintptr(&hook.wnd, wparam)
|
||||||
if hook.ctx != nil && hook.ctx.Err() != nil {
|
if hook.ctx != nil && hook.ctx.Err() != nil {
|
||||||
sendMessage.Call(wparam, _WM_SYSCOMMAND, _SC_CLOSE, 0)
|
sendMessage.Call(wparam, _WM_SYSCOMMAND, _SC_CLOSE, 0)
|
||||||
} else if hook.init != nil {
|
} else {
|
||||||
hook.init(wparam)
|
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(
|
next, _, _ := callNextHookEx.Call(
|
||||||
|
@ -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 {
|
var backRefs struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
m map[uintptr]unsafe.Pointer
|
m map[uintptr]unsafe.Pointer
|
||||||
|
|
Loading…
Reference in a new issue