Window icons (windows).
This commit is contained in:
parent
61a5cfeeb5
commit
fcf0a22b42
3 changed files with 128 additions and 62 deletions
|
@ -422,6 +422,23 @@ func loadFlags() []zenity.Option {
|
||||||
opts = append(opts, zenity.Icon(ingestPath(icon)))
|
opts = append(opts, zenity.Icon(ingestPath(icon)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch windowIcon {
|
||||||
|
case "error", "dialog-error":
|
||||||
|
opts = append(opts, zenity.WindowIcon(zenity.ErrorIcon))
|
||||||
|
case "info", "dialog-information":
|
||||||
|
opts = append(opts, zenity.WindowIcon(zenity.InfoIcon))
|
||||||
|
case "question", "dialog-question":
|
||||||
|
opts = append(opts, zenity.WindowIcon(zenity.QuestionIcon))
|
||||||
|
case "important", "warning", "dialog-warning":
|
||||||
|
opts = append(opts, zenity.WindowIcon(zenity.WarningIcon))
|
||||||
|
case "dialog-password":
|
||||||
|
opts = append(opts, zenity.WindowIcon(zenity.PasswordIcon))
|
||||||
|
case "", unspecified:
|
||||||
|
//
|
||||||
|
default:
|
||||||
|
opts = append(opts, zenity.WindowIcon(ingestPath(windowIcon)))
|
||||||
|
}
|
||||||
|
|
||||||
// Message options
|
// Message options
|
||||||
|
|
||||||
if noWrap {
|
if noWrap {
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
package zenity
|
package zenity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"os"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
messageBox = user32.NewProc("MessageBoxW")
|
|
||||||
getDlgCtrlID = user32.NewProc("GetDlgCtrlID")
|
getDlgCtrlID = user32.NewProc("GetDlgCtrlID")
|
||||||
loadImage = user32.NewProc("LoadImageW")
|
messageBox = user32.NewProc("MessageBoxW")
|
||||||
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 {
|
||||||
|
@ -94,6 +89,13 @@ func message(kind messageKind, text string, opts options) error {
|
||||||
|
|
||||||
func hookMessageDialog(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) {
|
||||||
|
if opts.windowIcon != nil {
|
||||||
|
icon := getIcon(opts.windowIcon)
|
||||||
|
if icon.handle != 0 {
|
||||||
|
defer icon.delete()
|
||||||
|
sendMessage.Call(wnd, 0x0080 /*WM_SETICON*/, 0, icon.handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
enumChildWindows.Call(wnd,
|
enumChildWindows.Call(wnd,
|
||||||
syscall.NewCallback(hookMessageDialogCallback),
|
syscall.NewCallback(hookMessageDialogCallback),
|
||||||
uintptr(unsafe.Pointer(&opts)))
|
uintptr(unsafe.Pointer(&opts)))
|
||||||
|
@ -116,26 +118,11 @@ func hookMessageDialogCallback(wnd uintptr, lparam *options) uintptr {
|
||||||
setWindowText.Call(wnd, strptr(*text))
|
setWindowText.Call(wnd, strptr(*text))
|
||||||
}
|
}
|
||||||
|
|
||||||
if i, ok := lparam.icon.(string); ok && ctl == 20 /*IDC_STATIC_OK*/ {
|
if ctl == 20 /*IDC_STATIC_OK*/ {
|
||||||
var icon uintptr
|
icon := getIcon(lparam.icon)
|
||||||
data, _ := os.ReadFile(i)
|
if icon.handle != 0 {
|
||||||
switch {
|
defer icon.delete()
|
||||||
case bytes.HasPrefix(data, []byte("\x00\x00\x01\x00")):
|
sendMessage.Call(wnd, 0x0170 /*STM_SETICON*/, icon.handle, 0)
|
||||||
icon, _, _ = loadImage.Call(0,
|
|
||||||
strptr(i),
|
|
||||||
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 icon != 0 {
|
|
||||||
sendMessage.Call(wnd, 0x0170 /*STM_SETICON*/, icon, 0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
|
|
132
util_windows.go
132
util_windows.go
|
@ -1,6 +1,7 @@
|
||||||
package zenity
|
package zenity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -26,59 +27,63 @@ var (
|
||||||
user32 = windows.NewLazySystemDLL("user32.dll")
|
user32 = windows.NewLazySystemDLL("user32.dll")
|
||||||
wtsapi32 = windows.NewLazySystemDLL("wtsapi32.dll")
|
wtsapi32 = windows.NewLazySystemDLL("wtsapi32.dll")
|
||||||
|
|
||||||
initCommonControlsEx = comctl32.NewProc("InitCommonControlsEx")
|
|
||||||
commDlgExtendedError = comdlg32.NewProc("CommDlgExtendedError")
|
commDlgExtendedError = comdlg32.NewProc("CommDlgExtendedError")
|
||||||
|
initCommonControlsEx = comctl32.NewProc("InitCommonControlsEx")
|
||||||
|
|
||||||
|
createFontIndirect = gdi32.NewProc("CreateFontIndirectW")
|
||||||
deleteObject = gdi32.NewProc("DeleteObject")
|
deleteObject = gdi32.NewProc("DeleteObject")
|
||||||
getDeviceCaps = gdi32.NewProc("GetDeviceCaps")
|
getDeviceCaps = gdi32.NewProc("GetDeviceCaps")
|
||||||
createFontIndirect = gdi32.NewProc("CreateFontIndirectW")
|
|
||||||
|
|
||||||
getModuleHandle = kernel32.NewProc("GetModuleHandleW")
|
|
||||||
getCurrentThreadId = kernel32.NewProc("GetCurrentThreadId")
|
|
||||||
getConsoleWindow = kernel32.NewProc("GetConsoleWindow")
|
|
||||||
getSystemDirectory = kernel32.NewProc("GetSystemDirectoryW")
|
|
||||||
createActCtx = kernel32.NewProc("CreateActCtxW")
|
|
||||||
activateActCtx = kernel32.NewProc("ActivateActCtx")
|
activateActCtx = kernel32.NewProc("ActivateActCtx")
|
||||||
|
createActCtx = kernel32.NewProc("CreateActCtxW")
|
||||||
deactivateActCtx = kernel32.NewProc("DeactivateActCtx")
|
deactivateActCtx = kernel32.NewProc("DeactivateActCtx")
|
||||||
|
getConsoleWindow = kernel32.NewProc("GetConsoleWindow")
|
||||||
|
getCurrentThreadId = kernel32.NewProc("GetCurrentThreadId")
|
||||||
|
getModuleHandle = kernel32.NewProc("GetModuleHandleW")
|
||||||
|
getSystemDirectory = kernel32.NewProc("GetSystemDirectoryW")
|
||||||
|
|
||||||
coInitializeEx = ole32.NewProc("CoInitializeEx")
|
|
||||||
coUninitialize = ole32.NewProc("CoUninitialize")
|
|
||||||
coCreateInstance = ole32.NewProc("CoCreateInstance")
|
coCreateInstance = ole32.NewProc("CoCreateInstance")
|
||||||
|
coInitializeEx = ole32.NewProc("CoInitializeEx")
|
||||||
coTaskMemFree = ole32.NewProc("CoTaskMemFree")
|
coTaskMemFree = ole32.NewProc("CoTaskMemFree")
|
||||||
|
coUninitialize = ole32.NewProc("CoUninitialize")
|
||||||
|
|
||||||
getMessage = user32.NewProc("GetMessageW")
|
|
||||||
sendMessage = user32.NewProc("SendMessageW")
|
|
||||||
postQuitMessage = user32.NewProc("PostQuitMessage")
|
|
||||||
isDialogMessage = user32.NewProc("IsDialogMessageW")
|
|
||||||
dispatchMessage = user32.NewProc("DispatchMessageW")
|
|
||||||
translateMessage = user32.NewProc("TranslateMessage")
|
|
||||||
unhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx")
|
|
||||||
setWindowsHookEx = user32.NewProc("SetWindowsHookExW")
|
|
||||||
callNextHookEx = user32.NewProc("CallNextHookEx")
|
callNextHookEx = user32.NewProc("CallNextHookEx")
|
||||||
enumWindows = user32.NewProc("EnumWindows")
|
createIconFromResource = user32.NewProc("CreateIconFromResource")
|
||||||
|
createWindowEx = user32.NewProc("CreateWindowExW")
|
||||||
|
defWindowProc = user32.NewProc("DefWindowProcW")
|
||||||
|
destroyIcon = user32.NewProc("DestroyIcon")
|
||||||
|
destroyWindow = user32.NewProc("DestroyWindow")
|
||||||
|
dispatchMessage = user32.NewProc("DispatchMessageW")
|
||||||
|
enableWindow = user32.NewProc("EnableWindow")
|
||||||
enumChildWindows = user32.NewProc("EnumChildWindows")
|
enumChildWindows = user32.NewProc("EnumChildWindows")
|
||||||
setWindowText = user32.NewProc("SetWindowTextW")
|
enumWindows = user32.NewProc("EnumWindows")
|
||||||
|
getDpiForWindow = user32.NewProc("GetDpiForWindow")
|
||||||
|
getMessage = user32.NewProc("GetMessageW")
|
||||||
|
getSystemMetrics = user32.NewProc("GetSystemMetrics")
|
||||||
|
getWindowDC = user32.NewProc("GetWindowDC")
|
||||||
|
getWindowRect = user32.NewProc("GetWindowRect")
|
||||||
getWindowText = user32.NewProc("GetWindowTextW")
|
getWindowText = user32.NewProc("GetWindowTextW")
|
||||||
getWindowTextLength = user32.NewProc("GetWindowTextLengthW")
|
getWindowTextLength = user32.NewProc("GetWindowTextLengthW")
|
||||||
setForegroundWindow = user32.NewProc("SetForegroundWindow")
|
|
||||||
getWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId")
|
getWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId")
|
||||||
setThreadDpiAwarenessContext = user32.NewProc("SetThreadDpiAwarenessContext")
|
isDialogMessage = user32.NewProc("IsDialogMessageW")
|
||||||
getDpiForWindow = user32.NewProc("GetDpiForWindow")
|
loadIcon = user32.NewProc("LoadIconW")
|
||||||
releaseDC = user32.NewProc("ReleaseDC")
|
loadImage = user32.NewProc("LoadImageW")
|
||||||
getWindowDC = user32.NewProc("GetWindowDC")
|
postQuitMessage = user32.NewProc("PostQuitMessage")
|
||||||
systemParametersInfo = user32.NewProc("SystemParametersInfoW")
|
|
||||||
setWindowPos = user32.NewProc("SetWindowPos")
|
|
||||||
getWindowRect = user32.NewProc("GetWindowRect")
|
|
||||||
setWindowLong = user32.NewProc("SetWindowLongW")
|
|
||||||
getSystemMetrics = user32.NewProc("GetSystemMetrics")
|
|
||||||
unregisterClass = user32.NewProc("UnregisterClassW")
|
|
||||||
registerClassEx = user32.NewProc("RegisterClassExW")
|
registerClassEx = user32.NewProc("RegisterClassExW")
|
||||||
destroyWindow = user32.NewProc("DestroyWindow")
|
releaseDC = user32.NewProc("ReleaseDC")
|
||||||
createWindowEx = user32.NewProc("CreateWindowExW")
|
sendMessage = user32.NewProc("SendMessageW")
|
||||||
showWindow = user32.NewProc("ShowWindow")
|
|
||||||
enableWindow = user32.NewProc("EnableWindow")
|
|
||||||
setFocus = user32.NewProc("SetFocus")
|
setFocus = user32.NewProc("SetFocus")
|
||||||
defWindowProc = user32.NewProc("DefWindowProcW")
|
setForegroundWindow = user32.NewProc("SetForegroundWindow")
|
||||||
|
setThreadDpiAwarenessContext = user32.NewProc("SetThreadDpiAwarenessContext")
|
||||||
|
setWindowLong = user32.NewProc("SetWindowLongW")
|
||||||
|
setWindowPos = user32.NewProc("SetWindowPos")
|
||||||
|
setWindowsHookEx = user32.NewProc("SetWindowsHookExW")
|
||||||
|
setWindowText = user32.NewProc("SetWindowTextW")
|
||||||
|
showWindow = user32.NewProc("ShowWindow")
|
||||||
|
systemParametersInfo = user32.NewProc("SystemParametersInfoW")
|
||||||
|
translateMessage = user32.NewProc("TranslateMessage")
|
||||||
|
unhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx")
|
||||||
|
unregisterClass = user32.NewProc("UnregisterClassW")
|
||||||
)
|
)
|
||||||
|
|
||||||
func intptr(i int64) uintptr {
|
func intptr(i int64) uintptr {
|
||||||
|
@ -320,6 +325,63 @@ func (f *font) delete() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type icon struct {
|
||||||
|
handle uintptr
|
||||||
|
destroy bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIcon(i any) icon {
|
||||||
|
var res icon
|
||||||
|
var resource uintptr
|
||||||
|
switch i {
|
||||||
|
case ErrorIcon:
|
||||||
|
resource = 32513 // IDI_ERROR
|
||||||
|
case QuestionIcon:
|
||||||
|
resource = 32514 // IDI_QUESTION
|
||||||
|
case WarningIcon:
|
||||||
|
resource = 32515 // IDI_WARNING
|
||||||
|
case InfoIcon:
|
||||||
|
resource = 32516 // IDI_INFORMATION
|
||||||
|
}
|
||||||
|
if resource != 0 {
|
||||||
|
res.handle, _, _ = loadIcon.Call(0, resource)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
path, ok := i.(string)
|
||||||
|
if !ok {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case bytes.HasPrefix(data, []byte("\x00\x00\x01\x00")):
|
||||||
|
res.handle, _, _ = loadImage.Call(0,
|
||||||
|
strptr(path),
|
||||||
|
1, /*IMAGE_ICON*/
|
||||||
|
0, 0,
|
||||||
|
0x00008050 /*LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_SHARED*/)
|
||||||
|
case bytes.HasPrefix(data, []byte("\x89PNG\r\n\x1a\n")):
|
||||||
|
res.handle, _, _ = createIconFromResource.Call(
|
||||||
|
uintptr(unsafe.Pointer(&data[0])),
|
||||||
|
uintptr(len(data)),
|
||||||
|
1, 0x00030000)
|
||||||
|
res.destroy = true
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *icon) delete() {
|
||||||
|
if i.handle != 0 {
|
||||||
|
destroyIcon.Call(i.handle)
|
||||||
|
i.handle = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func centerWindow(wnd uintptr) {
|
func centerWindow(wnd uintptr) {
|
||||||
getMetric := func(i uintptr) int32 {
|
getMetric := func(i uintptr) int32 {
|
||||||
n, _, _ := getSystemMetrics.Call(i)
|
n, _, _ := getSystemMetrics.Call(i)
|
||||||
|
|
Loading…
Reference in a new issue