VT_Player/cmd/gtkplayer/main.go

150 lines
3.3 KiB
Go

package main
import (
"flag"
"fmt"
"log"
"os"
"path/filepath"
"time"
"git.leaktechnologies.dev/stu/VT_Player/player/mpvembed"
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/gtk"
)
// simple GTK + mpv embedded player demo (single pane).
func main() {
flag.Parse()
gtk.Init(nil)
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
if err != nil {
log.Fatalf("window: %v", err)
}
win.SetTitle("VT Player (GTK/mpv)")
win.SetDefaultSize(1280, 720)
grid, _ := gtk.GridNew()
grid.SetColumnHomogeneous(true)
grid.SetRowHomogeneous(false)
win.Add(grid)
// Drawing area for mpv
da, _ := gtk.DrawingAreaNew()
da.SetHexpand(true)
da.SetVexpand(true)
grid.Attach(da, 0, 1, 4, 1)
// Controls
openBtn, _ := gtk.ButtonNewWithLabel("Open...")
playBtn, _ := gtk.ButtonNewWithLabel("Play")
pauseBtn, _ := gtk.ButtonNewWithLabel("Pause")
seekStartBtn, _ := gtk.ButtonNewWithLabel("<< Start")
grid.Attach(openBtn, 0, 0, 1, 1)
grid.Attach(playBtn, 1, 0, 1, 1)
grid.Attach(pauseBtn, 2, 0, 1, 1)
grid.Attach(seekStartBtn, 3, 0, 1, 1)
mpv, err := mpvembed.New()
if err != nil {
log.Fatalf("mpv: %v", err)
}
defer mpv.Destroy()
var duration float64
da.Connect("realize", func() {
w := da.GetWindow()
if w == nil {
log.Println("no window yet")
return
}
// Bind native window ID
if xid := getWindowID(w); xid != 0 {
_ = mpv.SetWID(xid)
}
// Set options and init
_ = mpv.SetOptionString("pause", "yes")
if err := mpv.Initialize(); err != nil {
log.Fatalf("mpv init: %v", err)
}
})
openBtn.Connect("clicked", func() {
dlg, _ := gtk.FileChooserDialogNewWith1Button("Open Video", win, gtk.FILE_CHOOSER_ACTION_OPEN, "Open", gtk.RESPONSE_ACCEPT)
if resp := dlg.Run(); resp == int(gtk.RESPONSE_ACCEPT) {
filename := dlg.GetFilename()
if filename != "" {
loadFile(mpv, filename, &duration)
}
}
dlg.Destroy()
})
playBtn.Connect("clicked", func() {
_ = mpv.SetPropertyBool("pause", false)
})
pauseBtn.Connect("clicked", func() {
_ = mpv.SetPropertyBool("pause", true)
})
seekStartBtn.Connect("clicked", func() {
_ = mpv.Command("seek", "0", "absolute", "exact")
})
// Progress poll
go func() {
t := time.NewTicker(250 * time.Millisecond)
defer t.Stop()
for range t.C {
pos, err := mpv.GetPropertyDouble("time-pos")
if err == nil && duration > 0 {
fmt.Printf("\r%.1f / %.1f", pos, duration)
}
}
}()
win.Connect("destroy", func() {
gtk.MainQuit()
})
win.ShowAll()
gtk.Main()
}
func loadFile(mpv *mpvembed.Client, path string, duration *float64) {
base := filepath.Base(path)
fmt.Printf("\nLoading: %s\n", base)
if err := mpv.Command("loadfile", path, "replace"); err != nil {
log.Printf("loadfile: %v", err)
}
if d, err := mpv.GetPropertyDouble("duration"); err == nil {
*duration = d
}
_ = mpv.SetPropertyBool("pause", false)
}
// getWindowID returns the native window handle (XID on X11, HWND on Windows).
func getWindowID(w *gdk.Window) uint64 {
// X11
if xid := gdkWindowGetXID(w); xid != 0 {
return xid
}
// TODO: add Windows handle if needed.
return 0
}
// gdkWindowGetXID extracts the XID from a GDK window when running on X11.
func gdkWindowGetXID(w *gdk.Window) uint64 {
type xidGetter interface {
GetXID() uint
}
if xw, ok := w.(xidGetter); ok {
return uint64(xw.GetXID())
}
return 0
}