zenity/notify_windows.go

139 lines
3.2 KiB
Go
Raw Normal View History

2020-01-26 11:04:49 -05:00
package zenity
2020-01-27 08:44:47 -05:00
import (
2021-08-13 21:50:04 -04:00
"math/rand"
2020-01-27 13:11:38 -05:00
"runtime"
2020-01-27 08:44:47 -05:00
"syscall"
2021-08-13 21:50:04 -04:00
"time"
2020-01-27 08:44:47 -05:00
"unsafe"
2020-01-30 21:18:43 -05:00
"github.com/ncruces/zenity/internal/zenutil"
2020-01-27 08:44:47 -05:00
)
var (
2021-08-13 21:50:04 -04:00
rtlGetNtVersionNumbers = ntdll.NewProc("RtlGetNtVersionNumbers")
shellNotifyIcon = shell32.NewProc("Shell_NotifyIconW")
wtsSendMessage = wtsapi32.NewProc("WTSSendMessageW")
2020-01-27 08:44:47 -05:00
)
2021-03-04 07:42:30 -05:00
func notify(text string, opts options) error {
2020-01-30 20:31:54 -05:00
if opts.ctx != nil && opts.ctx.Err() != nil {
return opts.ctx.Err()
}
2020-01-27 08:44:47 -05:00
var args _NOTIFYICONDATA
args.StructSize = uint32(unsafe.Sizeof(args))
2021-08-13 21:50:04 -04:00
args.ID = rand.Uint32()
2020-01-27 08:44:47 -05:00
args.Flags = 0x00000010 // NIF_INFO
args.State = 0x00000001 // NIS_HIDDEN
info := syscall.StringToUTF16(text)
copy(args.Info[:len(args.Info)-1], info)
2021-03-03 22:25:45 -05:00
if opts.title != nil {
title := syscall.StringToUTF16(*opts.title)
copy(args.InfoTitle[:len(args.InfoTitle)-1], title)
}
2020-01-27 08:44:47 -05:00
switch opts.icon {
2021-03-04 08:06:49 -05:00
case InfoIcon, QuestionIcon:
2020-01-27 08:44:47 -05:00
args.InfoFlags |= 0x1 // NIIF_INFO
case WarningIcon:
args.InfoFlags |= 0x2 // NIIF_WARNING
case ErrorIcon:
args.InfoFlags |= 0x3 // NIIF_ERROR
}
2020-01-27 13:11:38 -05:00
runtime.LockOSThread()
defer runtime.UnlockOSThread()
2020-01-29 09:15:21 -05:00
s, _, err := shellNotifyIcon.Call(0 /* NIM_ADD */, uintptr(unsafe.Pointer(&args)))
if s == 0 {
2020-01-27 13:11:38 -05:00
if errno, ok := err.(syscall.Errno); ok && errno == 0 {
2020-01-30 21:18:43 -05:00
return wtsMessage(text, opts)
2020-01-27 13:11:38 -05:00
}
2020-01-27 08:44:47 -05:00
return err
}
2021-08-13 21:50:04 -04:00
var major, minor, build uint32
rtlGetNtVersionNumbers.Call(
uintptr(unsafe.Pointer(&major)),
uintptr(unsafe.Pointer(&minor)),
uintptr(unsafe.Pointer(&build)))
// On Windows 7 (6.1) and lower, wait up to 10 seconds to clean up.
if major < 6 || major == 6 && minor < 2 {
if opts.ctx != nil {
select {
case <-opts.ctx.Done():
case <-time.After(10 * time.Second):
}
} else {
time.Sleep(10 * time.Second)
}
}
2020-01-27 08:44:47 -05:00
shellNotifyIcon.Call(2 /* NIM_DELETE */, uintptr(unsafe.Pointer(&args)))
return nil
}
2020-01-30 21:18:43 -05:00
func wtsMessage(text string, opts options) error {
var flags uintptr
switch opts.icon {
case ErrorIcon:
2022-03-28 22:05:46 -04:00
flags |= _MB_ICONERROR
2020-01-30 21:18:43 -05:00
case QuestionIcon:
2022-03-28 22:05:46 -04:00
flags |= _MB_ICONQUESTION
2020-01-30 21:18:43 -05:00
case WarningIcon:
2022-03-28 22:05:46 -04:00
flags |= _MB_ICONWARNING
2020-01-30 21:18:43 -05:00
case InfoIcon:
2022-03-28 22:05:46 -04:00
flags |= _MB_ICONINFORMATION
2020-01-30 21:18:43 -05:00
}
title := opts.title
2021-03-03 22:25:45 -05:00
if title == nil {
title = stringPtr("Notification")
2020-01-30 21:18:43 -05:00
}
timeout := zenutil.Timeout
if timeout == 0 {
timeout = 10
}
ptext := syscall.StringToUTF16(text)
2021-03-03 22:25:45 -05:00
ptitle := syscall.StringToUTF16(*title)
2020-01-30 21:18:43 -05:00
var res uint32
s, _, err := wtsSendMessage.Call(
0, // WTS_CURRENT_SERVER_HANDLE
0xffffffff, // WTS_CURRENT_SESSION
uintptr(unsafe.Pointer(&ptitle[0])), uintptr(2*len(ptitle)),
uintptr(unsafe.Pointer(&ptext[0])), uintptr(2*len(ptext)),
flags, uintptr(timeout), uintptr(unsafe.Pointer(&res)), 0)
if s == 0 {
return err
}
return nil
}
2021-03-10 09:49:09 -05:00
// https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataw
2020-01-27 08:44:47 -05:00
type _NOTIFYICONDATA struct {
StructSize uint32
2021-03-10 09:49:09 -05:00
Wnd uintptr
2020-01-27 08:44:47 -05:00
ID uint32
Flags uint32
CallbackMessage uint32
Icon uintptr
2021-03-10 09:49:09 -05:00
Tip [128]uint16 // NOTIFYICONDATAA_V1_SIZE
2020-01-27 08:44:47 -05:00
State uint32
StateMask uint32
Info [256]uint16
Version uint32
InfoTitle [64]uint16
InfoFlags uint32
2021-03-10 09:49:09 -05:00
// GuidItem [16]byte // NOTIFYICONDATAA_V2_SIZE
// BalloonIcon syscall.Handle // NOTIFYICONDATAA_V3_SIZE
2020-01-26 11:04:49 -05:00
}