-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMainWindow.cs
143 lines (134 loc) · 4.88 KB
/
MainWindow.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using Nickvision.MPVSharp;
namespace Nickvision.MPVSharp.Examples.GirCore;
/// <summary>
/// Main application window
/// </summary>
public partial class MainWindow : Gtk.ApplicationWindow
{
private const uint GDK_KEY_Left = 0xff51;
private const uint GDK_KEY_Right = 0xff53;
private const uint GDK_KEY_space = 0x020;
private readonly Gtk.GLArea _glArea;
private readonly Client _player;
private RenderContext? _ctx;
/// <summary>
/// Construct window
/// </summary>
public MainWindow(Gtk.Application application)
{
SetSizeRequest(640, 400);
var header = Gtk.HeaderBar.New();
SetTitlebar(header);
var title = Gtk.Label.New("Loading...");
header.SetTitleWidget(title);
var pauseButton = Gtk.Button.New();
header.PackStart(pauseButton);
_glArea = Gtk.GLArea.New();
SetChild(_glArea);
_glArea.SetVexpand(true);
_glArea.SetHexpand(true);
// Create MPV client
_player = new Client();
_player.SetProperty("ytdl", true);
_player.RequestLogMessages("debug");
_player.LogMessageReceived += (sender, e) =>
{
Console.Write($"[{e.Prefix}] {e.Text}"); // Log messages (e.Text) end with newline char
};
_player.PropertyChanged += (sender, e) =>
{
if (e.Name == "pause")
{
pauseButton.SetIconName((bool)e.Node! ? "media-playback-start-symbolic" : "media-playback-pause-symbolic");
}
if (e.Name == "media-title")
{
title.SetLabel((string)e.Node!);
}
};
_player.ObserveProperty("pause");
_player.ObserveProperty("media-title");
pauseButton.OnClicked += (sender, e) => _player.CyclePause();
// Setup rendering
_glArea.OnRealize += OnRealizeGLArea;
_glArea.OnUnrealize += OnUnrealizeGLArea;
_glArea.OnRender += OnRenderGLArea;
// Keyboard shortcuts
var keyboardController = Gtk.EventControllerKey.New();
keyboardController.SetPropagationPhase(Gtk.PropagationPhase.Capture);
keyboardController.OnKeyPressed += OnKeyPressed;
keyboardController.OnKeyReleased += OnKeyReleased;
AddController(keyboardController);
}
/// <summary>
/// Occurs on GLArea initialization. Set up render context and start playing.
/// </summary>
/// <param name="sender">Gtk.Widget that invoked the event</param>
/// <param name="e">EventArgs</param>
private void OnRealizeGLArea(Gtk.Widget sender, EventArgs e)
{
_glArea.MakeCurrent();
_player.Initialize();
_ctx = _player.CreateRenderContext();
// We create callback for MPV to call every time the screen needs to be redrawn,
// the callback calls GtkGLArea.QueueDraw which in turn makes RenderContext draw image
_ctx.SetupGL((x) => GLib.Functions.IdleAdd(0, () =>
{
_glArea.QueueDraw(); // QueueDraw must be called from GTK thread
return false;
}));
_player.Command("loadfile https://www.youtube.com/watch?v=UXqq0ZvbOnk append-play");
}
/// <summary>
/// Occurs on GLArea destruction. Free MPV objects
/// </summary>
/// <param name="sender">Gtk.Widget that invoked the event</param>
/// <param name="e">EventArgs</param>
private void OnUnrealizeGLArea(Gtk.Widget sender, EventArgs e)
{
// Free RenderContext first, then the Client
_ctx?.Dispose();
_player.Dispose();
}
/// <summary>
/// Occurs on GLArea redraw. Call RenderContext to redraw image
/// </summary>
/// <param name="sender">Gtk.Widget that invoked the event</param>
/// <param name="e">EventArgs</param>
private bool OnRenderGLArea(Gtk.Widget sender, EventArgs e)
{
_ctx?.RenderGL(_glArea.GetAllocatedWidth(), _glArea.GetAllocatedHeight());
return false;
}
/// <summary>
/// Occurs when a key was pressed
/// </summary>
/// <param name="sender">Key controller</param>
/// <param name="e">Event args</param>
/// <returns>Whether the key press was handled or not</returns>
private bool OnKeyPressed(Gtk.EventControllerKey sender, Gtk.EventControllerKey.KeyPressedSignalArgs e)
{
switch (e.Keyval)
{
case GDK_KEY_Left:
_player.Seek(-1);
break;
case GDK_KEY_Right:
_player.Seek(1);
break;
};
return true;
}
/// <summary>
/// Occurs when a key was released
/// </summary>
/// <param name="sender">Key controller</param>
/// <param name="e">Event args</param>
private void OnKeyReleased(Gtk.EventControllerKey sender, Gtk.EventControllerKey.KeyReleasedSignalArgs e)
{
if (e.Keyval == GDK_KEY_space)
{
_player.CyclePause();
}
}
}