Refactor (windows).

This commit is contained in:
Nuno Cruces 2022-06-23 14:49:08 +01:00
parent 762d54a00d
commit a52a097be2
8 changed files with 77 additions and 92 deletions

View File

@ -42,14 +42,11 @@ func selectColor(opts options) (color.Color, error) {
}
defer setup()()
if opts.ctx != nil || opts.title != nil {
unhook, err := hookDialog(opts.ctx, opts.windowIcon, opts.title, nil)
if err != nil {
return nil, err
}
defer unhook()
unhook, err := hookDialog(opts.ctx, opts.windowIcon, opts.title, nil)
if err != nil {
return nil, err
}
defer unhook()
ok := win.ChooseColor(&args)
if opts.ctx != nil && opts.ctx.Err() != nil {

View File

@ -163,7 +163,7 @@ func entryProc(wnd win.HWND, msg uint32, wparam uintptr, lparam *unsafe.Pointer)
default:
return 1
case win.IDOK, win.IDYES:
dlg.out = getWindowString(dlg.editCtl)
dlg.out = win.GetWindowText(dlg.editCtl)
case win.IDCANCEL:
dlg.err = ErrCanceled
case win.IDNO:

View File

@ -37,14 +37,11 @@ func selectFile(opts options) (string, error) {
args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:])
defer setup()()
if opts.ctx != nil {
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil {
return "", err
}
defer unhook()
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil {
return "", err
}
defer unhook()
ok := win.GetOpenFileName(&args)
if opts.ctx != nil && opts.ctx.Err() != nil {
@ -83,14 +80,11 @@ func selectFileMultiple(opts options) ([]string, error) {
args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:])
defer setup()()
if opts.ctx != nil {
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil {
return nil, err
}
defer unhook()
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil {
return nil, err
}
defer unhook()
ok := win.GetOpenFileName(&args)
if opts.ctx != nil && opts.ctx.Err() != nil {
@ -160,14 +154,11 @@ func selectFileSave(opts options) (string, error) {
args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:])
defer setup()()
if opts.ctx != nil {
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil {
return "", err
}
defer unhook()
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil {
return "", err
}
defer unhook()
ok := win.GetSaveFileName(&args)
if opts.ctx != nil && opts.ctx.Err() != nil {
@ -231,7 +222,7 @@ func pickFolders(opts options, multi bool) (string, []string, error) {
}
}
if opts.ctx != nil {
if opts.ctx != nil || opts.windowIcon != nil {
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil {
return "", nil, err
@ -302,7 +293,7 @@ func browseForFolder(opts options) (string, []string, error) {
args.CallbackFunc = syscall.NewCallback(browseForFolderCallback)
}
if opts.ctx != nil {
if opts.ctx != nil || opts.windowIcon != nil {
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil {
return "", nil, err

View File

@ -268,6 +268,13 @@ func GetWindowThreadProcessId(hwnd HWND, pid *uint32) (tid uint32, err error) {
return windows.GetWindowThreadProcessId(hwnd, pid)
}
func GetWindowText(wnd HWND) string {
len, _ := getWindowTextLength(wnd)
buf := make([]uint16, len+1)
getWindowText(wnd, &buf[0], len+1)
return syscall.UTF16ToString(buf)
}
func SendMessagePointer(wnd HWND, msg uint32, wparam uintptr, lparam unsafe.Pointer) (ret uintptr) {
r0, _, _ := syscall.Syscall6(procSendMessageW.Addr(), 4, uintptr(wnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
ret = uintptr(r0)
@ -389,16 +396,15 @@ type CWPRETSTRUCT struct {
//sys DestroyWindow(wnd HWND) (err error) = user32.DestroyWindow
//sys DispatchMessage(msg *MSG) (ret uintptr) = user32.DispatchMessageW
//sys EnableWindow(wnd HWND, enable bool) (ok bool) = user32.EnableWindow
//sys EnumChildWindows(parent HWND, enumFunc uintptr, lparam unsafe.Pointer) = user32.EnumChildWindows
//sys EnumWindows(enumFunc uintptr, lparam unsafe.Pointer) (err error) = user32.EnumChildWindows
//sys GetDlgCtrlID(wnd HWND) (ret int) = user32.GetDlgCtrlID
//sys GetDlgItem(dlg HWND, dlgItemID int) (ret HWND, err error) = user32.GetDlgItem
//sys getDpiForWindow(wnd HWND) (ret int) = user32.GetDpiForWindow
//sys GetMessage(msg *MSG, wnd HWND, msgFilterMin uint32, msgFilterMax uint32) (ret uintptr) = user32.GetMessageW
//sys GetSystemMetrics(index int) (ret int) = user32.GetSystemMetrics
//sys GetWindowDC(wnd HWND) (ret Handle) = user32.GetWindowDC
//sys GetWindowRect(wnd HWND, cmdShow *RECT) (err error) = user32.GetWindowRect
//sys GetWindowText(wnd HWND, str *uint16, maxCount int) (ret int, err error) = user32.GetWindowTextW
//sys GetWindowTextLength(wnd HWND) (ret int, err error) = user32.GetWindowTextLengthW
//sys getWindowText(wnd HWND, str *uint16, maxCount int) (ret int, err error) = user32.GetWindowTextW
//sys getWindowTextLength(wnd HWND) (ret int, err error) = user32.GetWindowTextLengthW
//sys IsDialogMessage(wnd HWND, msg *MSG) (ok bool) = user32.IsDialogMessageW
//sys LoadIcon(instance Handle, resource uintptr) (ret Handle, err error) = user32.LoadIconW
//sys LoadImage(instance Handle, name *uint16, typ int, cx int, cy int, load int) (ret Handle, err error) = user32.LoadImageW
@ -406,6 +412,7 @@ type CWPRETSTRUCT struct {
//sys RegisterClassEx(cls *WNDCLASSEX) (err error) = user32.RegisterClassExW
//sys ReleaseDC(wnd HWND, dc Handle) (ok bool) = user32.ReleaseDC
//sys SendMessage(wnd HWND, msg uint32, wparam uintptr, lparam uintptr) (ret uintptr) = user32.SendMessageW
//sys SetDlgItemText(dlg HWND, dlgItemID int, str *uint16) (err error) = user32.SetDlgItemTextW
//sys SetFocus(wnd HWND) (ret HWND, err error) = user32.SetFocus
//sys SetForegroundWindow(wnd HWND) (ok bool) = user32.SetForegroundWindow
//sys setThreadDpiAwarenessContext(dpiContext uintptr) (ret uintptr) = user32.SetThreadDpiAwarenessContext

View File

@ -75,7 +75,7 @@ var (
procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
procEnableWindow = moduser32.NewProc("EnableWindow")
procEnumChildWindows = moduser32.NewProc("EnumChildWindows")
procGetDlgCtrlID = moduser32.NewProc("GetDlgCtrlID")
procGetDlgItem = moduser32.NewProc("GetDlgItem")
procGetDpiForWindow = moduser32.NewProc("GetDpiForWindow")
procGetMessageW = moduser32.NewProc("GetMessageW")
procGetSystemMetrics = moduser32.NewProc("GetSystemMetrics")
@ -90,6 +90,7 @@ var (
procRegisterClassExW = moduser32.NewProc("RegisterClassExW")
procReleaseDC = moduser32.NewProc("ReleaseDC")
procSendMessageW = moduser32.NewProc("SendMessageW")
procSetDlgItemTextW = moduser32.NewProc("SetDlgItemTextW")
procSetFocus = moduser32.NewProc("SetFocus")
procSetForegroundWindow = moduser32.NewProc("SetForegroundWindow")
procSetThreadDpiAwarenessContext = moduser32.NewProc("SetThreadDpiAwarenessContext")
@ -305,11 +306,6 @@ func EnableWindow(wnd HWND, enable bool) (ok bool) {
return
}
func EnumChildWindows(parent HWND, enumFunc uintptr, lparam unsafe.Pointer) {
syscall.Syscall(procEnumChildWindows.Addr(), 3, uintptr(parent), uintptr(enumFunc), uintptr(lparam))
return
}
func EnumWindows(enumFunc uintptr, lparam unsafe.Pointer) (err error) {
r1, _, e1 := syscall.Syscall(procEnumChildWindows.Addr(), 2, uintptr(enumFunc), uintptr(lparam), 0)
if r1 == 0 {
@ -318,9 +314,12 @@ func EnumWindows(enumFunc uintptr, lparam unsafe.Pointer) (err error) {
return
}
func GetDlgCtrlID(wnd HWND) (ret int) {
r0, _, _ := syscall.Syscall(procGetDlgCtrlID.Addr(), 1, uintptr(wnd), 0, 0)
ret = int(r0)
func GetDlgItem(dlg HWND, dlgItemID int) (ret HWND, err error) {
r0, _, e1 := syscall.Syscall(procGetDlgItem.Addr(), 2, uintptr(dlg), uintptr(dlgItemID), 0)
ret = HWND(r0)
if ret == 0 {
err = errnoErr(e1)
}
return
}
@ -356,7 +355,7 @@ func GetWindowRect(wnd HWND, cmdShow *RECT) (err error) {
return
}
func GetWindowTextLength(wnd HWND) (ret int, err error) {
func getWindowTextLength(wnd HWND) (ret int, err error) {
r0, _, e1 := syscall.Syscall(procGetWindowTextLengthW.Addr(), 1, uintptr(wnd), 0, 0)
ret = int(r0)
if ret == 0 {
@ -365,7 +364,7 @@ func GetWindowTextLength(wnd HWND) (ret int, err error) {
return
}
func GetWindowText(wnd HWND, str *uint16, maxCount int) (ret int, err error) {
func getWindowText(wnd HWND, str *uint16, maxCount int) (ret int, err error) {
r0, _, e1 := syscall.Syscall(procGetWindowTextW.Addr(), 3, uintptr(wnd), uintptr(unsafe.Pointer(str)), uintptr(maxCount))
ret = int(r0)
if ret == 0 {
@ -423,6 +422,14 @@ func SendMessage(wnd HWND, msg uint32, wparam uintptr, lparam uintptr) (ret uint
return
}
func SetDlgItemText(dlg HWND, dlgItemID int, str *uint16) (err error) {
r1, _, e1 := syscall.Syscall(procSetDlgItemTextW.Addr(), 3, uintptr(dlg), uintptr(dlgItemID), uintptr(unsafe.Pointer(str)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetFocus(wnd HWND) (ret HWND, err error) {
r0, _, e1 := syscall.Syscall(procSetFocus.Addr(), 1, uintptr(wnd), 0, 0)
ret = HWND(r0)

View File

@ -2,8 +2,6 @@ package zenity
import (
"context"
"syscall"
"unsafe"
"github.com/ncruces/zenity/internal/win"
)
@ -55,14 +53,11 @@ func message(kind messageKind, text string, opts options) error {
}
defer setup()()
if opts.ctx != nil || opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil || opts.icon != nil {
unhook, err := hookMessageDialog(opts)
if err != nil {
return err
}
defer unhook()
unhook, err := hookMessageDialog(opts)
if err != nil {
return err
}
defer unhook()
var title *uint16
if opts.title != nil {
@ -88,35 +83,27 @@ func message(kind messageKind, text string, opts options) error {
}
func hookMessageDialog(opts options) (unhook context.CancelFunc, err error) {
// TODO: use GetDlgItem, SetDlgItemText instead of EnumChildWindows.
return hookDialog(opts.ctx, opts.windowIcon, nil, func(wnd win.HWND) {
win.EnumChildWindows(wnd, syscall.NewCallback(hookMessageDialogCallback),
unsafe.Pointer(&opts))
})
}
var init func(wnd win.HWND)
if opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil || opts.icon != nil {
init = func(wnd win.HWND) {
if opts.okLabel != nil {
win.SetDlgItemText(wnd, win.IDOK, strptr(*opts.okLabel))
win.SetDlgItemText(wnd, win.IDYES, strptr(*opts.okLabel))
}
if opts.cancelLabel != nil {
win.SetDlgItemText(wnd, win.IDCANCEL, strptr(*opts.cancelLabel))
}
if opts.extraButton != nil {
win.SetDlgItemText(wnd, win.IDNO, strptr(*opts.extraButton))
}
func hookMessageDialogCallback(wnd win.HWND, lparam *options) uintptr {
ctl := win.GetDlgCtrlID(wnd)
var text *string
switch ctl {
case win.IDOK, win.IDYES:
text = lparam.okLabel
case win.IDCANCEL:
text = lparam.cancelLabel
case win.IDNO:
text = lparam.extraButton
}
if text != nil {
win.SetWindowText(wnd, strptr(*text))
}
if ctl == win.IDC_STATIC_OK {
icon := getIcon(lparam.icon)
if icon.handle != 0 {
defer icon.delete()
win.SendMessage(wnd, win.STM_SETICON, uintptr(icon.handle), 0)
icon := getIcon(opts.icon)
if icon.handle != 0 {
defer icon.delete()
ctl, _ := win.GetDlgItem(wnd, win.IDC_STATIC_OK)
win.SendMessage(ctl, win.STM_SETICON, uintptr(icon.handle), 0)
}
}
}
return 1
return hookDialog(opts.ctx, opts.windowIcon, nil, init)
}

View File

@ -183,8 +183,8 @@ func passwordProc(wnd win.HWND, msg uint32, wparam uintptr, lparam *unsafe.Point
default:
return 1
case win.IDOK, win.IDYES:
dlg.usr = getWindowString(dlg.uEditCtl)
dlg.pwd = getWindowString(dlg.pEditCtl)
dlg.usr = win.GetWindowText(dlg.uEditCtl)
dlg.pwd = win.GetWindowText(dlg.pEditCtl)
case win.IDCANCEL:
dlg.err = ErrCanceled
case win.IDNO:

View File

@ -79,6 +79,9 @@ func setupEnumCallback(wnd win.HWND, lparam *win.HWND) uintptr {
}
func hookDialog(ctx context.Context, icon any, title *string, init func(wnd win.HWND)) (unhook context.CancelFunc, err error) {
if ctx == nil && icon == nil && init == nil {
return func() {}, nil
}
if ctx != nil && ctx.Err() != nil {
return nil, ctx.Err()
}
@ -314,13 +317,6 @@ func centerWindow(wnd win.HWND) {
win.SetWindowPos(wnd, 0, x/2, y/2, 0, 0, win.SWP_NOZORDER|win.SWP_NOSIZE)
}
func getWindowString(wnd win.HWND) string {
len, _ := win.GetWindowTextLength(wnd)
buf := make([]uint16, len+1)
win.GetWindowText(wnd, &buf[0], len+1)
return syscall.UTF16ToString(buf)
}
func registerClass(instance, icon win.Handle, proc uintptr) (*uint16, error) {
name := "WC_" + strconv.FormatUint(uint64(proc), 16)