Custom icons (windows).
This commit is contained in:
parent
9539a7da29
commit
53d7c0954c
3 changed files with 60 additions and 47 deletions
|
@ -395,6 +395,8 @@ func loadFlags() []zenity.Option {
|
||||||
|
|
||||||
var ico zenity.DialogIcon
|
var ico zenity.DialogIcon
|
||||||
switch icon {
|
switch icon {
|
||||||
|
case unspecified:
|
||||||
|
ico = 0
|
||||||
case "error", "dialog-error":
|
case "error", "dialog-error":
|
||||||
ico = zenity.ErrorIcon
|
ico = zenity.ErrorIcon
|
||||||
case "info", "dialog-information":
|
case "info", "dialog-information":
|
||||||
|
@ -405,7 +407,7 @@ func loadFlags() []zenity.Option {
|
||||||
ico = zenity.WarningIcon
|
ico = zenity.WarningIcon
|
||||||
case "dialog-password":
|
case "dialog-password":
|
||||||
ico = zenity.PasswordIcon
|
ico = zenity.PasswordIcon
|
||||||
case unspecified:
|
case "":
|
||||||
ico = zenity.NoIcon
|
ico = zenity.NoIcon
|
||||||
default:
|
default:
|
||||||
opts = append(opts, zenity.CustomIcon(icon))
|
opts = append(opts, zenity.CustomIcon(icon))
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
package zenity
|
package zenity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
messageBox = user32.NewProc("MessageBoxW")
|
messageBox = user32.NewProc("MessageBoxW")
|
||||||
getDlgCtrlID = user32.NewProc("GetDlgCtrlID")
|
getDlgCtrlID = user32.NewProc("GetDlgCtrlID")
|
||||||
|
loadImage = user32.NewProc("LoadImageW")
|
||||||
|
destroyIcon = user32.NewProc("DestroyIcon")
|
||||||
|
createIconFromResource = user32.NewProc("CreateIconFromResource")
|
||||||
)
|
)
|
||||||
|
|
||||||
func message(kind messageKind, text string, opts options) error {
|
func message(kind messageKind, text string, opts options) error {
|
||||||
|
@ -55,8 +60,8 @@ func message(kind messageKind, text string, opts options) error {
|
||||||
|
|
||||||
defer setup()()
|
defer setup()()
|
||||||
|
|
||||||
if opts.ctx != nil || opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil {
|
if opts.ctx != nil || opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil || opts.customIcon != "" {
|
||||||
unhook, err := hookMessageLabels(kind, opts)
|
unhook, err := hookMessageDialog(kind, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -85,30 +90,50 @@ func message(kind messageKind, text string, opts options) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hookMessageLabels(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, func(wnd uintptr) {
|
||||||
enumChildWindows.Call(wnd,
|
enumChildWindows.Call(wnd,
|
||||||
syscall.NewCallback(hookMessageLabelsCallback),
|
syscall.NewCallback(hookMessageDialogCallback),
|
||||||
uintptr(unsafe.Pointer(&opts)))
|
uintptr(unsafe.Pointer(&opts)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func hookMessageLabelsCallback(wnd uintptr, lparam *options) uintptr {
|
func hookMessageDialogCallback(wnd uintptr, lparam *options) uintptr {
|
||||||
var name [8]uint16
|
ctl, _, _ := getDlgCtrlID.Call(wnd)
|
||||||
getClassName.Call(wnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name)))
|
|
||||||
if syscall.UTF16ToString(name[:]) == "Button" {
|
var text *string
|
||||||
ctl, _, _ := getDlgCtrlID.Call(wnd)
|
switch ctl {
|
||||||
var text *string
|
case _IDOK, _IDYES:
|
||||||
switch ctl {
|
text = lparam.okLabel
|
||||||
case _IDOK, _IDYES:
|
case _IDCANCEL:
|
||||||
text = lparam.okLabel
|
text = lparam.cancelLabel
|
||||||
case _IDCANCEL:
|
case _IDNO:
|
||||||
text = lparam.cancelLabel
|
text = lparam.extraButton
|
||||||
case _IDNO:
|
}
|
||||||
text = lparam.extraButton
|
if text != nil {
|
||||||
|
setWindowText.Call(wnd, strptr(*text))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctl == 20 /*IDC_STATIC_OK*/ && lparam.customIcon != "" {
|
||||||
|
var icon uintptr
|
||||||
|
data, _ := os.ReadFile(lparam.customIcon)
|
||||||
|
switch {
|
||||||
|
case bytes.HasPrefix(data, []byte("\x00\x00\x01\x00")):
|
||||||
|
icon, _, _ = loadImage.Call(0,
|
||||||
|
strptr(lparam.customIcon),
|
||||||
|
1, /*IMAGE_ICON*/
|
||||||
|
0, 0,
|
||||||
|
0x00008050 /*LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_SHARED*/)
|
||||||
|
case bytes.HasPrefix(data, []byte("\x89PNG\r\n\x1a\n")):
|
||||||
|
icon, _, _ = createIconFromResource.Call(
|
||||||
|
uintptr(unsafe.Pointer(&data[0])),
|
||||||
|
uintptr(len(data)),
|
||||||
|
1, 0x00030000)
|
||||||
|
defer destroyIcon.Call(icon)
|
||||||
}
|
}
|
||||||
if text != nil {
|
|
||||||
setWindowText.Call(wnd, strptr(*text))
|
if icon != 0 {
|
||||||
|
sendMessage.Call(wnd, 0x0170 /*STM_SETICON*/, icon, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
|
|
|
@ -52,7 +52,6 @@ var (
|
||||||
isDialogMessage = user32.NewProc("IsDialogMessageW")
|
isDialogMessage = user32.NewProc("IsDialogMessageW")
|
||||||
dispatchMessage = user32.NewProc("DispatchMessageW")
|
dispatchMessage = user32.NewProc("DispatchMessageW")
|
||||||
translateMessage = user32.NewProc("TranslateMessage")
|
translateMessage = user32.NewProc("TranslateMessage")
|
||||||
getClassName = user32.NewProc("GetClassNameW")
|
|
||||||
unhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx")
|
unhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx")
|
||||||
setWindowsHookEx = user32.NewProc("SetWindowsHookExW")
|
setWindowsHookEx = user32.NewProc("SetWindowsHookExW")
|
||||||
callNextHookEx = user32.NewProc("CallNextHookEx")
|
callNextHookEx = user32.NewProc("CallNextHookEx")
|
||||||
|
@ -174,7 +173,7 @@ type dialogHook struct {
|
||||||
|
|
||||||
func newDialogHook(ctx context.Context, initDialog func(wnd uintptr)) (*dialogHook, error) {
|
func newDialogHook(ctx context.Context, initDialog func(wnd uintptr)) (*dialogHook, error) {
|
||||||
tid, _, _ := getCurrentThreadId.Call()
|
tid, _, _ := getCurrentThreadId.Call()
|
||||||
hk, _, err := setWindowsHookEx.Call(12, // WH_CALLWNDPROCRET
|
hk, _, err := setWindowsHookEx.Call(5, // WH_CBT
|
||||||
syscall.NewCallback(dialogHookProc), 0, tid)
|
syscall.NewCallback(dialogHookProc), 0, tid)
|
||||||
if hk == 0 {
|
if hk == 0 {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -195,23 +194,19 @@ func newDialogHook(ctx context.Context, initDialog func(wnd uintptr)) (*dialogHo
|
||||||
return &hook, nil
|
return &hook, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func dialogHookProc(code int32, wparam uintptr, lparam *_CWPRETSTRUCT) uintptr {
|
func dialogHookProc(code int32, wparam, lparam uintptr) uintptr {
|
||||||
if lparam.Message == 0x0110 { // WM_INITDIALOG
|
if code == 5 { // HCBT_ACTIVATE
|
||||||
var name [8]uint16
|
tid, _, _ := getCurrentThreadId.Call()
|
||||||
getClassName.Call(lparam.Wnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name)))
|
hook := (*dialogHook)(loadBackRef(tid))
|
||||||
if syscall.UTF16ToString(name[:]) == "#32770" { // The class for a dialog box
|
atomic.StoreUintptr(&hook.wnd, wparam)
|
||||||
tid, _, _ := getCurrentThreadId.Call()
|
if hook.ctx != nil && hook.ctx.Err() != nil {
|
||||||
hook := (*dialogHook)(loadBackRef(tid))
|
sendMessage.Call(wparam, _WM_SYSCOMMAND, _SC_CLOSE, 0)
|
||||||
atomic.StoreUintptr(&hook.wnd, lparam.Wnd)
|
} else if hook.init != nil {
|
||||||
if hook.ctx != nil && hook.ctx.Err() != nil {
|
hook.init(wparam)
|
||||||
sendMessage.Call(lparam.Wnd, _WM_SYSCOMMAND, _SC_CLOSE, 0)
|
|
||||||
} else if hook.init != nil {
|
|
||||||
hook.init(lparam.Wnd)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
next, _, _ := callNextHookEx.Call(
|
next, _, _ := callNextHookEx.Call(
|
||||||
0, uintptr(code), wparam, uintptr(unsafe.Pointer(lparam)))
|
0, uintptr(code), wparam, lparam)
|
||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,15 +417,6 @@ 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
|
||||||
|
|
Loading…
Reference in a new issue