Window icons (windows).

This commit is contained in:
Nuno Cruces 2022-05-24 00:12:38 +01:00
parent b988db5bd2
commit 205db7d4be
7 changed files with 48 additions and 23 deletions

View File

@ -38,6 +38,8 @@ func (dlg *calendarDialog) setup(text string, opts options) (time.Time, error) {
defer setup()() defer setup()()
dlg.font = getFont() dlg.font = getFont()
defer dlg.font.delete() defer dlg.font.delete()
icon := getIcon(opts.windowIcon)
defer icon.delete()
if opts.ctx != nil && opts.ctx.Err() != nil { if opts.ctx != nil && opts.ctx.Err() != nil {
return time.Time{}, opts.ctx.Err() return time.Time{}, opts.ctx.Err()
@ -48,7 +50,7 @@ func (dlg *calendarDialog) setup(text string, opts options) (time.Time, error) {
return time.Time{}, err return time.Time{}, err
} }
cls, err := registerClass(instance, syscall.NewCallback(calendarProc)) cls, err := registerClass(instance, icon.handle, syscall.NewCallback(calendarProc))
if cls == 0 { if cls == 0 {
return time.Time{}, err return time.Time{}, err
} }

View File

@ -37,6 +37,8 @@ func (dlg *entryDialog) setup(text string, opts options) (string, error) {
defer setup()() defer setup()()
dlg.font = getFont() dlg.font = getFont()
defer dlg.font.delete() defer dlg.font.delete()
icon := getIcon(opts.windowIcon)
defer icon.delete()
if opts.ctx != nil && opts.ctx.Err() != nil { if opts.ctx != nil && opts.ctx.Err() != nil {
return "", opts.ctx.Err() return "", opts.ctx.Err()
@ -47,7 +49,7 @@ func (dlg *entryDialog) setup(text string, opts options) (string, error) {
return "", err return "", err
} }
cls, err := registerClass(instance, syscall.NewCallback(entryProc)) cls, err := registerClass(instance, icon.handle, syscall.NewCallback(entryProc))
if cls == 0 { if cls == 0 {
return "", err return "", err
} }

View File

@ -54,6 +54,8 @@ func (dlg *listDialog) setup(text string, opts options) ([]string, error) {
defer setup()() defer setup()()
dlg.font = getFont() dlg.font = getFont()
defer dlg.font.delete() defer dlg.font.delete()
icon := getIcon(opts.windowIcon)
defer icon.delete()
if opts.ctx != nil && opts.ctx.Err() != nil { if opts.ctx != nil && opts.ctx.Err() != nil {
return nil, opts.ctx.Err() return nil, opts.ctx.Err()
@ -64,7 +66,7 @@ func (dlg *listDialog) setup(text string, opts options) ([]string, error) {
return nil, err return nil, err
} }
cls, err := registerClass(instance, syscall.NewCallback(listProc)) cls, err := registerClass(instance, icon.handle, syscall.NewCallback(listProc))
if cls == 0 { if cls == 0 {
return nil, err return nil, err
} }

View File

@ -42,6 +42,16 @@ func notify(text string, opts options) error {
args.InfoFlags |= 0x2 // NIIF_WARNING args.InfoFlags |= 0x2 // NIIF_WARNING
case ErrorIcon: case ErrorIcon:
args.InfoFlags |= 0x3 // NIIF_ERROR args.InfoFlags |= 0x3 // NIIF_ERROR
case NoIcon:
//
default:
icon := getIcon(opts.icon)
if icon.handle != 0 {
defer icon.delete()
args.Icon = icon.handle
args.Flags |= 0x00000002 // NIF_ICON
args.InfoFlags |= 0x4 // NIIF_USER
}
} }
runtime.LockOSThread() runtime.LockOSThread()

View File

@ -111,16 +111,14 @@ func (d *progressDialog) Close() error {
} }
func (dlg *progressDialog) setup(opts options) error { func (dlg *progressDialog) setup(opts options) error {
done := false var once sync.Once
defer func() { defer once.Do(dlg.init.Done)
if !done {
dlg.init.Done()
}
}()
defer setup()() defer setup()()
dlg.font = getFont() dlg.font = getFont()
defer dlg.font.delete() defer dlg.font.delete()
icon := getIcon(opts.windowIcon)
defer icon.delete()
if opts.ctx != nil && opts.ctx.Err() != nil { if opts.ctx != nil && opts.ctx.Err() != nil {
return opts.ctx.Err() return opts.ctx.Err()
@ -131,7 +129,7 @@ func (dlg *progressDialog) setup(opts options) error {
return err return err
} }
cls, err := registerClass(instance, syscall.NewCallback(progressProc)) cls, err := registerClass(instance, icon.handle, syscall.NewCallback(progressProc))
if cls == 0 { if cls == 0 {
return err return err
} }
@ -182,8 +180,7 @@ func (dlg *progressDialog) setup(opts options) error {
} else { } else {
sendMessage.Call(dlg.progCtl, _PBM_SETRANGE32, 0, uintptr(opts.maxValue)) sendMessage.Call(dlg.progCtl, _PBM_SETRANGE32, 0, uintptr(opts.maxValue))
} }
dlg.init.Done() once.Do(dlg.init.Done)
done = true
if opts.ctx != nil { if opts.ctx != nil {
wait := make(chan struct{}) wait := make(chan struct{})

View File

@ -47,6 +47,8 @@ func (dlg *passwordDialog) setup(opts options) (string, string, error) {
defer setup()() defer setup()()
dlg.font = getFont() dlg.font = getFont()
defer dlg.font.delete() defer dlg.font.delete()
icon := getIcon(opts.windowIcon)
defer icon.delete()
if opts.ctx != nil && opts.ctx.Err() != nil { if opts.ctx != nil && opts.ctx.Err() != nil {
return "", "", opts.ctx.Err() return "", "", opts.ctx.Err()
@ -57,7 +59,7 @@ func (dlg *passwordDialog) setup(opts options) (string, string, error) {
return "", "", err return "", "", err
} }
cls, err := registerClass(instance, syscall.NewCallback(passwordProc)) cls, err := registerClass(instance, icon.handle, syscall.NewCallback(passwordProc))
if cls == 0 { if cls == 0 {
return "", "", err return "", "", err
} }

View File

@ -180,7 +180,7 @@ type dialogHook struct {
func newDialogHook(ctx context.Context, icon any, title *string, init 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(12, // WH_CALLWNDPROCRET
syscall.NewCallback(dialogHookProc), 0, tid) syscall.NewCallback(dialogHookProc), 0, tid)
if hk == 0 { if hk == 0 {
return nil, err return nil, err
@ -203,31 +203,31 @@ func newDialogHook(ctx context.Context, icon any, title *string, init func(wnd u
return &hook, nil return &hook, nil
} }
func dialogHookProc(code int32, wparam, lparam uintptr) uintptr { func dialogHookProc(code int32, wparam uintptr, lparam *_CWPRETSTRUCT) uintptr {
if code == 5 { // HCBT_ACTIVATE if lparam.Message == 0x0110 { // WM_INITDIALOG
tid, _, _ := getCurrentThreadId.Call() tid, _, _ := getCurrentThreadId.Call()
hook := (*dialogHook)(loadBackRef(tid)) hook := (*dialogHook)(loadBackRef(tid))
atomic.StoreUintptr(&hook.wnd, wparam) atomic.StoreUintptr(&hook.wnd, lparam.Wnd)
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(lparam.Wnd, _WM_SYSCOMMAND, _SC_CLOSE, 0)
} else { } else {
if hook.icon != nil { if hook.icon != nil {
icon := getIcon(hook.icon) icon := getIcon(hook.icon)
if icon.handle != 0 { if icon.handle != 0 {
defer icon.delete() defer icon.delete()
sendMessage.Call(wparam, _WM_SETICON, 0, icon.handle) sendMessage.Call(lparam.Wnd, _WM_SETICON, 0, icon.handle)
} }
} }
if hook.title != nil { if hook.title != nil {
setWindowText.Call(wparam, strptr(*hook.title)) setWindowText.Call(lparam.Wnd, strptr(*hook.title))
} }
if hook.init != nil { if hook.init != nil {
hook.init(wparam) hook.init(lparam.Wnd)
} }
} }
} }
next, _, _ := callNextHookEx.Call( next, _, _ := callNextHookEx.Call(
0, uintptr(code), wparam, lparam) 0, uintptr(code), wparam, uintptr(unsafe.Pointer(lparam)))
return next return next
} }
@ -408,12 +408,13 @@ func getWindowString(wnd uintptr) string {
return syscall.UTF16ToString(buf) return syscall.UTF16ToString(buf)
} }
func registerClass(instance, proc uintptr) (uintptr, error) { func registerClass(instance, icon, proc uintptr) (uintptr, error) {
name := "WC_" + strconv.FormatUint(uint64(proc), 16) name := "WC_" + strconv.FormatUint(uint64(proc), 16)
var wcx _WNDCLASSEX var wcx _WNDCLASSEX
wcx.Size = uint32(unsafe.Sizeof(wcx)) wcx.Size = uint32(unsafe.Sizeof(wcx))
wcx.WndProc = proc wcx.WndProc = proc
wcx.Icon = icon
wcx.Instance = instance wcx.Instance = instance
wcx.Background = 5 // COLOR_WINDOW wcx.Background = 5 // COLOR_WINDOW
wcx.ClassName = syscall.StringToUTF16Ptr(name) wcx.ClassName = syscall.StringToUTF16Ptr(name)
@ -487,6 +488,15 @@ type _INITCOMMONCONTROLSEX struct {
ICC uint32 ICC uint32
} }
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cwpretstruct
type _CWPRETSTRUCT struct {
Result uintptr
LParam uintptr
WParam uintptr
Message uint32
Wnd uintptr
}
// https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logfontw // https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logfontw
type _LOGFONT struct { type _LOGFONT struct {
Height int32 Height int32