add icons to taskbar control buttons
This commit is contained in:
committed by
Drew Weymouth
parent
aedaa32de4
commit
041e4d3ba7
@@ -1,29 +1,131 @@
|
||||
//go:build windows
|
||||
|
||||
package windows
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lole32
|
||||
#include "taskbar_buttons.h"
|
||||
|
||||
extern void goButtonClicked(int);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var gTaskbarButtonCallback func(TaskbarButton)
|
||||
|
||||
func InitializeTaskbarButtons(hwnd uintptr, callback func(TaskbarButton)) error {
|
||||
gTaskbarButtonCallback = callback
|
||||
C.initialize_taskbar_buttons(unsafe.Pointer(hwnd), C.ThumbnailCallback(C.goButtonClicked))
|
||||
return nil
|
||||
}
|
||||
|
||||
//export goButtonClicked
|
||||
func goButtonClicked(buttonID C.int) {
|
||||
if gTaskbarButtonCallback != nil {
|
||||
gTaskbarButtonCallback(TaskbarButton(buttonID))
|
||||
}
|
||||
}
|
||||
//go:build windows
|
||||
|
||||
package windows
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lole32
|
||||
#include "taskbar_buttons.h"
|
||||
|
||||
extern void goButtonClicked(int);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var gTaskbarButtonCallback func(TaskbarButton)
|
||||
|
||||
// InitializeTaskbarIcons supplies the image icons that will be used for the taskbar buttons.
|
||||
// They must all have the same pixel dimensions.
|
||||
// This should be called before InitializeTaskbarButtons or the buttons will not have icons.
|
||||
func InitializeTaskbarIcons(prev, next, play, pause image.Image) error {
|
||||
pB := imageToBGRA(prev)
|
||||
nB := imageToBGRA(next)
|
||||
plB := imageToBGRA(play)
|
||||
paB := imageToBGRA(pause)
|
||||
bnds := prev.Bounds()
|
||||
|
||||
C.initialize_taskbar_icons(unsafe.Pointer(&pB[0]), unsafe.Pointer(&nB[0]), unsafe.Pointer(&plB[0]), unsafe.Pointer(&paB[0]), C.int(bnds.Dx()), C.int(bnds.Dy()))
|
||||
return nil
|
||||
}
|
||||
|
||||
func InitializeTaskbarButtons(hwnd uintptr, callback func(TaskbarButton)) error {
|
||||
gTaskbarButtonCallback = callback
|
||||
C.initialize_taskbar_buttons(unsafe.Pointer(hwnd), C.ThumbnailCallback(C.goButtonClicked))
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetTaskbarButtonIsPlaying(isPlaying bool) error {
|
||||
i := C.int(0)
|
||||
if isPlaying {
|
||||
i = C.int(1)
|
||||
}
|
||||
if ret := int(C.set_is_playing(i)); ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("failed to set taskbar button is playing state")
|
||||
}
|
||||
|
||||
//export goButtonClicked
|
||||
func goButtonClicked(buttonID C.int) {
|
||||
if gTaskbarButtonCallback != nil {
|
||||
gTaskbarButtonCallback(TaskbarButton(buttonID))
|
||||
}
|
||||
}
|
||||
|
||||
// imageToBGRA converts an image.Image to a BGRA byte slice.
|
||||
// For *image.RGBA, it un-premultiplies the colors to straight alpha.
|
||||
func imageToBGRA(img image.Image) []byte {
|
||||
bounds := img.Bounds()
|
||||
w, h := bounds.Dx(), bounds.Dy()
|
||||
bgra := make([]byte, w*h*4)
|
||||
|
||||
i := 0
|
||||
switch src := img.(type) {
|
||||
case *image.NRGBA:
|
||||
// Straight alpha, just swap channels
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
off := src.PixOffset(bounds.Min.X, y)
|
||||
for x := 0; x < w; x++ {
|
||||
r := src.Pix[off+0]
|
||||
g := src.Pix[off+1]
|
||||
b := src.Pix[off+2]
|
||||
a := src.Pix[off+3]
|
||||
bgra[i+0] = b
|
||||
bgra[i+1] = g
|
||||
bgra[i+2] = r
|
||||
bgra[i+3] = a
|
||||
off += 4
|
||||
i += 4
|
||||
}
|
||||
}
|
||||
|
||||
case *image.RGBA:
|
||||
// Premultiplied alpha, un-premultiply to straight alpha
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
off := src.PixOffset(bounds.Min.X, y)
|
||||
for x := 0; x < w; x++ {
|
||||
r := src.Pix[off+0]
|
||||
g := src.Pix[off+1]
|
||||
b := src.Pix[off+2]
|
||||
a := src.Pix[off+3]
|
||||
|
||||
if a != 0 {
|
||||
// Convert from premultiplied to straight alpha
|
||||
r = uint8((uint16(r) * 0xFF) / uint16(a))
|
||||
g = uint8((uint16(g) * 0xFF) / uint16(a))
|
||||
b = uint8((uint16(b) * 0xFF) / uint16(a))
|
||||
}
|
||||
|
||||
bgra[i+0] = b
|
||||
bgra[i+1] = g
|
||||
bgra[i+2] = r
|
||||
bgra[i+3] = a
|
||||
off += 4
|
||||
i += 4
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
// Fallback: handle any other image.Image type via At()
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
r16, g16, b16, a16 := img.At(x, y).RGBA()
|
||||
// Convert from 16-bit [0, 65535] to 8-bit [0, 255]
|
||||
r := uint8(r16 >> 8)
|
||||
g := uint8(g16 >> 8)
|
||||
b := uint8(b16 >> 8)
|
||||
a := uint8(a16 >> 8)
|
||||
bgra[i+0] = b
|
||||
bgra[i+1] = g
|
||||
bgra[i+2] = r
|
||||
bgra[i+3] = a
|
||||
i += 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bgra
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user