gtk4/subclass/
media_stream.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! Traits intended for subclassing [`MediaStream`](crate::MediaStream).
5
6use glib::translate::*;
7
8use crate::{ffi, prelude::*, subclass::prelude::*, MediaStream};
9
10pub trait MediaStreamImpl: MediaStreamImplExt + ObjectImpl {
11    /// Pauses playback of the stream.
12    ///
13    /// If the stream is not playing, do nothing.
14    fn pause(&self) {
15        self.parent_pause()
16    }
17
18    fn play(&self) -> bool {
19        self.parent_play()
20    }
21
22    /// Called by users to attach the media stream to a [`gdk::Surface`][crate::gdk::Surface] they manage.
23    ///
24    /// The stream can then access the resources of @surface for its
25    /// rendering purposes. In particular, media streams might want to
26    /// create a [`gdk::GLContext`][crate::gdk::GLContext] or sync to the [`gdk::FrameClock`][crate::gdk::FrameClock].
27    ///
28    /// Whoever calls this function is responsible for calling
29    /// [`MediaStreamExt::unrealize()`][crate::prelude::MediaStreamExt::unrealize()] before either the stream
30    /// or @surface get destroyed.
31    ///
32    /// Multiple calls to this function may happen from different
33    /// users of the video, even with the same @surface. Each of these
34    /// calls must be followed by its own call to
35    /// [`MediaStreamExt::unrealize()`][crate::prelude::MediaStreamExt::unrealize()].
36    ///
37    /// It is not required to call this function to make a media stream work.
38    /// ## `surface`
39    /// a [`gdk::Surface`][crate::gdk::Surface]
40    fn realize(&self, surface: gdk::Surface) {
41        self.parent_realize(surface)
42    }
43
44    /// Start a seek operation on @self to @timestamp.
45    ///
46    /// If @timestamp is out of range, it will be clamped.
47    ///
48    /// Seek operations may not finish instantly. While a
49    /// seek operation is in process, the [`seeking`][struct@crate::MediaStream#seeking]
50    /// property will be set.
51    ///
52    /// When calling gtk_media_stream_seek() during an
53    /// ongoing seek operation, the new seek will override
54    /// any pending seek.
55    /// ## `timestamp`
56    /// timestamp to seek to.
57    fn seek(&self, timestamp: i64) {
58        self.parent_seek(timestamp)
59    }
60
61    /// Undoes a previous call to gtk_media_stream_realize().
62    ///
63    /// This causes the stream to release all resources it had
64    /// allocated from @surface.
65    /// ## `surface`
66    /// the [`gdk::Surface`][crate::gdk::Surface] the stream was realized with
67    fn unrealize(&self, surface: gdk::Surface) {
68        self.parent_unrealize(surface)
69    }
70
71    fn update_audio(&self, muted: bool, volume: f64) {
72        self.parent_update_audio(muted, volume)
73    }
74}
75
76mod sealed {
77    pub trait Sealed {}
78    impl<T: super::MediaStreamImplExt> Sealed for T {}
79}
80
81pub trait MediaStreamImplExt: sealed::Sealed + ObjectSubclass {
82    fn parent_pause(&self) {
83        unsafe {
84            let data = Self::type_data();
85            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkMediaStreamClass;
86            let f = (*parent_class)
87                .pause
88                .expect("No parent class impl for \"pause\"");
89            f(self.obj().unsafe_cast_ref::<MediaStream>().to_glib_none().0)
90        }
91    }
92
93    // Returns true if successfully started playing
94    fn parent_play(&self) -> bool {
95        unsafe {
96            let data = Self::type_data();
97            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkMediaStreamClass;
98            if let Some(f) = (*parent_class).play {
99                return from_glib(f(self
100                    .obj()
101                    .unsafe_cast_ref::<MediaStream>()
102                    .to_glib_none()
103                    .0));
104            }
105            false
106        }
107    }
108
109    fn parent_realize(&self, surface: gdk::Surface) {
110        unsafe {
111            let data = Self::type_data();
112            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkMediaStreamClass;
113            let f = (*parent_class)
114                .realize
115                .expect("No parent class impl for \"realize\"");
116            f(
117                self.obj().unsafe_cast_ref::<MediaStream>().to_glib_none().0,
118                surface.to_glib_none().0,
119            )
120        }
121    }
122
123    fn parent_seek(&self, timestamp: i64) {
124        unsafe {
125            let data = Self::type_data();
126            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkMediaStreamClass;
127            let f = (*parent_class)
128                .seek
129                .expect("No parent class impl for \"realize\"");
130            f(
131                self.obj().unsafe_cast_ref::<MediaStream>().to_glib_none().0,
132                timestamp,
133            )
134        }
135    }
136
137    fn parent_unrealize(&self, surface: gdk::Surface) {
138        unsafe {
139            let data = Self::type_data();
140            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkMediaStreamClass;
141            let f = (*parent_class)
142                .unrealize
143                .expect("No parent class impl for \"unrealize\"");
144            f(
145                self.obj().unsafe_cast_ref::<MediaStream>().to_glib_none().0,
146                surface.to_glib_none().0,
147            )
148        }
149    }
150
151    fn parent_update_audio(&self, muted: bool, volume: f64) {
152        unsafe {
153            let data = Self::type_data();
154            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkMediaStreamClass;
155            let f = (*parent_class)
156                .update_audio
157                .expect("No parent class impl for \"update_audio\"");
158            f(
159                self.obj().unsafe_cast_ref::<MediaStream>().to_glib_none().0,
160                muted.into_glib(),
161                volume,
162            )
163        }
164    }
165}
166
167impl<T: MediaStreamImpl> MediaStreamImplExt for T {}
168
169unsafe impl<T: MediaStreamImpl> IsSubclassable<T> for MediaStream {
170    fn class_init(class: &mut glib::Class<Self>) {
171        Self::parent_class_init::<T>(class);
172
173        assert_initialized_main_thread!();
174
175        let klass = class.as_mut();
176        klass.pause = Some(media_stream_pause::<T>);
177        klass.play = Some(media_stream_play::<T>);
178        klass.realize = Some(media_stream_realize::<T>);
179        klass.seek = Some(media_stream_seek::<T>);
180        klass.unrealize = Some(media_stream_unrealize::<T>);
181        klass.update_audio = Some(media_stream_update_audio::<T>);
182    }
183}
184
185unsafe extern "C" fn media_stream_pause<T: MediaStreamImpl>(ptr: *mut ffi::GtkMediaStream) {
186    let instance = &*(ptr as *mut T::Instance);
187    let imp = instance.imp();
188
189    imp.pause()
190}
191
192unsafe extern "C" fn media_stream_play<T: MediaStreamImpl>(
193    ptr: *mut ffi::GtkMediaStream,
194) -> glib::ffi::gboolean {
195    let instance = &*(ptr as *mut T::Instance);
196    let imp = instance.imp();
197
198    imp.play().into_glib()
199}
200
201unsafe extern "C" fn media_stream_realize<T: MediaStreamImpl>(
202    ptr: *mut ffi::GtkMediaStream,
203    surface: *mut gdk::ffi::GdkSurface,
204) {
205    let instance = &*(ptr as *mut T::Instance);
206    let imp = instance.imp();
207
208    imp.realize(from_glib_none(surface))
209}
210
211unsafe extern "C" fn media_stream_seek<T: MediaStreamImpl>(
212    ptr: *mut ffi::GtkMediaStream,
213    timestamp: i64,
214) {
215    let instance = &*(ptr as *mut T::Instance);
216    let imp = instance.imp();
217
218    imp.seek(timestamp)
219}
220
221unsafe extern "C" fn media_stream_unrealize<T: MediaStreamImpl>(
222    ptr: *mut ffi::GtkMediaStream,
223    surface: *mut gdk::ffi::GdkSurface,
224) {
225    let instance = &*(ptr as *mut T::Instance);
226    let imp = instance.imp();
227
228    imp.unrealize(from_glib_none(surface))
229}
230
231unsafe extern "C" fn media_stream_update_audio<T: MediaStreamImpl>(
232    ptr: *mut ffi::GtkMediaStream,
233    muted: glib::ffi::gboolean,
234    volume: f64,
235) {
236    let instance = &*(ptr as *mut T::Instance);
237    let imp = instance.imp();
238
239    imp.update_audio(from_glib(muted), volume)
240}