Refactor (windows).

This commit is contained in:
Nuno Cruces 2022-06-18 12:37:39 +01:00
parent d33a18d05a
commit d47150a866
24 changed files with 222 additions and 145 deletions

View file

@ -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 {

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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 {

View file

@ -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

30
internal/win/gdi32.go Normal file
View file

@ -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

View file

@ -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

View file

@ -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
@ -35,7 +35,7 @@ type NOTIFYICONDATA struct {
InfoTitle [64]uint16
InfoFlags uint32
// GuidItem [16]byte // NOTIFYICONDATAA_V2_SIZE
// BalloonIcon syscall.Handle // NOTIFYICONDATAA_V3_SIZE
// BalloonIcon Handle // NOTIFYICONDATAA_V3_SIZE
}
type IShellItem struct {

34
internal/win/user32.go Normal file
View file

@ -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)
}

9
internal/win/win32.go Normal file
View file

@ -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

View file

@ -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 {

View file

@ -1,3 +0,0 @@
package zenutil
//go:generate go run osa_generator.go osascripts/

View file

@ -1,4 +1,5 @@
// Code generated by zenity; DO NOT EDIT.
//go:build darwin
package zenutil

View file

@ -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

View file

@ -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.

View file

@ -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)

View file

@ -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 {

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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 {

View file

@ -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

View file

@ -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")
}