From d47150a866ec2e8b71cfd98f142e758ed5a6bf24 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Sat, 18 Jun 2022 12:37:39 +0100 Subject: [PATCH] Refactor (windows). --- color_windows.go | 2 +- const_windows.go | 16 ---------- date_windows.go | 18 ++++++----- entry_windows.go | 18 ++++++----- file_windows.go | 12 +++---- internal/win/comdlg32.go | 8 ++--- internal/win/gdi32.go | 30 ++++++++++++++++++ internal/win/{pkg.go => generate.go} | 7 +++-- internal/win/shell32.go | 10 +++--- internal/win/user32.go | 34 ++++++++++++++++++++ internal/win/win32.go | 9 ++++++ internal/win/zsyscall_windows.go | 22 +++++++++++++ internal/zenutil/osa_generate.go | 3 -- internal/zenutil/osa_generated.go | 1 + internal/zenutil/osa_generator.go | 5 ++- internal/zenutil/window_windows.go | 10 ++++-- list_windows.go | 18 ++++++----- msg_windows.go | 47 ++++++++++++++-------------- notify_windows.go | 10 +++--- progress_windows.go | 18 ++++++----- pwd_windows.go | 18 ++++++----- util_unix.go | 2 ++ util_windows.go | 47 ++++++++-------------------- zenity.go | 2 +- 24 files changed, 222 insertions(+), 145 deletions(-) create mode 100644 internal/win/gdi32.go rename internal/win/{pkg.go => generate.go} (52%) create mode 100644 internal/win/user32.go create mode 100644 internal/win/win32.go delete mode 100644 internal/zenutil/osa_generate.go diff --git a/color_windows.go b/color_windows.go index 1394616..32306fb 100644 --- a/color_windows.go +++ b/color_windows.go @@ -27,7 +27,7 @@ func selectColor(opts options) (color.Color, error) { var args win.CHOOSECOLOR args.StructSize = uint32(unsafe.Sizeof(args)) - args.Owner, _ = opts.attach.(uintptr) + args.Owner, _ = opts.attach.(win.HWND) args.CustColors = &customColors if opts.color != nil { diff --git a/const_windows.go b/const_windows.go index 318fd12..cba0578 100644 --- a/const_windows.go +++ b/const_windows.go @@ -37,22 +37,6 @@ const ( _SWP_NOMOVE = 0x0002 _SWP_NOZORDER = 0x0004 - _MB_OKCANCEL = 0x00000001 - _MB_YESNOCANCEL = 0x00000003 - _MB_YESNO = 0x00000004 - _MB_ICONERROR = 0x00000010 - _MB_ICONQUESTION = 0x00000020 - _MB_ICONWARNING = 0x00000030 - _MB_ICONINFORMATION = 0x00000040 - _MB_DEFBUTTON1 = 0x00000000 - _MB_DEFBUTTON2 = 0x00000100 - _MB_DEFBUTTON3 = 0x00000200 - - _IDOK = 1 - _IDCANCEL = 2 - _IDYES = 6 - _IDNO = 7 - _SC_CLOSE = 0xf060 _WM_DESTROY = 0x0002 diff --git a/date_windows.go b/date_windows.go index 82ee7b6..043f19f 100644 --- a/date_windows.go +++ b/date_windows.go @@ -4,6 +4,8 @@ import ( "syscall" "time" "unsafe" + + "github.com/ncruces/zenity/internal/win" ) func calendar(text string, opts options) (time.Time, error) { @@ -56,12 +58,12 @@ func (dlg *calendarDialog) setup(text string, opts options) (time.Time, error) { } defer unregisterClass.Call(cls, instance) - owner, _ := opts.attach.(uintptr) + owner, _ := opts.attach.(win.HWND) dlg.wnd, _, _ = createWindowEx.Call(_WS_EX_CONTROLPARENT|_WS_EX_WINDOWEDGE|_WS_EX_DLGMODALFRAME, cls, strptr(*opts.title), _WS_POPUPWINDOW|_WS_CLIPSIBLINGS|_WS_DLGFRAME, _CW_USEDEFAULT, _CW_USEDEFAULT, - 281, 281, owner, 0, instance, uintptr(unsafe.Pointer(dlg))) + 281, 281, uintptr(owner), 0, instance, uintptr(unsafe.Pointer(dlg))) dlg.textCtl, _, _ = createWindowEx.Call(0, strptr("STATIC"), strptr(text), @@ -77,16 +79,16 @@ func (dlg *calendarDialog) setup(text string, opts options) (time.Time, error) { dlg.okBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.okLabel), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP|_BS_DEFPUSHBUTTON, - 12, 206, 75, 24, dlg.wnd, _IDOK, instance, 0) + 12, 206, 75, 24, dlg.wnd, win.IDOK, instance, 0) dlg.cancelBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.cancelLabel), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP, - 12, 206, 75, 24, dlg.wnd, _IDCANCEL, instance, 0) + 12, 206, 75, 24, dlg.wnd, win.IDCANCEL, instance, 0) if opts.extraButton != nil { dlg.extraBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.extraButton), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP, - 12, 206, 75, 24, dlg.wnd, _IDNO, instance, 0) + 12, 206, 75, 24, dlg.wnd, win.IDNO, instance, 0) } if opts.time != nil { @@ -168,13 +170,13 @@ func calendarProc(wnd uintptr, msg uint32, wparam uintptr, lparam *unsafe.Pointe switch wparam { default: return 1 - case _IDOK, _IDYES: + case win.IDOK, win.IDYES: var date _SYSTEMTIME sendMessage.Call(dlg.dateCtl, _MCM_GETCURSEL, 0, uintptr(unsafe.Pointer(&date))) dlg.out = time.Date(int(date.year), time.Month(date.month), int(date.day), 0, 0, 0, 0, time.UTC) - case _IDCANCEL: + case win.IDCANCEL: dlg.err = ErrCanceled - case _IDNO: + case win.IDNO: dlg.err = ErrExtraButton } destroyWindow.Call(wnd) diff --git a/entry_windows.go b/entry_windows.go index 216bd63..6d09cb1 100644 --- a/entry_windows.go +++ b/entry_windows.go @@ -3,6 +3,8 @@ package zenity import ( "syscall" "unsafe" + + "github.com/ncruces/zenity/internal/win" ) func entry(text string, opts options) (string, error) { @@ -55,12 +57,12 @@ func (dlg *entryDialog) setup(text string, opts options) (string, error) { } defer unregisterClass.Call(cls, instance) - owner, _ := opts.attach.(uintptr) + owner, _ := opts.attach.(win.HWND) dlg.wnd, _, _ = createWindowEx.Call(_WS_EX_CONTROLPARENT|_WS_EX_WINDOWEDGE|_WS_EX_DLGMODALFRAME, cls, strptr(*opts.title), _WS_POPUPWINDOW|_WS_CLIPSIBLINGS|_WS_DLGFRAME, _CW_USEDEFAULT, _CW_USEDEFAULT, - 281, 141, owner, 0, instance, uintptr(unsafe.Pointer(dlg))) + 281, 141, uintptr(owner), 0, instance, uintptr(unsafe.Pointer(dlg))) dlg.textCtl, _, _ = createWindowEx.Call(0, strptr("STATIC"), strptr(text), @@ -79,16 +81,16 @@ func (dlg *entryDialog) setup(text string, opts options) (string, error) { dlg.okBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.okLabel), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP|_BS_DEFPUSHBUTTON, - 12, 66, 75, 24, dlg.wnd, _IDOK, instance, 0) + 12, 66, 75, 24, dlg.wnd, win.IDOK, instance, 0) dlg.cancelBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.cancelLabel), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP, - 12, 66, 75, 24, dlg.wnd, _IDCANCEL, instance, 0) + 12, 66, 75, 24, dlg.wnd, win.IDCANCEL, instance, 0) if opts.extraButton != nil { dlg.extraBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.extraButton), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP, - 12, 66, 75, 24, dlg.wnd, _IDNO, instance, 0) + 12, 66, 75, 24, dlg.wnd, win.IDNO, instance, 0) } dlg.layout(getDPI(dlg.wnd)) @@ -162,11 +164,11 @@ func entryProc(wnd uintptr, msg uint32, wparam uintptr, lparam *unsafe.Pointer) switch wparam { default: return 1 - case _IDOK, _IDYES: + case win.IDOK, win.IDYES: dlg.out = getWindowString(dlg.editCtl) - case _IDCANCEL: + case win.IDCANCEL: dlg.err = ErrCanceled - case _IDNO: + case win.IDNO: dlg.err = ErrExtraButton } destroyWindow.Call(wnd) diff --git a/file_windows.go b/file_windows.go index 33c64dc..d9e7918 100644 --- a/file_windows.go +++ b/file_windows.go @@ -27,7 +27,7 @@ func selectFile(opts options) (string, error) { var args win.OPENFILENAME args.StructSize = uint32(unsafe.Sizeof(args)) - args.Owner, _ = opts.attach.(uintptr) + args.Owner, _ = opts.attach.(win.HWND) args.Flags = win.OFN_NOCHANGEDIR | win.OFN_FILEMUSTEXIST | win.OFN_EXPLORER if opts.title != nil { @@ -73,7 +73,7 @@ func selectFileMultiple(opts options) ([]string, error) { var args win.OPENFILENAME args.StructSize = uint32(unsafe.Sizeof(args)) - args.Owner, _ = opts.attach.(uintptr) + args.Owner, _ = opts.attach.(win.HWND) args.Flags = win.OFN_NOCHANGEDIR | win.OFN_ALLOWMULTISELECT | win.OFN_FILEMUSTEXIST | win.OFN_EXPLORER if opts.title != nil { @@ -144,7 +144,7 @@ func selectFileSave(opts options) (string, error) { var args win.OPENFILENAME args.StructSize = uint32(unsafe.Sizeof(args)) - args.Owner, _ = opts.attach.(uintptr) + args.Owner, _ = opts.attach.(win.HWND) args.Flags = win.OFN_NOCHANGEDIR | win.OFN_PATHMUSTEXIST | win.OFN_NOREADONLYRETURN | win.OFN_EXPLORER if opts.title != nil { @@ -252,8 +252,8 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error) defer unhook() } - owner, _ := opts.attach.(uintptr) - hr, _, _ = dialog.Call(dialog.Show, owner) + owner, _ := opts.attach.(win.HWND) + hr, _, _ = dialog.Call(dialog.Show, uintptr(owner)) if opts.ctx != nil && opts.ctx.Err() != nil { return "", nil, opts.ctx.Err() } @@ -313,7 +313,7 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error) func browseForFolder(opts options) (string, []string, error) { var args win.BROWSEINFO - args.Owner, _ = opts.attach.(uintptr) + args.Owner, _ = opts.attach.(win.HWND) args.Flags = 0x1 // BIF_RETURNONLYFSDIRS if opts.title != nil { diff --git a/internal/win/comdlg32.go b/internal/win/comdlg32.go index a4f51d6..02e6344 100644 --- a/internal/win/comdlg32.go +++ b/internal/win/comdlg32.go @@ -17,8 +17,8 @@ const ( // https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-choosecolorw-r1 type CHOOSECOLOR struct { StructSize uint32 - Owner uintptr - Instance uintptr + Owner HWND + Instance HWND RgbResult uint32 CustColors *[16]uint32 Flags uint32 @@ -42,8 +42,8 @@ const ( // https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamew type OPENFILENAME struct { StructSize uint32 - Owner uintptr - Instance uintptr + Owner HWND + Instance Handle Filter *uint16 CustomFilter *uint16 MaxCustomFilter uint32 diff --git a/internal/win/gdi32.go b/internal/win/gdi32.go new file mode 100644 index 0000000..9dfb75b --- /dev/null +++ b/internal/win/gdi32.go @@ -0,0 +1,30 @@ +//go:build windows + +package win + +const ( + LOGPIXELSX = 88 + LOGPIXELSY = 90 +) + +// https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logfontw +type LOGFONT struct { + Height int32 + Width int32 + Escapement int32 + Orientation int32 + Weight int32 + Italic byte + Underline byte + StrikeOut byte + CharSet byte + OutPrecision byte + ClipPrecision byte + Quality byte + PitchAndFamily byte + FaceName [32]uint16 +} + +//sys CreateFontIndirect(lf *LOGFONT) (font Handle) = gdi32.CreateFontIndirectW +//sys DeleteObject(o Handle) (ok bool) = gdi32.DeleteObject +//sys GetDeviceCaps(dc Handle, index int) (cap uintptr) = gdi32.GetDeviceCaps diff --git a/internal/win/pkg.go b/internal/win/generate.go similarity index 52% rename from internal/win/pkg.go rename to internal/win/generate.go index 3bca0c0..cd3060a 100644 --- a/internal/win/pkg.go +++ b/internal/win/generate.go @@ -1,5 +1,6 @@ -// Package win is internal. DO NOT USE. -package win +//go:build generate //go:generate -command mkwinsyscall go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go -//go:generate mkwinsyscall comctl32.go comdlg32.go ole32.go shell32.go +//go:generate mkwinsyscall comctl32.go comdlg32.go gdi32.go ole32.go shell32.go user32.go + +package win diff --git a/internal/win/shell32.go b/internal/win/shell32.go index dc49774..97bd834 100644 --- a/internal/win/shell32.go +++ b/internal/win/shell32.go @@ -9,7 +9,7 @@ const ( // https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfow type BROWSEINFO struct { - Owner uintptr + Owner HWND Root uintptr DisplayName *uint16 Title *uint16 @@ -22,11 +22,11 @@ type BROWSEINFO struct { // https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataw type NOTIFYICONDATA struct { StructSize uint32 - Wnd uintptr + Wnd HWND ID uint32 Flags uint32 CallbackMessage uint32 - Icon uintptr + Icon Handle Tip [128]uint16 // NOTIFYICONDATAA_V1_SIZE State uint32 StateMask uint32 @@ -34,8 +34,8 @@ type NOTIFYICONDATA struct { Version uint32 InfoTitle [64]uint16 InfoFlags uint32 - // GuidItem [16]byte // NOTIFYICONDATAA_V2_SIZE - // BalloonIcon syscall.Handle // NOTIFYICONDATAA_V3_SIZE + // GuidItem [16]byte // NOTIFYICONDATAA_V2_SIZE + // BalloonIcon Handle // NOTIFYICONDATAA_V3_SIZE } type IShellItem struct { diff --git a/internal/win/user32.go b/internal/win/user32.go new file mode 100644 index 0000000..26c94ca --- /dev/null +++ b/internal/win/user32.go @@ -0,0 +1,34 @@ +//go:build windows + +package win + +import "golang.org/x/sys/windows" + +const ( + IDOK = 1 + IDCANCEL = 2 + IDABORT = 3 + IDRETRY = 4 + IDIGNORE = 5 + IDYES = 6 + IDNO = 7 + + MB_OK = windows.MB_OK + MB_OKCANCEL = windows.MB_OKCANCEL + MB_ABORTRETRYIGNORE = windows.MB_ABORTRETRYIGNORE + MB_YESNOCANCEL = windows.MB_YESNOCANCEL + MB_YESNO = windows.MB_YESNO + MB_RETRYCANCEL = windows.MB_RETRYCANCEL + MB_CANCELTRYCONTINUE = windows.MB_CANCELTRYCONTINUE + MB_ICONERROR = windows.MB_ICONERROR + MB_ICONQUESTION = windows.MB_ICONQUESTION + MB_ICONWARNING = windows.MB_ICONWARNING + MB_ICONINFORMATION = windows.MB_ICONINFORMATION + MB_DEFBUTTON1 = windows.MB_DEFBUTTON1 + MB_DEFBUTTON2 = windows.MB_DEFBUTTON2 + MB_DEFBUTTON3 = windows.MB_DEFBUTTON3 +) + +func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) { + return windows.MessageBox(hwnd, text, caption, boxtype) +} diff --git a/internal/win/win32.go b/internal/win/win32.go new file mode 100644 index 0000000..ebf0d87 --- /dev/null +++ b/internal/win/win32.go @@ -0,0 +1,9 @@ +//go:build windows + +// Package win is internal. DO NOT USE. +package win + +import "golang.org/x/sys/windows" + +type Handle = windows.Handle +type HWND = windows.HWND diff --git a/internal/win/zsyscall_windows.go b/internal/win/zsyscall_windows.go index 6b347f4..66b5cf5 100644 --- a/internal/win/zsyscall_windows.go +++ b/internal/win/zsyscall_windows.go @@ -40,6 +40,7 @@ func errnoErr(e syscall.Errno) error { var ( modcomctl32 = windows.NewLazySystemDLL("comctl32.dll") modcomdlg32 = windows.NewLazySystemDLL("comdlg32.dll") + modgdi32 = windows.NewLazySystemDLL("gdi32.dll") modole32 = windows.NewLazySystemDLL("ole32.dll") modshell32 = windows.NewLazySystemDLL("shell32.dll") @@ -48,6 +49,9 @@ var ( procCommDlgExtendedError = modcomdlg32.NewProc("CommDlgExtendedError") procGetOpenFileNameW = modcomdlg32.NewProc("GetOpenFileNameW") procGetSaveFileNameW = modcomdlg32.NewProc("GetSaveFileNameW") + procCreateFontIndirectW = modgdi32.NewProc("CreateFontIndirectW") + procDeleteObject = modgdi32.NewProc("DeleteObject") + procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps") procCoCreateInstance = modole32.NewProc("CoCreateInstance") procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolder") @@ -86,6 +90,24 @@ func GetSaveFileName(ofn *OPENFILENAME) (ok bool) { return } +func CreateFontIndirect(lf *LOGFONT) (font Handle) { + r0, _, _ := syscall.Syscall(procCreateFontIndirectW.Addr(), 1, uintptr(unsafe.Pointer(lf)), 0, 0) + font = Handle(r0) + return +} + +func DeleteObject(o Handle) (ok bool) { + r0, _, _ := syscall.Syscall(procDeleteObject.Addr(), 1, uintptr(o), 0, 0) + ok = r0 != 0 + return +} + +func GetDeviceCaps(dc Handle, index int) (cap uintptr) { + r0, _, _ := syscall.Syscall(procGetDeviceCaps.Addr(), 2, uintptr(dc), uintptr(index), 0) + cap = uintptr(r0) + return +} + func CoCreateInstance(clsid uintptr, unkOuter unsafe.Pointer, clsContext int32, iid uintptr, address unsafe.Pointer) (ret error) { r0, _, _ := syscall.Syscall6(procCoCreateInstance.Addr(), 5, uintptr(clsid), uintptr(unkOuter), uintptr(clsContext), uintptr(iid), uintptr(address), 0) if r0 != 0 { diff --git a/internal/zenutil/osa_generate.go b/internal/zenutil/osa_generate.go deleted file mode 100644 index 0bcc980..0000000 --- a/internal/zenutil/osa_generate.go +++ /dev/null @@ -1,3 +0,0 @@ -package zenutil - -//go:generate go run osa_generator.go osascripts/ diff --git a/internal/zenutil/osa_generated.go b/internal/zenutil/osa_generated.go index 2e1d1ad..10f0798 100644 --- a/internal/zenutil/osa_generated.go +++ b/internal/zenutil/osa_generated.go @@ -1,4 +1,5 @@ // Code generated by zenity; DO NOT EDIT. + //go:build darwin package zenutil diff --git a/internal/zenutil/osa_generator.go b/internal/zenutil/osa_generator.go index b8c11bf..e4e8bee 100644 --- a/internal/zenutil/osa_generator.go +++ b/internal/zenutil/osa_generator.go @@ -1,4 +1,6 @@ -//go:build tools +//go:build generate + +//go:generate go run osa_generator.go osascripts/ package main @@ -102,6 +104,7 @@ func minify(data []byte) ([]byte, error) { } var generator = template.Must(template.New("").Parse(`// Code generated by zenity; DO NOT EDIT. + //go:build darwin package zenutil diff --git a/internal/zenutil/window_windows.go b/internal/zenutil/window_windows.go index 14eef03..b92d98d 100644 --- a/internal/zenutil/window_windows.go +++ b/internal/zenutil/window_windows.go @@ -1,11 +1,15 @@ package zenutil -import "strconv" +import ( + "strconv" + + "golang.org/x/sys/windows" +) // ParseWindowId is internal. -func ParseWindowId(id string) uintptr { +func ParseWindowId(id string) windows.HWND { hwnd, _ := strconv.ParseUint(id, 0, 64) - return uintptr(hwnd) + return windows.HWND(uintptr(hwnd)) } // GetParentWindowId is internal. diff --git a/list_windows.go b/list_windows.go index f2e0934..93a1d25 100644 --- a/list_windows.go +++ b/list_windows.go @@ -3,6 +3,8 @@ package zenity import ( "syscall" "unsafe" + + "github.com/ncruces/zenity/internal/win" ) func list(text string, items []string, opts options) (string, error) { @@ -72,12 +74,12 @@ func (dlg *listDialog) setup(text string, opts options) ([]string, error) { } defer unregisterClass.Call(cls, instance) - owner, _ := opts.attach.(uintptr) + owner, _ := opts.attach.(win.HWND) dlg.wnd, _, _ = createWindowEx.Call(_WS_EX_CONTROLPARENT|_WS_EX_WINDOWEDGE|_WS_EX_DLGMODALFRAME, cls, strptr(*opts.title), _WS_POPUPWINDOW|_WS_CLIPSIBLINGS|_WS_DLGFRAME, _CW_USEDEFAULT, _CW_USEDEFAULT, - 281, 281, owner, 0, instance, uintptr(unsafe.Pointer(dlg))) + 281, 281, uintptr(owner), 0, instance, uintptr(unsafe.Pointer(dlg))) dlg.textCtl, _, _ = createWindowEx.Call(0, strptr("STATIC"), strptr(text), @@ -96,16 +98,16 @@ func (dlg *listDialog) setup(text string, opts options) ([]string, error) { dlg.okBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.okLabel), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP|_BS_DEFPUSHBUTTON, - 12, 206, 75, 24, dlg.wnd, _IDOK, instance, 0) + 12, 206, 75, 24, dlg.wnd, win.IDOK, instance, 0) dlg.cancelBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.cancelLabel), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP, - 12, 206, 75, 24, dlg.wnd, _IDCANCEL, instance, 0) + 12, 206, 75, 24, dlg.wnd, win.IDCANCEL, instance, 0) if opts.extraButton != nil { dlg.extraBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.extraButton), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP, - 12, 206, 75, 24, dlg.wnd, _IDNO, instance, 0) + 12, 206, 75, 24, dlg.wnd, win.IDNO, instance, 0) } for _, item := range dlg.items { @@ -182,7 +184,7 @@ func listProc(wnd uintptr, msg uint32, wparam uintptr, lparam *unsafe.Pointer) u switch wparam { default: return 1 - case _IDOK, _IDYES: + case win.IDOK, win.IDYES: if dlg.multiple { if len, _, _ := sendMessage.Call(dlg.listCtl, _LB_GETSELCOUNT, 0, 0); int32(len) >= 0 { dlg.out = make([]string, len) @@ -201,9 +203,9 @@ func listProc(wnd uintptr, msg uint32, wparam uintptr, lparam *unsafe.Pointer) u dlg.out = []string{} } } - case _IDCANCEL: + case win.IDCANCEL: dlg.err = ErrCanceled - case _IDNO: + case win.IDNO: dlg.err = ErrExtraButton } destroyWindow.Call(wnd) diff --git a/msg_windows.go b/msg_windows.go index c1084c4..9ec5fec 100644 --- a/msg_windows.go +++ b/msg_windows.go @@ -4,54 +4,55 @@ import ( "context" "syscall" "unsafe" + + "github.com/ncruces/zenity/internal/win" ) var ( getDlgCtrlID = user32.NewProc("GetDlgCtrlID") - messageBox = user32.NewProc("MessageBoxW") ) func message(kind messageKind, text string, opts options) error { - var flags uintptr + var flags uint32 switch { case kind == questionKind && opts.extraButton != nil: - flags |= _MB_YESNOCANCEL + flags |= win.MB_YESNOCANCEL case kind == questionKind: - flags |= _MB_OKCANCEL + flags |= win.MB_OKCANCEL case opts.extraButton != nil: - flags |= _MB_YESNO + flags |= win.MB_YESNO } switch opts.icon { case ErrorIcon: - flags |= _MB_ICONERROR + flags |= win.MB_ICONERROR case QuestionIcon: - flags |= _MB_ICONQUESTION + flags |= win.MB_ICONQUESTION case WarningIcon: - flags |= _MB_ICONWARNING + flags |= win.MB_ICONWARNING case InfoIcon: - flags |= _MB_ICONINFORMATION + flags |= win.MB_ICONINFORMATION case NoIcon: // default: switch kind { case errorKind: - flags |= _MB_ICONERROR + flags |= win.MB_ICONERROR case questionKind: - flags |= _MB_ICONQUESTION + flags |= win.MB_ICONQUESTION case warningKind: - flags |= _MB_ICONWARNING + flags |= win.MB_ICONWARNING case infoKind: - flags |= _MB_ICONINFORMATION + flags |= win.MB_ICONINFORMATION } } if kind == questionKind && opts.defaultCancel { if opts.extraButton == nil { - flags |= _MB_DEFBUTTON2 + flags |= win.MB_DEFBUTTON2 } else { - flags |= _MB_DEFBUTTON3 + flags |= win.MB_DEFBUTTON3 } } @@ -70,18 +71,18 @@ func message(kind messageKind, text string, opts options) error { title = syscall.StringToUTF16Ptr(*opts.title) } - owner, _ := opts.attach.(uintptr) - s, _, err := messageBox.Call(owner, strptr(text), uintptr(unsafe.Pointer(title)), flags) + owner, _ := opts.attach.(win.HWND) + s, err := win.MessageBox(owner, syscall.StringToUTF16Ptr(text), title, flags) if opts.ctx != nil && opts.ctx.Err() != nil { return opts.ctx.Err() } switch s { - case _IDOK, _IDYES: + case win.IDOK, win.IDYES: return nil - case _IDCANCEL: + case win.IDCANCEL: return ErrCanceled - case _IDNO: + case win.IDNO: return ErrExtraButton default: return err @@ -101,11 +102,11 @@ func hookMessageDialogCallback(wnd uintptr, lparam *options) uintptr { var text *string switch ctl { - case _IDOK, _IDYES: + case win.IDOK, win.IDYES: text = lparam.okLabel - case _IDCANCEL: + case win.IDCANCEL: text = lparam.cancelLabel - case _IDNO: + case win.IDNO: text = lparam.extraButton } if text != nil { diff --git a/notify_windows.go b/notify_windows.go index 9dc2db8..9143cc4 100644 --- a/notify_windows.go +++ b/notify_windows.go @@ -46,7 +46,7 @@ func notify(text string, opts options) error { icon := getIcon(opts.icon) if icon.handle != 0 { defer icon.delete() - args.Icon = icon.handle + args.Icon = win.Handle(icon.handle) args.Flags |= 0x00000002 // NIF_ICON args.InfoFlags |= 0x4 // NIIF_USER } @@ -90,13 +90,13 @@ func wtsMessage(text string, opts options) error { switch opts.icon { case ErrorIcon: - flags |= _MB_ICONERROR + flags |= win.MB_ICONERROR case QuestionIcon: - flags |= _MB_ICONQUESTION + flags |= win.MB_ICONQUESTION case WarningIcon: - flags |= _MB_ICONWARNING + flags |= win.MB_ICONWARNING case InfoIcon: - flags |= _MB_ICONINFORMATION + flags |= win.MB_ICONINFORMATION } title := opts.title diff --git a/progress_windows.go b/progress_windows.go index df47739..bc83139 100644 --- a/progress_windows.go +++ b/progress_windows.go @@ -5,6 +5,8 @@ import ( "sync" "syscall" "unsafe" + + "github.com/ncruces/zenity/internal/win" ) func progress(opts options) (ProgressDialog, error) { @@ -135,12 +137,12 @@ func (dlg *progressDialog) setup(opts options) error { } defer unregisterClass.Call(cls, instance) - owner, _ := opts.attach.(uintptr) + owner, _ := opts.attach.(win.HWND) dlg.wnd, _, _ = createWindowEx.Call(_WS_EX_CONTROLPARENT|_WS_EX_WINDOWEDGE|_WS_EX_DLGMODALFRAME, cls, strptr(*opts.title), _WS_POPUPWINDOW|_WS_CLIPSIBLINGS|_WS_DLGFRAME, _CW_USEDEFAULT, _CW_USEDEFAULT, - 281, 133, owner, 0, instance, uintptr(unsafe.Pointer(dlg))) + 281, 133, uintptr(owner), 0, instance, uintptr(unsafe.Pointer(dlg))) dlg.textCtl, _, _ = createWindowEx.Call(0, strptr("STATIC"), 0, @@ -159,18 +161,18 @@ func (dlg *progressDialog) setup(opts options) error { dlg.okBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.okLabel), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP|_BS_DEFPUSHBUTTON|_WS_DISABLED, - 12, 58, 75, 24, dlg.wnd, _IDOK, instance, 0) + 12, 58, 75, 24, dlg.wnd, win.IDOK, instance, 0) if !opts.noCancel { dlg.cancelBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.cancelLabel), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP, - 12, 58, 75, 24, dlg.wnd, _IDCANCEL, instance, 0) + 12, 58, 75, 24, dlg.wnd, win.IDCANCEL, instance, 0) } if opts.extraButton != nil { dlg.extraBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.extraButton), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP, - 12, 58, 75, 24, dlg.wnd, _IDNO, instance, 0) + 12, 58, 75, 24, dlg.wnd, win.IDNO, instance, 0) } dlg.layout(getDPI(dlg.wnd)) @@ -256,11 +258,11 @@ func progressProc(wnd uintptr, msg uint32, wparam uintptr, lparam *unsafe.Pointe switch wparam { default: return 1 - case _IDOK, _IDYES: + case win.IDOK, win.IDYES: // - case _IDCANCEL: + case win.IDCANCEL: dlg.err = ErrCanceled - case _IDNO: + case win.IDNO: dlg.err = ErrExtraButton } destroyWindow.Call(wnd) diff --git a/pwd_windows.go b/pwd_windows.go index 6698f60..7f1bed4 100644 --- a/pwd_windows.go +++ b/pwd_windows.go @@ -3,6 +3,8 @@ package zenity import ( "syscall" "unsafe" + + "github.com/ncruces/zenity/internal/win" ) func password(opts options) (string, string, error) { @@ -65,12 +67,12 @@ func (dlg *passwordDialog) setup(opts options) (string, string, error) { } defer unregisterClass.Call(cls, instance) - owner, _ := opts.attach.(uintptr) + owner, _ := opts.attach.(win.HWND) dlg.wnd, _, _ = createWindowEx.Call(_WS_EX_CONTROLPARENT|_WS_EX_WINDOWEDGE|_WS_EX_DLGMODALFRAME, cls, strptr(*opts.title), _WS_POPUPWINDOW|_WS_CLIPSIBLINGS|_WS_DLGFRAME, _CW_USEDEFAULT, _CW_USEDEFAULT, - 281, 191, owner, 0, instance, uintptr(unsafe.Pointer(dlg))) + 281, 191, uintptr(owner), 0, instance, uintptr(unsafe.Pointer(dlg))) dlg.uTextCtl, _, _ = createWindowEx.Call(0, strptr("STATIC"), strptr("Username:"), @@ -96,16 +98,16 @@ func (dlg *passwordDialog) setup(opts options) (string, string, error) { dlg.okBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.okLabel), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP|_BS_DEFPUSHBUTTON, - 12, 116, 75, 24, dlg.wnd, _IDOK, instance, 0) + 12, 116, 75, 24, dlg.wnd, win.IDOK, instance, 0) dlg.cancelBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.cancelLabel), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP, - 12, 116, 75, 24, dlg.wnd, _IDCANCEL, instance, 0) + 12, 116, 75, 24, dlg.wnd, win.IDCANCEL, instance, 0) if opts.extraButton != nil { dlg.extraBtn, _, _ = createWindowEx.Call(0, strptr("BUTTON"), strptr(*opts.extraButton), _WS_CHILD|_WS_VISIBLE|_WS_GROUP|_WS_TABSTOP, - 12, 116, 75, 24, dlg.wnd, _IDNO, instance, 0) + 12, 116, 75, 24, dlg.wnd, win.IDNO, instance, 0) } dlg.layout(getDPI(dlg.wnd)) @@ -183,12 +185,12 @@ func passwordProc(wnd uintptr, msg uint32, wparam uintptr, lparam *unsafe.Pointe switch wparam { default: return 1 - case _IDOK, _IDYES: + case win.IDOK, win.IDYES: dlg.usr = getWindowString(dlg.uEditCtl) dlg.pwd = getWindowString(dlg.pEditCtl) - case _IDCANCEL: + case win.IDCANCEL: dlg.err = ErrCanceled - case _IDNO: + case win.IDNO: dlg.err = ErrExtraButton } destroyWindow.Call(wnd) diff --git a/util_unix.go b/util_unix.go index 111cd47..26c5c39 100644 --- a/util_unix.go +++ b/util_unix.go @@ -98,6 +98,8 @@ func pwdResult(sep string, opts options, out []byte, err error) (string, string, return "", str, err } +func hwnd(i uint64) uintptr { return uintptr(i) } + // Replace with strings.Cut after 1.18. func cut(s, sep string) (before, after string, found bool) { if i := strings.Index(s, sep); i >= 0 { diff --git a/util_windows.go b/util_windows.go index 178203c..549a5fd 100644 --- a/util_windows.go +++ b/util_windows.go @@ -17,16 +17,11 @@ import ( ) var ( - gdi32 = windows.NewLazySystemDLL("gdi32.dll") kernel32 = windows.NewLazySystemDLL("kernel32.dll") ntdll = windows.NewLazySystemDLL("ntdll.dll") user32 = windows.NewLazySystemDLL("user32.dll") wtsapi32 = windows.NewLazySystemDLL("wtsapi32.dll") - createFontIndirect = gdi32.NewProc("CreateFontIndirectW") - deleteObject = gdi32.NewProc("DeleteObject") - getDeviceCaps = gdi32.NewProc("GetDeviceCaps") - activateActCtx = kernel32.NewProc("ActivateActCtx") createActCtx = kernel32.NewProc("CreateActCtxW") deactivateActCtx = kernel32.NewProc("DeactivateActCtx") @@ -82,6 +77,8 @@ func strptr(s string) uintptr { return uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(s))) } +func hwnd(i uint64) win.HWND { return win.HWND(uintptr(i)) } + func setup() context.CancelFunc { var wnd uintptr enumWindows.Call(syscall.NewCallback(setupEnumCallback), uintptr(unsafe.Pointer(&wnd))) @@ -264,7 +261,7 @@ func getDPI(wnd uintptr) dpi { if wnd != 0 && getDpiForWindow.Find() == nil { res, _, _ = getDpiForWindow.Call(wnd) } else if dc, _, _ := getWindowDC.Call(wnd); dc != 0 { - res, _, _ = getDeviceCaps.Call(dc, 90) // LOGPIXELSY + res = win.GetDeviceCaps(win.Handle(dc), win.LOGPIXELSY) releaseDC.Call(0, dc) } @@ -282,8 +279,8 @@ func (d dpi) scale(dim uintptr) uintptr { } type font struct { - handle uintptr - logical _LOGFONT + handle win.Handle + logical win.LOGFONT } func getFont() font { @@ -298,14 +295,14 @@ func (f *font) forDPI(dpi dpi) uintptr { if h := -int32(dpi.scale(12)); f.handle == 0 || f.logical.Height != h { f.delete() f.logical.Height = h - f.handle, _, _ = createFontIndirect.Call(uintptr(unsafe.Pointer(&f.logical))) + f.handle = win.CreateFontIndirect(&f.logical) } - return f.handle + return uintptr(f.handle) } func (f *font) delete() { if f.handle != 0 { - deleteObject.Call(f.handle) + win.DeleteObject(f.handle) f.handle = 0 } } @@ -470,24 +467,6 @@ type _CWPRETSTRUCT struct { Wnd uintptr } -// https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logfontw -type _LOGFONT struct { - Height int32 - Width int32 - Escapement int32 - Orientation int32 - Weight int32 - Italic byte - Underline byte - StrikeOut byte - CharSet byte - OutPrecision byte - ClipPrecision byte - Quality byte - PitchAndFamily byte - FaceName [32]uint16 -} - // https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-nonclientmetricsw type _NONCLIENTMETRICS struct { Size uint32 @@ -496,15 +475,15 @@ type _NONCLIENTMETRICS struct { ScrollHeight int32 CaptionWidth int32 CaptionHeight int32 - CaptionFont _LOGFONT + CaptionFont win.LOGFONT SmCaptionWidth int32 SmCaptionHeight int32 - SmCaptionFont _LOGFONT + SmCaptionFont win.LOGFONT MenuWidth int32 MenuHeight int32 - MenuFont _LOGFONT - StatusFont _LOGFONT - MessageFont _LOGFONT + MenuFont win.LOGFONT + StatusFont win.LOGFONT + MessageFont win.LOGFONT } // https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-msg diff --git a/zenity.go b/zenity.go index 1a8dbf6..d09b997 100644 --- a/zenity.go +++ b/zenity.go @@ -201,7 +201,7 @@ func Attach(id any) Option { switch runtime.GOOS { case "windows": if v := reflect.ValueOf(id); v.Kind() == reflect.Uintptr { - id = uintptr(v.Uint()) + id = hwnd(v.Uint()) } else { panic("interface conversion: expected uintptr") }