add Windows taskbar control buttons (TODO: icons)
This commit is contained in:
committed by
Drew Weymouth
parent
21edd38f38
commit
aedaa32de4
+25
-11
@@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/dweymouth/supersonic/backend/player"
|
"github.com/dweymouth/supersonic/backend/player"
|
||||||
"github.com/dweymouth/supersonic/backend/player/mpv"
|
"github.com/dweymouth/supersonic/backend/player/mpv"
|
||||||
"github.com/dweymouth/supersonic/backend/util"
|
"github.com/dweymouth/supersonic/backend/util"
|
||||||
|
"github.com/dweymouth/supersonic/backend/windows"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"github.com/20after4/configdir"
|
"github.com/20after4/configdir"
|
||||||
@@ -49,7 +50,7 @@ type App struct {
|
|||||||
LocalPlayer *mpv.Player
|
LocalPlayer *mpv.Player
|
||||||
UpdateChecker UpdateChecker
|
UpdateChecker UpdateChecker
|
||||||
MPRISHandler *MPRISHandler
|
MPRISHandler *MPRISHandler
|
||||||
WinSMTC *SMTC
|
WinSMTC *windows.SMTC
|
||||||
ipcServer ipc.IPCServer
|
ipcServer ipc.IPCServer
|
||||||
LrcLibFetcher *LrcLibFetcher
|
LrcLibFetcher *LrcLibFetcher
|
||||||
|
|
||||||
@@ -378,7 +379,7 @@ func (a *App) setupMPRIS(mprisAppName string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) SetupWindowsSMTC(hwnd uintptr) {
|
func (a *App) SetupWindowsSMTC(hwnd uintptr) {
|
||||||
smtc, err := InitSMTCForWindow(hwnd)
|
smtc, err := windows.InitSMTCForWindow(hwnd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error initializing SMTC: %d", err)
|
log.Printf("error initializing SMTC: %d", err)
|
||||||
return
|
return
|
||||||
@@ -386,17 +387,17 @@ func (a *App) SetupWindowsSMTC(hwnd uintptr) {
|
|||||||
a.WinSMTC = smtc
|
a.WinSMTC = smtc
|
||||||
smtc.UpdateMetadata(a.displayAppName, "")
|
smtc.UpdateMetadata(a.displayAppName, "")
|
||||||
|
|
||||||
smtc.OnButtonPressed(func(btn SMTCButton) {
|
smtc.OnButtonPressed(func(btn windows.SMTCButton) {
|
||||||
switch btn {
|
switch btn {
|
||||||
case SMTCButtonPlay:
|
case windows.SMTCButtonPlay:
|
||||||
a.PlaybackManager.Continue()
|
a.PlaybackManager.Continue()
|
||||||
case SMTCButtonPause:
|
case windows.SMTCButtonPause:
|
||||||
a.PlaybackManager.Pause()
|
a.PlaybackManager.Pause()
|
||||||
case SMTCButtonNext:
|
case windows.SMTCButtonNext:
|
||||||
a.PlaybackManager.SeekNext()
|
a.PlaybackManager.SeekNext()
|
||||||
case SMTCButtonPrevious:
|
case windows.SMTCButtonPrevious:
|
||||||
a.PlaybackManager.SeekBackOrPrevious()
|
a.PlaybackManager.SeekBackOrPrevious()
|
||||||
case SMTCButtonStop:
|
case windows.SMTCButtonStop:
|
||||||
a.PlaybackManager.Stop()
|
a.PlaybackManager.Stop()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -425,15 +426,28 @@ func (a *App) SetupWindowsSMTC(hwnd uintptr) {
|
|||||||
})
|
})
|
||||||
a.PlaybackManager.OnPlaying(func() {
|
a.PlaybackManager.OnPlaying(func() {
|
||||||
smtc.SetEnabled(true)
|
smtc.SetEnabled(true)
|
||||||
smtc.UpdatePlaybackState(SMTCPlaybackStatePlaying)
|
smtc.UpdatePlaybackState(windows.SMTCPlaybackStatePlaying)
|
||||||
})
|
})
|
||||||
a.PlaybackManager.OnPaused(func() {
|
a.PlaybackManager.OnPaused(func() {
|
||||||
smtc.SetEnabled(true)
|
smtc.SetEnabled(true)
|
||||||
smtc.UpdatePlaybackState(SMTCPlaybackStatePaused)
|
smtc.UpdatePlaybackState(windows.SMTCPlaybackStatePaused)
|
||||||
})
|
})
|
||||||
a.PlaybackManager.OnStopped(func() {
|
a.PlaybackManager.OnStopped(func() {
|
||||||
smtc.SetEnabled(false)
|
smtc.SetEnabled(false)
|
||||||
smtc.UpdatePlaybackState(SMTCPlaybackStateStopped)
|
smtc.UpdatePlaybackState(windows.SMTCPlaybackStateStopped)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) SetupWindowsTaskbarButtons(hwnd uintptr) {
|
||||||
|
windows.InitializeTaskbarButtons(hwnd, func(btn windows.TaskbarButton) {
|
||||||
|
switch btn {
|
||||||
|
case windows.TaskbarButtonPrevious:
|
||||||
|
a.PlaybackManager.SeekBackOrPrevious()
|
||||||
|
case windows.TaskbarButtonPlayPause:
|
||||||
|
a.PlaybackManager.PlayPause()
|
||||||
|
case windows.TaskbarButtonNext:
|
||||||
|
a.PlaybackManager.SeekNext()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//go:build windows
|
//go:build windows
|
||||||
|
|
||||||
package backend
|
package windows
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo CFLAGS: -I .
|
#cgo CFLAGS: -I .
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
//go:build windows
|
//go:build windows
|
||||||
|
|
||||||
package backend
|
package windows
|
||||||
|
|
||||||
/*
|
/*
|
||||||
void btn_callback_cgo(int in) {
|
void btn_callback_cgo(int in) {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
//go:build !windows
|
//go:build !windows
|
||||||
|
|
||||||
package backend
|
package windows
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shobjidl.h>
|
||||||
|
#include <initguid.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "taskbar_buttons.h"
|
||||||
|
|
||||||
|
DEFINE_GUID(IID_ITaskbarList3,
|
||||||
|
0xEA1AFB91, 0x9E28, 0x4B86, 0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF);
|
||||||
|
|
||||||
|
static ITaskbarList3 *g_taskbar = NULL;
|
||||||
|
static ThumbnailCallback g_callback = NULL;
|
||||||
|
static HWND g_mainHWnd = NULL;
|
||||||
|
static WNDPROC g_originalProc = NULL;
|
||||||
|
|
||||||
|
THUMBBUTTON g_thumbButtons[3];
|
||||||
|
|
||||||
|
LRESULT CALLBACK OverrideWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||||
|
if (msg == WM_COMMAND) {
|
||||||
|
int buttonId = LOWORD(wParam);
|
||||||
|
if (g_callback) {
|
||||||
|
g_callback(buttonId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallWindowProc(g_originalProc, hwnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hook_window_proc(HWND hwnd) {
|
||||||
|
g_originalProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)OverrideWndProc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int initialize_taskbar_buttons(void *hwndPtr, ThumbnailCallback cb) {
|
||||||
|
g_callback = cb;
|
||||||
|
g_mainHWnd = (HWND)hwndPtr;
|
||||||
|
hook_window_proc(g_mainHWnd);
|
||||||
|
|
||||||
|
CoInitialize(NULL);
|
||||||
|
CoCreateInstance(&CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, &IID_ITaskbarList3, (void**)&g_taskbar);
|
||||||
|
|
||||||
|
if (g_taskbar) {
|
||||||
|
g_taskbar->lpVtbl->HrInit(g_taskbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_taskbar || !g_mainHWnd) return -1;
|
||||||
|
|
||||||
|
ZeroMemory(g_thumbButtons, sizeof(g_thumbButtons));
|
||||||
|
|
||||||
|
g_thumbButtons[0].dwMask = THB_FLAGS | THB_TOOLTIP;
|
||||||
|
g_thumbButtons[0].iId = 1;
|
||||||
|
g_thumbButtons[0].dwFlags = THBF_ENABLED;
|
||||||
|
wcscpy_s(g_thumbButtons[0].szTip, ARRAYSIZE(g_thumbButtons[0].szTip), L"Previous");
|
||||||
|
|
||||||
|
g_thumbButtons[1].dwMask = THB_FLAGS | THB_TOOLTIP;
|
||||||
|
g_thumbButtons[1].iId = 2;
|
||||||
|
g_thumbButtons[1].dwFlags = THBF_ENABLED;
|
||||||
|
wcscpy_s(g_thumbButtons[1].szTip, ARRAYSIZE(g_thumbButtons[1].szTip), L"Play");
|
||||||
|
|
||||||
|
g_thumbButtons[2].dwMask = THB_FLAGS | THB_TOOLTIP;
|
||||||
|
g_thumbButtons[2].iId = 3;
|
||||||
|
g_thumbButtons[2].dwFlags = THBF_ENABLED;
|
||||||
|
wcscpy_s(g_thumbButtons[2].szTip, ARRAYSIZE(g_thumbButtons[2].szTip), L"Next");
|
||||||
|
|
||||||
|
g_taskbar->lpVtbl->ThumbBarAddButtons(g_taskbar, g_mainHWnd, ARRAYSIZE(g_thumbButtons), g_thumbButtons);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
//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))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void (*ThumbnailCallback)(int buttonId);
|
||||||
|
|
||||||
|
int initialize_taskbar_buttons(void *hwndPtr, ThumbnailCallback cb);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package windows
|
||||||
|
|
||||||
|
type TaskbarButton int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TaskbarButtonPrevious TaskbarButton = 1
|
||||||
|
TaskbarButtonPlayPause TaskbarButton = 2
|
||||||
|
TaskbarButtonNext TaskbarButton = 3
|
||||||
|
)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
func InitializeTaskbarButtons(hwnd uintptr, callback func(TaskbarButton)) error {
|
||||||
|
return errors.New("taskbar buttons unsupported")
|
||||||
|
}
|
||||||
@@ -97,6 +97,7 @@ func main() {
|
|||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
hwnd := ctx.(driver.WindowsWindowContext).HWND
|
hwnd := ctx.(driver.WindowsWindowContext).HWND
|
||||||
myApp.SetupWindowsSMTC(hwnd)
|
myApp.SetupWindowsSMTC(hwnd)
|
||||||
|
myApp.SetupWindowsTaskbarButtons(hwnd)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user