1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | use std::mem; |
3 | |
4 | use glib::{prelude::*, translate::*}; |
5 | use gst::EventType; |
6 | |
7 | #[cfg (feature = "v1_22" )] |
8 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
9 | use crate::NavigationModifierType; |
10 | use crate::{ffi, NavigationCommand, NavigationEventType}; |
11 | |
12 | // FIXME: Copy from gstreamer/src/event.rs |
13 | macro_rules! event_builder_generic_impl { |
14 | ($new_fn:expr) => { |
15 | pub fn seqnum(self, seqnum: gst::Seqnum) -> Self { |
16 | Self { |
17 | seqnum: Some(seqnum), |
18 | ..self |
19 | } |
20 | } |
21 | |
22 | pub fn seqnum_if(self, seqnum: gst::Seqnum, predicate: bool) -> Self { |
23 | if predicate { |
24 | self.seqnum(seqnum) |
25 | } else { |
26 | self |
27 | } |
28 | } |
29 | |
30 | pub fn seqnum_if_some(self, seqnum: Option<gst::Seqnum>) -> Self { |
31 | if let Some(seqnum) = seqnum { |
32 | self.seqnum(seqnum) |
33 | } else { |
34 | self |
35 | } |
36 | } |
37 | |
38 | pub fn running_time_offset(self, running_time_offset: i64) -> Self { |
39 | Self { |
40 | running_time_offset: Some(running_time_offset), |
41 | ..self |
42 | } |
43 | } |
44 | |
45 | pub fn running_time_offset_if(self, running_time_offset: i64, predicate: bool) -> Self { |
46 | if predicate { |
47 | self.running_time_offset(running_time_offset) |
48 | } else { |
49 | self |
50 | } |
51 | } |
52 | |
53 | pub fn running_time_offset_if_some(self, running_time_offset: Option<i64>) -> Self { |
54 | if let Some(running_time_offset) = running_time_offset { |
55 | self.running_time_offset(running_time_offset) |
56 | } else { |
57 | self |
58 | } |
59 | } |
60 | |
61 | pub fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self { |
62 | let mut other_fields = self.other_fields; |
63 | other_fields.push((name, value.to_send_value())); |
64 | |
65 | Self { |
66 | other_fields, |
67 | ..self |
68 | } |
69 | } |
70 | |
71 | gst::impl_builder_gvalue_extra_setters!(other_field); |
72 | |
73 | #[deprecated = "use build.other_field() instead" ] |
74 | pub fn other_fields( |
75 | self, |
76 | other_fields: &[(&'a str, &'a (dyn ToSendValue + Sync))], |
77 | ) -> Self { |
78 | let mut s = self; |
79 | |
80 | for (name, value) in other_fields { |
81 | s = s.other_field(name, value.to_send_value()); |
82 | } |
83 | |
84 | s |
85 | } |
86 | |
87 | #[must_use = "Building the event without using it has no effect" ] |
88 | #[allow(clippy::redundant_closure_call)] |
89 | pub fn build(mut self) -> gst::Event { |
90 | skip_assert_initialized!(); |
91 | unsafe { |
92 | let event = $new_fn(&mut self); |
93 | if let Some(seqnum) = self.seqnum { |
94 | gst::ffi::gst_event_set_seqnum(event, seqnum.into_glib()); |
95 | } |
96 | |
97 | if let Some(running_time_offset) = self.running_time_offset { |
98 | gst::ffi::gst_event_set_running_time_offset(event, running_time_offset); |
99 | } |
100 | |
101 | { |
102 | let s = gst::StructureRef::from_glib_borrow_mut( |
103 | gst::ffi::gst_event_writable_structure(event), |
104 | ); |
105 | |
106 | for (k, v) in self.other_fields { |
107 | s.set_value(k, v); |
108 | } |
109 | } |
110 | |
111 | from_glib_full(event) |
112 | } |
113 | } |
114 | }; |
115 | } |
116 | |
117 | #[must_use = "The builder must be built to be used" ] |
118 | pub struct DownstreamForceKeyUnitEventBuilder<'a> { |
119 | seqnum: Option<gst::Seqnum>, |
120 | running_time_offset: Option<i64>, |
121 | other_fields: Vec<(&'a str, glib::SendValue)>, |
122 | timestamp: Option<gst::ClockTime>, |
123 | stream_time: Option<gst::ClockTime>, |
124 | running_time: Option<gst::ClockTime>, |
125 | all_headers: bool, |
126 | count: u32, |
127 | } |
128 | |
129 | impl<'a> DownstreamForceKeyUnitEventBuilder<'a> { |
130 | fn new() -> Self { |
131 | skip_assert_initialized!(); |
132 | Self { |
133 | seqnum: None, |
134 | running_time_offset: None, |
135 | other_fields: Vec::new(), |
136 | timestamp: gst::ClockTime::NONE, |
137 | stream_time: gst::ClockTime::NONE, |
138 | running_time: gst::ClockTime::NONE, |
139 | all_headers: true, |
140 | count: 0, |
141 | } |
142 | } |
143 | |
144 | pub fn timestamp(self, timestamp: impl Into<Option<gst::ClockTime>>) -> Self { |
145 | Self { |
146 | timestamp: timestamp.into(), |
147 | ..self |
148 | } |
149 | } |
150 | |
151 | pub fn timestamp_if(self, timestamp: gst::ClockTime, predicate: bool) -> Self { |
152 | if predicate { |
153 | self.timestamp(timestamp) |
154 | } else { |
155 | self |
156 | } |
157 | } |
158 | |
159 | pub fn timestamp_if_some(self, timestamp: Option<gst::ClockTime>) -> Self { |
160 | if let Some(timestamp) = timestamp { |
161 | self.timestamp(timestamp) |
162 | } else { |
163 | self |
164 | } |
165 | } |
166 | |
167 | pub fn stream_time(self, stream_time: impl Into<Option<gst::ClockTime>>) -> Self { |
168 | Self { |
169 | stream_time: stream_time.into(), |
170 | ..self |
171 | } |
172 | } |
173 | |
174 | pub fn stream_time_if(self, stream_time: gst::ClockTime, predicate: bool) -> Self { |
175 | if predicate { |
176 | self.stream_time(stream_time) |
177 | } else { |
178 | self |
179 | } |
180 | } |
181 | |
182 | pub fn stream_time_if_some(self, stream_time: Option<gst::ClockTime>) -> Self { |
183 | if let Some(stream_time) = stream_time { |
184 | self.stream_time(stream_time) |
185 | } else { |
186 | self |
187 | } |
188 | } |
189 | |
190 | pub fn running_time(self, running_time: impl Into<Option<gst::ClockTime>>) -> Self { |
191 | Self { |
192 | running_time: running_time.into(), |
193 | ..self |
194 | } |
195 | } |
196 | |
197 | pub fn running_time_if(self, running_time: gst::ClockTime, predicate: bool) -> Self { |
198 | if predicate { |
199 | self.running_time(running_time) |
200 | } else { |
201 | self |
202 | } |
203 | } |
204 | |
205 | pub fn running_time_if_some(self, running_time: Option<gst::ClockTime>) -> Self { |
206 | if let Some(running_time) = running_time { |
207 | self.running_time(running_time) |
208 | } else { |
209 | self |
210 | } |
211 | } |
212 | |
213 | pub fn all_headers(self, all_headers: bool) -> Self { |
214 | Self { |
215 | all_headers, |
216 | ..self |
217 | } |
218 | } |
219 | |
220 | pub fn all_headers_if_some(self, all_headers: Option<bool>) -> Self { |
221 | if let Some(all_headers) = all_headers { |
222 | self.all_headers(all_headers) |
223 | } else { |
224 | self |
225 | } |
226 | } |
227 | |
228 | pub fn count(self, count: u32) -> Self { |
229 | Self { count, ..self } |
230 | } |
231 | |
232 | pub fn count_if(self, count: u32, predicate: bool) -> Self { |
233 | if predicate { |
234 | self.count(count) |
235 | } else { |
236 | self |
237 | } |
238 | } |
239 | |
240 | pub fn count_if_some(self, count: Option<u32>) -> Self { |
241 | if let Some(count) = count { |
242 | self.count(count) |
243 | } else { |
244 | self |
245 | } |
246 | } |
247 | |
248 | event_builder_generic_impl!(|s: &mut Self| { |
249 | ffi::gst_video_event_new_downstream_force_key_unit( |
250 | s.timestamp.into_glib(), |
251 | s.stream_time.into_glib(), |
252 | s.running_time.into_glib(), |
253 | s.all_headers.into_glib(), |
254 | s.count, |
255 | ) |
256 | }); |
257 | } |
258 | |
259 | #[derive (Clone, PartialEq, Eq, Debug)] |
260 | pub struct DownstreamForceKeyUnitEvent { |
261 | pub timestamp: Option<gst::ClockTime>, |
262 | pub stream_time: Option<gst::ClockTime>, |
263 | pub running_time: Option<gst::ClockTime>, |
264 | pub all_headers: bool, |
265 | pub count: u32, |
266 | } |
267 | |
268 | impl DownstreamForceKeyUnitEvent { |
269 | pub fn builder<'a>() -> DownstreamForceKeyUnitEventBuilder<'a> { |
270 | assert_initialized_main_thread!(); |
271 | DownstreamForceKeyUnitEventBuilder::new() |
272 | } |
273 | |
274 | #[doc (alias = "gst_video_event_parse_downstream_force_key_unit" )] |
275 | pub fn parse(event: &gst::EventRef) -> Result<Self, glib::error::BoolError> { |
276 | skip_assert_initialized!(); |
277 | unsafe { |
278 | let mut timestamp = mem::MaybeUninit::uninit(); |
279 | let mut stream_time = mem::MaybeUninit::uninit(); |
280 | let mut running_time = mem::MaybeUninit::uninit(); |
281 | let mut all_headers = mem::MaybeUninit::uninit(); |
282 | let mut count = mem::MaybeUninit::uninit(); |
283 | |
284 | let res: bool = from_glib(ffi::gst_video_event_parse_downstream_force_key_unit( |
285 | event.as_mut_ptr(), |
286 | timestamp.as_mut_ptr(), |
287 | stream_time.as_mut_ptr(), |
288 | running_time.as_mut_ptr(), |
289 | all_headers.as_mut_ptr(), |
290 | count.as_mut_ptr(), |
291 | )); |
292 | if res { |
293 | Ok(Self { |
294 | timestamp: from_glib(timestamp.assume_init()), |
295 | stream_time: from_glib(stream_time.assume_init()), |
296 | running_time: from_glib(running_time.assume_init()), |
297 | all_headers: from_glib(all_headers.assume_init()), |
298 | count: count.assume_init(), |
299 | }) |
300 | } else { |
301 | Err(glib::bool_error!("Failed to parse GstEvent" )) |
302 | } |
303 | } |
304 | } |
305 | } |
306 | |
307 | #[must_use = "The builder must be built to be used" ] |
308 | pub struct UpstreamForceKeyUnitEventBuilder<'a> { |
309 | seqnum: Option<gst::Seqnum>, |
310 | running_time_offset: Option<i64>, |
311 | other_fields: Vec<(&'a str, glib::SendValue)>, |
312 | running_time: Option<gst::ClockTime>, |
313 | all_headers: bool, |
314 | count: u32, |
315 | } |
316 | |
317 | impl<'a> UpstreamForceKeyUnitEventBuilder<'a> { |
318 | fn new() -> Self { |
319 | skip_assert_initialized!(); |
320 | Self { |
321 | seqnum: None, |
322 | running_time_offset: None, |
323 | other_fields: Vec::new(), |
324 | running_time: gst::ClockTime::NONE, |
325 | all_headers: true, |
326 | count: 0, |
327 | } |
328 | } |
329 | |
330 | pub fn running_time(self, running_time: impl Into<Option<gst::ClockTime>>) -> Self { |
331 | Self { |
332 | running_time: running_time.into(), |
333 | ..self |
334 | } |
335 | } |
336 | |
337 | pub fn running_time_if(self, running_time: gst::ClockTime, predicate: bool) -> Self { |
338 | if predicate { |
339 | self.running_time(running_time) |
340 | } else { |
341 | self |
342 | } |
343 | } |
344 | |
345 | pub fn running_time_if_some(self, running_time: Option<gst::ClockTime>) -> Self { |
346 | if let Some(running_time) = running_time { |
347 | self.running_time(running_time) |
348 | } else { |
349 | self |
350 | } |
351 | } |
352 | |
353 | pub fn all_headers(self, all_headers: bool) -> Self { |
354 | Self { |
355 | all_headers, |
356 | ..self |
357 | } |
358 | } |
359 | |
360 | pub fn all_headers_if_some(self, all_headers: Option<bool>) -> Self { |
361 | if let Some(all_headers) = all_headers { |
362 | self.all_headers(all_headers) |
363 | } else { |
364 | self |
365 | } |
366 | } |
367 | |
368 | pub fn count(self, count: u32) -> Self { |
369 | Self { count, ..self } |
370 | } |
371 | |
372 | pub fn count_if(self, count: u32, predicate: bool) -> Self { |
373 | if predicate { |
374 | self.count(count) |
375 | } else { |
376 | self |
377 | } |
378 | } |
379 | |
380 | pub fn count_if_some(self, count: Option<u32>) -> Self { |
381 | if let Some(count) = count { |
382 | self.count(count) |
383 | } else { |
384 | self |
385 | } |
386 | } |
387 | |
388 | event_builder_generic_impl!(|s: &mut Self| { |
389 | ffi::gst_video_event_new_upstream_force_key_unit( |
390 | s.running_time.into_glib(), |
391 | s.all_headers.into_glib(), |
392 | s.count, |
393 | ) |
394 | }); |
395 | } |
396 | |
397 | #[derive (Clone, PartialEq, Eq, Debug)] |
398 | pub struct UpstreamForceKeyUnitEvent { |
399 | pub running_time: Option<gst::ClockTime>, |
400 | pub all_headers: bool, |
401 | pub count: u32, |
402 | } |
403 | |
404 | impl UpstreamForceKeyUnitEvent { |
405 | pub fn builder<'a>() -> UpstreamForceKeyUnitEventBuilder<'a> { |
406 | assert_initialized_main_thread!(); |
407 | UpstreamForceKeyUnitEventBuilder::new() |
408 | } |
409 | |
410 | #[doc (alias = "gst_video_event_parse_upstream_force_key_unit" )] |
411 | pub fn parse(event: &gst::EventRef) -> Result<Self, glib::error::BoolError> { |
412 | skip_assert_initialized!(); |
413 | unsafe { |
414 | let mut running_time = mem::MaybeUninit::uninit(); |
415 | let mut all_headers = mem::MaybeUninit::uninit(); |
416 | let mut count = mem::MaybeUninit::uninit(); |
417 | |
418 | let res: bool = from_glib(ffi::gst_video_event_parse_upstream_force_key_unit( |
419 | event.as_mut_ptr(), |
420 | running_time.as_mut_ptr(), |
421 | all_headers.as_mut_ptr(), |
422 | count.as_mut_ptr(), |
423 | )); |
424 | if res { |
425 | Ok(Self { |
426 | running_time: from_glib(running_time.assume_init()), |
427 | all_headers: from_glib(all_headers.assume_init()), |
428 | count: count.assume_init(), |
429 | }) |
430 | } else { |
431 | Err(glib::bool_error!("Failed to parse GstEvent" )) |
432 | } |
433 | } |
434 | } |
435 | } |
436 | |
437 | #[derive (Clone, PartialEq, Eq, Debug)] |
438 | pub enum ForceKeyUnitEvent { |
439 | Downstream(DownstreamForceKeyUnitEvent), |
440 | Upstream(UpstreamForceKeyUnitEvent), |
441 | } |
442 | |
443 | impl ForceKeyUnitEvent { |
444 | #[doc (alias = "gst_video_event_is_force_key_unit" )] |
445 | pub fn is(event: &gst::EventRef) -> bool { |
446 | skip_assert_initialized!(); |
447 | unsafe { from_glib(val:ffi::gst_video_event_is_force_key_unit(event.as_mut_ptr())) } |
448 | } |
449 | |
450 | pub fn parse(event: &gst::EventRef) -> Result<Self, glib::error::BoolError> { |
451 | skip_assert_initialized!(); |
452 | if event.is_upstream() { |
453 | UpstreamForceKeyUnitEvent::parse(event).map(Self::Upstream) |
454 | } else { |
455 | DownstreamForceKeyUnitEvent::parse(event).map(Self::Downstream) |
456 | } |
457 | } |
458 | } |
459 | |
460 | #[must_use = "The builder must be built to be used" ] |
461 | pub struct StillFrameEventBuilder<'a> { |
462 | seqnum: Option<gst::Seqnum>, |
463 | running_time_offset: Option<i64>, |
464 | other_fields: Vec<(&'a str, glib::SendValue)>, |
465 | in_still: bool, |
466 | } |
467 | |
468 | impl<'a> StillFrameEventBuilder<'a> { |
469 | fn new(in_still: bool) -> Self { |
470 | skip_assert_initialized!(); |
471 | Self { |
472 | seqnum: None, |
473 | running_time_offset: None, |
474 | other_fields: Vec::new(), |
475 | in_still, |
476 | } |
477 | } |
478 | |
479 | event_builder_generic_impl!(|s: &mut Self| ffi::gst_video_event_new_still_frame( |
480 | s.in_still.into_glib() |
481 | )); |
482 | } |
483 | |
484 | #[derive (Clone, PartialEq, Eq, Debug)] |
485 | pub struct StillFrameEvent { |
486 | pub in_still: bool, |
487 | } |
488 | |
489 | impl StillFrameEvent { |
490 | pub fn builder<'a>(in_still: bool) -> StillFrameEventBuilder<'a> { |
491 | assert_initialized_main_thread!(); |
492 | StillFrameEventBuilder::new(in_still) |
493 | } |
494 | |
495 | #[doc (alias = "gst_video_event_parse_still_frame" )] |
496 | pub fn parse(event: &gst::EventRef) -> Result<Self, glib::error::BoolError> { |
497 | skip_assert_initialized!(); |
498 | unsafe { |
499 | let mut in_still = mem::MaybeUninit::uninit(); |
500 | |
501 | let res: bool = from_glib(ffi::gst_video_event_parse_still_frame( |
502 | event.as_mut_ptr(), |
503 | in_still.as_mut_ptr(), |
504 | )); |
505 | if res { |
506 | Ok(Self { |
507 | in_still: from_glib(in_still.assume_init()), |
508 | }) |
509 | } else { |
510 | Err(glib::bool_error!("Invalid still-frame event" )) |
511 | } |
512 | } |
513 | } |
514 | } |
515 | |
516 | macro_rules! nav_event_builder { |
517 | ($builder:ident, $($event_field:ident: $event_type:ty,)? [$( $field_names:ident : $field_types:ty),*], $new_fn: expr) => { |
518 | #[must_use = "The builder must be built to be used" ] |
519 | pub struct $builder<'a> { |
520 | seqnum: Option<gst::Seqnum>, |
521 | running_time_offset: Option<i64>, |
522 | other_fields: Vec<(&'a str, glib::SendValue)>, |
523 | $($field_names: $field_types,)* |
524 | #[cfg(feature = "v1_22" )] |
525 | #[cfg_attr(docsrs, doc(cfg(feature = "v1_22" )))] |
526 | modifier_state: NavigationModifierType, |
527 | $($event_field: $event_type,)? |
528 | } |
529 | |
530 | impl<'a> $builder<'a> { |
531 | fn new($($event_field: $event_type)?) -> Self { |
532 | skip_assert_initialized!(); |
533 | Self { |
534 | seqnum: None, |
535 | running_time_offset: None, |
536 | other_fields: Vec::new(), |
537 | $($field_names: <$field_types>::default(),)* |
538 | #[cfg(feature = "v1_22" )] |
539 | #[cfg_attr(docsrs, doc(cfg(feature = "v1_22" )))] |
540 | modifier_state: NavigationModifierType::empty(), |
541 | $($event_field,)? |
542 | } |
543 | } |
544 | |
545 | $(pub fn $field_names(self, $field_names: $field_types) -> Self { |
546 | Self { $field_names, ..self } |
547 | })* |
548 | |
549 | #[cfg(feature = "v1_22" )] |
550 | #[cfg_attr(docsrs, doc(cfg(feature = "v1_22" )))] |
551 | pub fn modifier_state(self, modifier_state: NavigationModifierType) -> Self { |
552 | Self { modifier_state, ..self } |
553 | } |
554 | |
555 | event_builder_generic_impl!($new_fn); |
556 | } |
557 | }; |
558 | } |
559 | |
560 | pub enum KeyEventType<'a> { |
561 | Press { key: &'a str }, |
562 | Release { key: &'a str }, |
563 | } |
564 | |
565 | nav_event_builder!( |
566 | KeyEventBuilder, |
567 | kind: KeyEventType<'a>, |
568 | [], |
569 | |s: &mut Self| { |
570 | let event = match s.kind { |
571 | KeyEventType::Press { key } => NavigationEvent::KeyPress { |
572 | key: key.to_owned(), |
573 | #[cfg (feature = "v1_22" )] |
574 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
575 | modifier_state: s.modifier_state, |
576 | }, |
577 | KeyEventType::Release { key } => NavigationEvent::KeyRelease { |
578 | key: key.to_owned(), |
579 | #[cfg (feature = "v1_22" )] |
580 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
581 | modifier_state: s.modifier_state, |
582 | }, |
583 | }; |
584 | gst::ffi::gst_event_new_navigation(event.structure().into_glib_ptr()) |
585 | } |
586 | ); |
587 | |
588 | pub enum MouseEventType { |
589 | Move, |
590 | Press { |
591 | button: i32, |
592 | }, |
593 | Release { |
594 | button: i32, |
595 | }, |
596 | #[cfg (feature = "v1_18" )] |
597 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_18" )))] |
598 | Scroll { |
599 | delta_x: f64, |
600 | delta_y: f64, |
601 | }, |
602 | #[cfg (feature = "v1_26" )] |
603 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_26" )))] |
604 | DoubleClick { |
605 | button: i32, |
606 | }, |
607 | } |
608 | |
609 | nav_event_builder!( |
610 | MouseEventBuilder, |
611 | kind: MouseEventType, |
612 | [x: f64, y: f64], |
613 | |s: &mut Self| { |
614 | let event = match s.kind { |
615 | MouseEventType::Move => NavigationEvent::MouseMove { |
616 | x: s.x, |
617 | y: s.y, |
618 | #[cfg (feature = "v1_22" )] |
619 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
620 | modifier_state: s.modifier_state, |
621 | }, |
622 | MouseEventType::Press { button } => NavigationEvent::MouseButtonPress { |
623 | button, |
624 | x: s.x, |
625 | y: s.y, |
626 | #[cfg (feature = "v1_22" )] |
627 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
628 | modifier_state: s.modifier_state, |
629 | }, |
630 | MouseEventType::Release { button } => NavigationEvent::MouseButtonRelease { |
631 | button, |
632 | x: s.x, |
633 | y: s.y, |
634 | #[cfg (feature = "v1_22" )] |
635 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
636 | modifier_state: s.modifier_state, |
637 | }, |
638 | #[cfg (feature = "v1_18" )] |
639 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_18" )))] |
640 | MouseEventType::Scroll { delta_x, delta_y } => NavigationEvent::MouseScroll { |
641 | x: s.x, |
642 | y: s.y, |
643 | delta_x, |
644 | delta_y, |
645 | #[cfg (feature = "v1_22" )] |
646 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
647 | modifier_state: s.modifier_state, |
648 | }, |
649 | #[cfg (feature = "v1_26" )] |
650 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_26" )))] |
651 | MouseEventType::DoubleClick { button } => NavigationEvent::MouseDoubleClick { |
652 | button, |
653 | x: s.x, |
654 | y: s.y, |
655 | modifier_state: s.modifier_state, |
656 | }, |
657 | }; |
658 | gst::ffi::gst_event_new_navigation(event.structure().into_glib_ptr()) |
659 | } |
660 | ); |
661 | |
662 | #[must_use = "The builder must be built to be used" ] |
663 | pub struct CommandEventBuilder<'a> { |
664 | seqnum: Option<gst::Seqnum>, |
665 | running_time_offset: Option<i64>, |
666 | other_fields: Vec<(&'a str, glib::SendValue)>, |
667 | command: NavigationCommand, |
668 | #[cfg (feature = "v1_22" )] |
669 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
670 | modifier_state: NavigationModifierType, |
671 | } |
672 | |
673 | impl<'a> CommandEventBuilder<'a> { |
674 | fn new(command: NavigationCommand) -> Self { |
675 | skip_assert_initialized!(); |
676 | Self { |
677 | seqnum: None, |
678 | running_time_offset: None, |
679 | other_fields: Vec::new(), |
680 | command, |
681 | #[cfg (feature = "v1_22" )] |
682 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
683 | modifier_state: NavigationModifierType::empty(), |
684 | } |
685 | } |
686 | |
687 | #[cfg (feature = "v1_22" )] |
688 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
689 | pub fn modifier_state(self, modifier_state: NavigationModifierType) -> Self { |
690 | Self { |
691 | modifier_state, |
692 | ..self |
693 | } |
694 | } |
695 | |
696 | event_builder_generic_impl!(|s: &mut Self| { |
697 | let event = NavigationEvent::Command { |
698 | command: s.command, |
699 | #[cfg (feature = "v1_22" )] |
700 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
701 | modifier_state: s.modifier_state, |
702 | }; |
703 | gst::ffi::gst_event_new_navigation(event.structure().into_glib_ptr()) |
704 | }); |
705 | } |
706 | |
707 | #[cfg (feature = "v1_22" )] |
708 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
709 | pub enum TouchEventType { |
710 | Down { pressure: f64 }, |
711 | Motion { pressure: f64 }, |
712 | Up, |
713 | } |
714 | |
715 | #[cfg (feature = "v1_22" )] |
716 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
717 | nav_event_builder!( |
718 | TouchEventBuilder, |
719 | kind: TouchEventType, |
720 | [identifier: u32, x: f64, y: f64], |
721 | |s: &mut Self| { |
722 | let event = match s.kind { |
723 | TouchEventType::Down { pressure } => NavigationEvent::TouchDown { |
724 | identifier: s.identifier, |
725 | x: s.x, |
726 | y: s.y, |
727 | modifier_state: s.modifier_state, |
728 | pressure, |
729 | }, |
730 | TouchEventType::Motion { pressure } => NavigationEvent::TouchMotion { |
731 | identifier: s.identifier, |
732 | x: s.x, |
733 | y: s.y, |
734 | modifier_state: s.modifier_state, |
735 | pressure, |
736 | }, |
737 | TouchEventType::Up => NavigationEvent::TouchUp { |
738 | identifier: s.identifier, |
739 | x: s.x, |
740 | y: s.y, |
741 | modifier_state: s.modifier_state, |
742 | }, |
743 | }; |
744 | gst::ffi::gst_event_new_navigation(event.structure().into_glib_ptr()) |
745 | } |
746 | ); |
747 | |
748 | #[cfg (feature = "v1_22" )] |
749 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
750 | pub enum TouchMetaEventType { |
751 | Frame, |
752 | Cancel, |
753 | } |
754 | |
755 | #[cfg (feature = "v1_22" )] |
756 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
757 | nav_event_builder!( |
758 | TouchMetaEventBuilder, |
759 | kind: TouchMetaEventType, |
760 | [], |
761 | |s: &mut Self| { |
762 | let event = match s.kind { |
763 | TouchMetaEventType::Frame => NavigationEvent::TouchFrame { |
764 | modifier_state: s.modifier_state, |
765 | }, |
766 | TouchMetaEventType::Cancel => NavigationEvent::TouchCancel { |
767 | modifier_state: s.modifier_state, |
768 | }, |
769 | }; |
770 | gst::ffi::gst_event_new_navigation(event.structure().into_glib_ptr()) |
771 | } |
772 | ); |
773 | |
774 | const NAVIGATION_EVENT_NAME: &str = "application/x-gst-navigation" ; |
775 | #[cfg_attr (feature = "serde" , derive(serde::Serialize, serde::Deserialize))] |
776 | #[cfg_attr (feature = "serde" , serde(tag = "event" ))] |
777 | #[derive (Clone, PartialEq, Debug)] |
778 | pub enum NavigationEvent { |
779 | KeyPress { |
780 | key: String, |
781 | #[cfg (feature = "v1_22" )] |
782 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
783 | modifier_state: NavigationModifierType, |
784 | }, |
785 | KeyRelease { |
786 | key: String, |
787 | #[cfg (feature = "v1_22" )] |
788 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
789 | modifier_state: NavigationModifierType, |
790 | }, |
791 | MouseMove { |
792 | x: f64, |
793 | y: f64, |
794 | #[cfg (feature = "v1_22" )] |
795 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
796 | modifier_state: NavigationModifierType, |
797 | }, |
798 | MouseButtonPress { |
799 | button: i32, |
800 | x: f64, |
801 | y: f64, |
802 | #[cfg (feature = "v1_22" )] |
803 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
804 | modifier_state: NavigationModifierType, |
805 | }, |
806 | MouseButtonRelease { |
807 | button: i32, |
808 | x: f64, |
809 | y: f64, |
810 | #[cfg (feature = "v1_22" )] |
811 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
812 | modifier_state: NavigationModifierType, |
813 | }, |
814 | Command { |
815 | command: NavigationCommand, |
816 | #[cfg (feature = "v1_22" )] |
817 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
818 | modifier_state: NavigationModifierType, |
819 | }, |
820 | #[cfg (feature = "v1_18" )] |
821 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_18" )))] |
822 | MouseScroll { |
823 | x: f64, |
824 | y: f64, |
825 | delta_x: f64, |
826 | delta_y: f64, |
827 | #[cfg (feature = "v1_22" )] |
828 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
829 | modifier_state: NavigationModifierType, |
830 | }, |
831 | #[cfg (feature = "v1_22" )] |
832 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
833 | TouchDown { |
834 | identifier: u32, |
835 | x: f64, |
836 | y: f64, |
837 | pressure: f64, |
838 | modifier_state: NavigationModifierType, |
839 | }, |
840 | #[cfg (feature = "v1_22" )] |
841 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
842 | TouchMotion { |
843 | identifier: u32, |
844 | x: f64, |
845 | y: f64, |
846 | pressure: f64, |
847 | modifier_state: NavigationModifierType, |
848 | }, |
849 | #[cfg (feature = "v1_22" )] |
850 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
851 | TouchUp { |
852 | identifier: u32, |
853 | x: f64, |
854 | y: f64, |
855 | modifier_state: NavigationModifierType, |
856 | }, |
857 | #[cfg (feature = "v1_22" )] |
858 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
859 | TouchFrame { |
860 | modifier_state: NavigationModifierType, |
861 | }, |
862 | #[cfg (feature = "v1_22" )] |
863 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
864 | TouchCancel { |
865 | modifier_state: NavigationModifierType, |
866 | }, |
867 | #[cfg (feature = "v1_26" )] |
868 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_26" )))] |
869 | MouseDoubleClick { |
870 | button: i32, |
871 | x: f64, |
872 | y: f64, |
873 | modifier_state: NavigationModifierType, |
874 | }, |
875 | } |
876 | |
877 | impl NavigationEvent { |
878 | #[doc (alias = "gst_navigation_event_new_key_press" )] |
879 | pub fn new_key_press(key: &str) -> NavigationEvent { |
880 | assert_initialized_main_thread!(); |
881 | Self::KeyPress { |
882 | key: key.to_string(), |
883 | #[cfg (feature = "v1_22" )] |
884 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
885 | modifier_state: NavigationModifierType::empty(), |
886 | } |
887 | } |
888 | |
889 | #[doc (alias = "gst_navigation_event_new_key_release" )] |
890 | pub fn new_key_release(key: &str) -> NavigationEvent { |
891 | assert_initialized_main_thread!(); |
892 | Self::KeyRelease { |
893 | key: key.to_string(), |
894 | #[cfg (feature = "v1_22" )] |
895 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
896 | modifier_state: NavigationModifierType::empty(), |
897 | } |
898 | } |
899 | |
900 | #[doc (alias = "gst_navigation_event_new_mouse_move" )] |
901 | pub fn new_mouse_move(x: f64, y: f64) -> NavigationEvent { |
902 | assert_initialized_main_thread!(); |
903 | Self::MouseMove { |
904 | x, |
905 | y, |
906 | #[cfg (feature = "v1_22" )] |
907 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
908 | modifier_state: NavigationModifierType::empty(), |
909 | } |
910 | } |
911 | |
912 | #[doc (alias = "gst_navigation_event_new_mouse_button_press" )] |
913 | pub fn new_mouse_button_press(button: i32, x: f64, y: f64) -> NavigationEvent { |
914 | assert_initialized_main_thread!(); |
915 | Self::MouseButtonPress { |
916 | button, |
917 | x, |
918 | y, |
919 | #[cfg (feature = "v1_22" )] |
920 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
921 | modifier_state: NavigationModifierType::empty(), |
922 | } |
923 | } |
924 | |
925 | #[doc (alias = "gst_navigation_event_new_mouse_button_release" )] |
926 | pub fn new_mouse_button_release(button: i32, x: f64, y: f64) -> NavigationEvent { |
927 | assert_initialized_main_thread!(); |
928 | Self::MouseButtonRelease { |
929 | button, |
930 | x, |
931 | y, |
932 | #[cfg (feature = "v1_22" )] |
933 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
934 | modifier_state: NavigationModifierType::empty(), |
935 | } |
936 | } |
937 | |
938 | #[cfg (feature = "v1_18" )] |
939 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_18" )))] |
940 | #[doc (alias = "gst_navigation_event_new_mouse_scroll" )] |
941 | pub fn new_mouse_scroll(x: f64, y: f64, delta_x: f64, delta_y: f64) -> NavigationEvent { |
942 | assert_initialized_main_thread!(); |
943 | Self::MouseScroll { |
944 | x, |
945 | y, |
946 | delta_x, |
947 | delta_y, |
948 | #[cfg (feature = "v1_22" )] |
949 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
950 | modifier_state: NavigationModifierType::empty(), |
951 | } |
952 | } |
953 | |
954 | #[doc (alias = "gst_navigation_event_new_command" )] |
955 | pub fn new_command(command: NavigationCommand) -> NavigationEvent { |
956 | assert_initialized_main_thread!(); |
957 | Self::Command { |
958 | command, |
959 | #[cfg (feature = "v1_22" )] |
960 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
961 | modifier_state: NavigationModifierType::empty(), |
962 | } |
963 | } |
964 | |
965 | #[cfg (feature = "v1_22" )] |
966 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
967 | #[doc (alias = "gst_navigation_event_new_touch_down" )] |
968 | pub fn new_touch_down(identifier: u32, x: f64, y: f64, pressure: f64) -> NavigationEvent { |
969 | assert_initialized_main_thread!(); |
970 | Self::TouchDown { |
971 | identifier, |
972 | x, |
973 | y, |
974 | pressure, |
975 | modifier_state: NavigationModifierType::empty(), |
976 | } |
977 | } |
978 | |
979 | #[cfg (feature = "v1_22" )] |
980 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
981 | #[doc (alias = "gst_navigation_event_new_touch_motion" )] |
982 | pub fn new_touch_motion(identifier: u32, x: f64, y: f64, pressure: f64) -> NavigationEvent { |
983 | assert_initialized_main_thread!(); |
984 | Self::TouchMotion { |
985 | identifier, |
986 | x, |
987 | y, |
988 | pressure, |
989 | modifier_state: NavigationModifierType::empty(), |
990 | } |
991 | } |
992 | |
993 | #[cfg (feature = "v1_22" )] |
994 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
995 | #[doc (alias = "gst_navigation_event_new_touch_up" )] |
996 | pub fn new_touch_up(identifier: u32, x: f64, y: f64) -> NavigationEvent { |
997 | assert_initialized_main_thread!(); |
998 | Self::TouchUp { |
999 | identifier, |
1000 | x, |
1001 | y, |
1002 | modifier_state: NavigationModifierType::empty(), |
1003 | } |
1004 | } |
1005 | |
1006 | #[cfg (feature = "v1_22" )] |
1007 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1008 | #[doc (alias = "gst_navigation_event_new_touch_frame" )] |
1009 | pub fn new_touch_frame() -> NavigationEvent { |
1010 | assert_initialized_main_thread!(); |
1011 | Self::TouchFrame { |
1012 | modifier_state: NavigationModifierType::empty(), |
1013 | } |
1014 | } |
1015 | |
1016 | #[cfg (feature = "v1_22" )] |
1017 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1018 | #[doc (alias = "gst_navigation_event_new_touch_cancel" )] |
1019 | pub fn new_touch_cancel() -> NavigationEvent { |
1020 | assert_initialized_main_thread!(); |
1021 | Self::TouchCancel { |
1022 | modifier_state: NavigationModifierType::empty(), |
1023 | } |
1024 | } |
1025 | |
1026 | #[cfg (feature = "v1_26" )] |
1027 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_26" )))] |
1028 | #[doc (alias = "gst_navigation_event_new_mouse_double_click" )] |
1029 | pub fn new_mouse_double_click(button: i32, x: f64, y: f64) -> NavigationEvent { |
1030 | assert_initialized_main_thread!(); |
1031 | Self::MouseDoubleClick { |
1032 | button, |
1033 | x, |
1034 | y, |
1035 | modifier_state: NavigationModifierType::empty(), |
1036 | } |
1037 | } |
1038 | pub fn key_press_builder(key: &str) -> KeyEventBuilder { |
1039 | assert_initialized_main_thread!(); |
1040 | KeyEventBuilder::new(KeyEventType::Press { key }) |
1041 | } |
1042 | |
1043 | pub fn key_release_builder(key: &str) -> KeyEventBuilder { |
1044 | assert_initialized_main_thread!(); |
1045 | KeyEventBuilder::new(KeyEventType::Release { key }) |
1046 | } |
1047 | |
1048 | pub fn mouse_move_builder(x: f64, y: f64) -> MouseEventBuilder<'static> { |
1049 | assert_initialized_main_thread!(); |
1050 | MouseEventBuilder::new(MouseEventType::Move {}).x(x).y(y) |
1051 | } |
1052 | |
1053 | pub fn mouse_button_press_builder(button: i32, x: f64, y: f64) -> MouseEventBuilder<'static> { |
1054 | assert_initialized_main_thread!(); |
1055 | MouseEventBuilder::new(MouseEventType::Press { button }) |
1056 | .x(x) |
1057 | .y(y) |
1058 | } |
1059 | |
1060 | pub fn mouse_button_release_builder(button: i32, x: f64, y: f64) -> MouseEventBuilder<'static> { |
1061 | assert_initialized_main_thread!(); |
1062 | MouseEventBuilder::new(MouseEventType::Press { button }) |
1063 | .x(x) |
1064 | .y(y) |
1065 | } |
1066 | |
1067 | #[cfg (feature = "v1_18" )] |
1068 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_18" )))] |
1069 | pub fn mouse_scroll_builder( |
1070 | x: f64, |
1071 | y: f64, |
1072 | delta_x: f64, |
1073 | delta_y: f64, |
1074 | ) -> MouseEventBuilder<'static> { |
1075 | assert_initialized_main_thread!(); |
1076 | MouseEventBuilder::new(MouseEventType::Scroll { delta_x, delta_y }) |
1077 | .x(x) |
1078 | .y(y) |
1079 | } |
1080 | |
1081 | pub fn command_builder(command: NavigationCommand) -> CommandEventBuilder<'static> { |
1082 | assert_initialized_main_thread!(); |
1083 | CommandEventBuilder::new(command) |
1084 | } |
1085 | |
1086 | #[cfg (feature = "v1_22" )] |
1087 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1088 | pub fn touch_down_builder( |
1089 | identifier: u32, |
1090 | x: f64, |
1091 | y: f64, |
1092 | pressure: f64, |
1093 | ) -> TouchEventBuilder<'static> { |
1094 | assert_initialized_main_thread!(); |
1095 | TouchEventBuilder::new(TouchEventType::Down { pressure }) |
1096 | .identifier(identifier) |
1097 | .x(x) |
1098 | .y(y) |
1099 | } |
1100 | |
1101 | #[cfg (feature = "v1_22" )] |
1102 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1103 | pub fn touch_motion_builder( |
1104 | identifier: u32, |
1105 | x: f64, |
1106 | y: f64, |
1107 | pressure: f64, |
1108 | ) -> TouchEventBuilder<'static> { |
1109 | assert_initialized_main_thread!(); |
1110 | TouchEventBuilder::new(TouchEventType::Motion { pressure }) |
1111 | .identifier(identifier) |
1112 | .x(x) |
1113 | .y(y) |
1114 | } |
1115 | |
1116 | #[cfg (feature = "v1_22" )] |
1117 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1118 | pub fn touch_up_builder(identifier: u32, x: f64, y: f64) -> TouchEventBuilder<'static> { |
1119 | assert_initialized_main_thread!(); |
1120 | TouchEventBuilder::new(TouchEventType::Up) |
1121 | .identifier(identifier) |
1122 | .x(x) |
1123 | .y(y) |
1124 | } |
1125 | |
1126 | #[cfg (feature = "v1_22" )] |
1127 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1128 | pub fn touch_frame_builder() -> TouchMetaEventBuilder<'static> { |
1129 | assert_initialized_main_thread!(); |
1130 | TouchMetaEventBuilder::new(TouchMetaEventType::Frame) |
1131 | } |
1132 | |
1133 | #[cfg (feature = "v1_22" )] |
1134 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1135 | pub fn touch_cancel_builder() -> TouchMetaEventBuilder<'static> { |
1136 | assert_initialized_main_thread!(); |
1137 | TouchMetaEventBuilder::new(TouchMetaEventType::Cancel) |
1138 | } |
1139 | |
1140 | #[cfg (feature = "v1_26" )] |
1141 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_26" )))] |
1142 | pub fn mouse_double_click_builder(button: i32, x: f64, y: f64) -> MouseEventBuilder<'static> { |
1143 | assert_initialized_main_thread!(); |
1144 | MouseEventBuilder::new(MouseEventType::DoubleClick { button }) |
1145 | .x(x) |
1146 | .y(y) |
1147 | } |
1148 | |
1149 | #[doc (alias = "gst_navigation_event_get_type" )] |
1150 | pub fn type_(event: &gst::EventRef) -> NavigationEventType { |
1151 | skip_assert_initialized!(); |
1152 | unsafe { from_glib(ffi::gst_navigation_event_get_type(event.as_mut_ptr())) } |
1153 | } |
1154 | |
1155 | #[doc (alias = "gst_navigation_event_parse_key_event" )] |
1156 | #[doc (alias = "gst_navigation_event_parse_mouse_button_event" )] |
1157 | #[doc (alias = "gst_navigation_event_parse_mouse_scroll_event" )] |
1158 | #[doc (alias = "gst_navigation_event_parse_mouse_move_event" )] |
1159 | #[doc (alias = "gst_navigation_event_parse_touch_event" )] |
1160 | #[doc (alias = "gst_navigation_event_parse_touch_up_event" )] |
1161 | #[doc (alias = "gst_navigation_event_parse_command" )] |
1162 | pub fn parse(event: &gst::EventRef) -> Result<Self, glib::error::BoolError> { |
1163 | skip_assert_initialized!(); |
1164 | if event.type_() != EventType::Navigation { |
1165 | return Err(glib::bool_error!("Invalid navigation event" )); |
1166 | } |
1167 | |
1168 | let structure = event |
1169 | .structure() |
1170 | .ok_or_else(|| glib::bool_error!("Invalid navigation event" ))?; |
1171 | if structure.name() != NAVIGATION_EVENT_NAME { |
1172 | return Err(glib::bool_error!("Invalid navigation event" )); |
1173 | } |
1174 | |
1175 | #[cfg (feature = "v1_22" )] |
1176 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1177 | let modifier_state = structure |
1178 | .get("state" ) |
1179 | .unwrap_or(NavigationModifierType::empty()); |
1180 | let event = match Self::type_(event) { |
1181 | NavigationEventType::MouseMove => NavigationEvent::MouseMove { |
1182 | x: structure |
1183 | .get("pointer_x" ) |
1184 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1185 | y: structure |
1186 | .get("pointer_y" ) |
1187 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1188 | #[cfg (feature = "v1_22" )] |
1189 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1190 | modifier_state, |
1191 | }, |
1192 | NavigationEventType::MouseButtonPress => NavigationEvent::MouseButtonPress { |
1193 | button: structure |
1194 | .get("button" ) |
1195 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1196 | x: structure |
1197 | .get("pointer_x" ) |
1198 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1199 | y: structure |
1200 | .get("pointer_y" ) |
1201 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1202 | #[cfg (feature = "v1_22" )] |
1203 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1204 | modifier_state, |
1205 | }, |
1206 | NavigationEventType::MouseButtonRelease => NavigationEvent::MouseButtonRelease { |
1207 | button: structure |
1208 | .get("button" ) |
1209 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1210 | x: structure |
1211 | .get("pointer_x" ) |
1212 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1213 | y: structure |
1214 | .get("pointer_y" ) |
1215 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1216 | #[cfg (feature = "v1_22" )] |
1217 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1218 | modifier_state, |
1219 | }, |
1220 | #[cfg (feature = "v1_18" )] |
1221 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_18" )))] |
1222 | NavigationEventType::MouseScroll => NavigationEvent::MouseScroll { |
1223 | x: structure |
1224 | .get("pointer_x" ) |
1225 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1226 | y: structure |
1227 | .get("pointer_y" ) |
1228 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1229 | delta_x: structure |
1230 | .get("delta_pointer_x" ) |
1231 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1232 | delta_y: structure |
1233 | .get("delta_pointer_y" ) |
1234 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1235 | #[cfg (feature = "v1_22" )] |
1236 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1237 | modifier_state, |
1238 | }, |
1239 | NavigationEventType::KeyPress => NavigationEvent::KeyPress { |
1240 | key: structure |
1241 | .get("key" ) |
1242 | .map_err(|_| glib::bool_error!("Invalid key press event" ))?, |
1243 | #[cfg (feature = "v1_22" )] |
1244 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1245 | modifier_state, |
1246 | }, |
1247 | NavigationEventType::KeyRelease => NavigationEvent::KeyRelease { |
1248 | key: structure |
1249 | .get("key" ) |
1250 | .map_err(|_| glib::bool_error!("Invalid key press event" ))?, |
1251 | #[cfg (feature = "v1_22" )] |
1252 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1253 | modifier_state, |
1254 | }, |
1255 | NavigationEventType::Command => NavigationEvent::Command { |
1256 | command: structure |
1257 | .get("command-code" ) |
1258 | .map_err(|_| glib::bool_error!("Invalid key press event" ))?, |
1259 | #[cfg (feature = "v1_22" )] |
1260 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1261 | modifier_state, |
1262 | }, |
1263 | #[cfg (feature = "v1_22" )] |
1264 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1265 | NavigationEventType::TouchDown => NavigationEvent::TouchDown { |
1266 | identifier: structure |
1267 | .get("identifier" ) |
1268 | .map_err(|_| glib::bool_error!("Invalid touch event" ))?, |
1269 | x: structure |
1270 | .get("pointer_x" ) |
1271 | .map_err(|_| glib::bool_error!("Invalid touch event" ))?, |
1272 | y: structure |
1273 | .get("pointer_y" ) |
1274 | .map_err(|_| glib::bool_error!("Invalid touch event" ))?, |
1275 | pressure: structure |
1276 | .get("pressure" ) |
1277 | .map_err(|_| glib::bool_error!("Invalid touch event" ))?, |
1278 | modifier_state, |
1279 | }, |
1280 | #[cfg (feature = "v1_22" )] |
1281 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1282 | NavigationEventType::TouchMotion => NavigationEvent::TouchMotion { |
1283 | identifier: structure |
1284 | .get("identifier" ) |
1285 | .map_err(|_| glib::bool_error!("Invalid touch event" ))?, |
1286 | x: structure |
1287 | .get("pointer_x" ) |
1288 | .map_err(|_| glib::bool_error!("Invalid touch event" ))?, |
1289 | y: structure |
1290 | .get("pointer_y" ) |
1291 | .map_err(|_| glib::bool_error!("Invalid touch event" ))?, |
1292 | pressure: structure |
1293 | .get("pressure" ) |
1294 | .map_err(|_| glib::bool_error!("Invalid touch event" ))?, |
1295 | modifier_state, |
1296 | }, |
1297 | #[cfg (feature = "v1_22" )] |
1298 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1299 | NavigationEventType::TouchUp => NavigationEvent::TouchUp { |
1300 | identifier: structure |
1301 | .get("identifier" ) |
1302 | .map_err(|_| glib::bool_error!("Invalid touch event" ))?, |
1303 | x: structure |
1304 | .get("pointer_x" ) |
1305 | .map_err(|_| glib::bool_error!("Invalid touch event" ))?, |
1306 | y: structure |
1307 | .get("pointer_y" ) |
1308 | .map_err(|_| glib::bool_error!("Invalid touch event" ))?, |
1309 | modifier_state, |
1310 | }, |
1311 | #[cfg (feature = "v1_22" )] |
1312 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1313 | NavigationEventType::TouchFrame => NavigationEvent::TouchFrame { modifier_state }, |
1314 | #[cfg (feature = "v1_22" )] |
1315 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1316 | NavigationEventType::TouchCancel => NavigationEvent::TouchCancel { modifier_state }, |
1317 | #[cfg (feature = "v1_26" )] |
1318 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_26" )))] |
1319 | NavigationEventType::MouseDoubleClick => NavigationEvent::MouseDoubleClick { |
1320 | button: structure |
1321 | .get("button" ) |
1322 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1323 | x: structure |
1324 | .get("pointer_x" ) |
1325 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1326 | y: structure |
1327 | .get("pointer_y" ) |
1328 | .map_err(|_| glib::bool_error!("Invalid mouse event" ))?, |
1329 | modifier_state, |
1330 | }, |
1331 | |
1332 | NavigationEventType::Invalid | NavigationEventType::__Unknown(_) => { |
1333 | return Err(glib::bool_error!("Invalid navigation event" )) |
1334 | } |
1335 | }; |
1336 | Ok(event) |
1337 | } |
1338 | |
1339 | pub fn structure(&self) -> gst::Structure { |
1340 | skip_assert_initialized!(); |
1341 | #[allow (unused_mut)] |
1342 | let mut structure = match self { |
1343 | Self::MouseMove { x, y, .. } => gst::Structure::builder(NAVIGATION_EVENT_NAME) |
1344 | .field("event" , "mouse-move" ) |
1345 | .field("pointer_x" , x) |
1346 | .field("pointer_y" , y), |
1347 | Self::MouseButtonPress { button, x, y, .. } => { |
1348 | gst::Structure::builder(NAVIGATION_EVENT_NAME) |
1349 | .field("event" , "mouse-button-press" ) |
1350 | .field("button" , button) |
1351 | .field("pointer_x" , x) |
1352 | .field("pointer_y" , y) |
1353 | } |
1354 | Self::MouseButtonRelease { button, x, y, .. } => { |
1355 | gst::Structure::builder(NAVIGATION_EVENT_NAME) |
1356 | .field("event" , "mouse-button-release" ) |
1357 | .field("button" , button) |
1358 | .field("pointer_x" , x) |
1359 | .field("pointer_y" , y) |
1360 | } |
1361 | #[cfg (feature = "v1_18" )] |
1362 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_18" )))] |
1363 | Self::MouseScroll { |
1364 | x, |
1365 | y, |
1366 | delta_x, |
1367 | delta_y, |
1368 | .. |
1369 | } => gst::Structure::builder(NAVIGATION_EVENT_NAME) |
1370 | .field("event" , "mouse-scroll" ) |
1371 | .field("pointer_x" , x) |
1372 | .field("pointer_y" , y) |
1373 | .field("delta_pointer_x" , delta_x) |
1374 | .field("delta_pointer_y" , delta_y), |
1375 | Self::KeyPress { key, .. } => gst::Structure::builder(NAVIGATION_EVENT_NAME) |
1376 | .field("event" , "key-press" ) |
1377 | .field("key" , key), |
1378 | Self::KeyRelease { key, .. } => gst::Structure::builder(NAVIGATION_EVENT_NAME) |
1379 | .field("event" , "key-release" ) |
1380 | .field("key" , key), |
1381 | Self::Command { command, .. } => gst::Structure::builder(NAVIGATION_EVENT_NAME) |
1382 | .field("event" , "command" ) |
1383 | .field("command-code" , command), |
1384 | #[cfg (feature = "v1_22" )] |
1385 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1386 | Self::TouchDown { |
1387 | identifier, |
1388 | x, |
1389 | y, |
1390 | pressure, |
1391 | .. |
1392 | } => gst::Structure::builder(NAVIGATION_EVENT_NAME) |
1393 | .field("event" , "touch-down" ) |
1394 | .field("identifier" , identifier) |
1395 | .field("pointer_x" , x) |
1396 | .field("pointer_y" , y) |
1397 | .field("pressure" , pressure), |
1398 | #[cfg (feature = "v1_22" )] |
1399 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1400 | Self::TouchMotion { |
1401 | identifier, |
1402 | x, |
1403 | y, |
1404 | pressure, |
1405 | .. |
1406 | } => gst::Structure::builder(NAVIGATION_EVENT_NAME) |
1407 | .field("event" , "touch-motion" ) |
1408 | .field("identifier" , identifier) |
1409 | .field("pointer_x" , x) |
1410 | .field("pointer_y" , y) |
1411 | .field("pressure" , pressure), |
1412 | #[cfg (feature = "v1_22" )] |
1413 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1414 | Self::TouchUp { |
1415 | identifier, x, y, .. |
1416 | } => gst::Structure::builder(NAVIGATION_EVENT_NAME) |
1417 | .field("event" , "touch-up" ) |
1418 | .field("identifier" , identifier) |
1419 | .field("pointer_x" , x) |
1420 | .field("pointer_y" , y), |
1421 | #[cfg (feature = "v1_22" )] |
1422 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1423 | Self::TouchFrame { .. } => { |
1424 | gst::Structure::builder(NAVIGATION_EVENT_NAME).field("event" , "touch-frame" ) |
1425 | } |
1426 | #[cfg (feature = "v1_22" )] |
1427 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1428 | Self::TouchCancel { .. } => { |
1429 | gst::Structure::builder(NAVIGATION_EVENT_NAME).field("event" , "touch-cancel" ) |
1430 | } |
1431 | #[cfg (feature = "v1_26" )] |
1432 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_26" )))] |
1433 | Self::MouseDoubleClick { button, x, y, .. } => { |
1434 | gst::Structure::builder(NAVIGATION_EVENT_NAME) |
1435 | .field("event" , "mouse-double-click" ) |
1436 | .field("button" , button) |
1437 | .field("pointer_x" , x) |
1438 | .field("pointer_y" , y) |
1439 | } |
1440 | }; |
1441 | |
1442 | #[cfg (feature = "v1_22" )] |
1443 | { |
1444 | structure = match self { |
1445 | Self::MouseMove { modifier_state, .. } => structure.field("state" , modifier_state), |
1446 | Self::MouseButtonPress { modifier_state, .. } => { |
1447 | structure.field("state" , modifier_state) |
1448 | } |
1449 | Self::MouseButtonRelease { modifier_state, .. } => { |
1450 | structure.field("state" , modifier_state) |
1451 | } |
1452 | Self::MouseScroll { modifier_state, .. } => { |
1453 | structure.field("state" , modifier_state) |
1454 | } |
1455 | Self::KeyPress { modifier_state, .. } => structure.field("state" , modifier_state), |
1456 | Self::KeyRelease { modifier_state, .. } => structure.field("state" , modifier_state), |
1457 | Self::Command { modifier_state, .. } => structure.field("state" , modifier_state), |
1458 | Self::TouchDown { modifier_state, .. } => structure.field("state" , modifier_state), |
1459 | Self::TouchMotion { modifier_state, .. } => { |
1460 | structure.field("state" , modifier_state) |
1461 | } |
1462 | Self::TouchUp { modifier_state, .. } => structure.field("state" , modifier_state), |
1463 | Self::TouchFrame { modifier_state, .. } => structure.field("state" , modifier_state), |
1464 | Self::TouchCancel { modifier_state, .. } => { |
1465 | structure.field("state" , modifier_state) |
1466 | } |
1467 | #[cfg (feature = "v1_26" )] |
1468 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_26" )))] |
1469 | Self::MouseDoubleClick { modifier_state, .. } => { |
1470 | structure.field("state" , modifier_state) |
1471 | } |
1472 | }; |
1473 | } |
1474 | |
1475 | structure.build() |
1476 | } |
1477 | |
1478 | pub fn build(&self) -> gst::Event { |
1479 | skip_assert_initialized!(); |
1480 | |
1481 | gst::event::Navigation::new(self.structure()) |
1482 | } |
1483 | } |
1484 | |
1485 | #[cfg (test)] |
1486 | mod tests { |
1487 | #[test ] |
1488 | #[cfg (feature = "serde" )] |
1489 | #[cfg (feature = "v1_22" )] |
1490 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
1491 | fn serialize_navigation_events() { |
1492 | use crate::{NavigationEvent, NavigationModifierType}; |
1493 | |
1494 | gst::init().unwrap(); |
1495 | |
1496 | let mods = NavigationModifierType::SHIFT_MASK | NavigationModifierType::CONTROL_MASK; |
1497 | let ev = NavigationEvent::mouse_scroll_builder(1.0, 2.0, 3.0, 4.0) |
1498 | .modifier_state(mods) |
1499 | .build(); |
1500 | let navigation_event = NavigationEvent::parse(&ev).unwrap(); |
1501 | match &navigation_event { |
1502 | NavigationEvent::MouseScroll { |
1503 | x, |
1504 | y, |
1505 | delta_x, |
1506 | delta_y, |
1507 | modifier_state, |
1508 | } => { |
1509 | assert!( |
1510 | *x == 1.0 |
1511 | && *y == 2.0 |
1512 | && *delta_x == 3.0 |
1513 | && *delta_y == 4.0 |
1514 | && *modifier_state == mods |
1515 | ); |
1516 | } |
1517 | _ => unreachable!(), |
1518 | } |
1519 | |
1520 | let json_event = serde_json::to_string(&navigation_event).unwrap(); |
1521 | assert_eq!( |
1522 | json_event, |
1523 | r#"{"event":"MouseScroll","x":1.0,"y":2.0,"delta_x":3.0,"delta_y":4.0,"modifier_state":"shift-mask+control-mask"}"# |
1524 | ); |
1525 | let navigation_event: NavigationEvent = serde_json::from_str(&json_event).unwrap(); |
1526 | match &navigation_event { |
1527 | NavigationEvent::MouseScroll { |
1528 | x, |
1529 | y, |
1530 | delta_x, |
1531 | delta_y, |
1532 | modifier_state, |
1533 | } => { |
1534 | assert!( |
1535 | *x == 1.0 |
1536 | && *y == 2.0 |
1537 | && *delta_x == 3.0 |
1538 | && *delta_y == 4.0 |
1539 | && *modifier_state == mods |
1540 | ); |
1541 | } |
1542 | _ => unreachable!(), |
1543 | } |
1544 | |
1545 | let ev = NavigationEvent::new_mouse_button_press(1, 1.0, 2.0).build(); |
1546 | let navigation_event = NavigationEvent::parse(&ev).unwrap(); |
1547 | match &navigation_event { |
1548 | NavigationEvent::MouseButtonPress { |
1549 | button, |
1550 | x, |
1551 | y, |
1552 | modifier_state, |
1553 | } => { |
1554 | assert!( |
1555 | *button == 1 |
1556 | && *x == 1.0 |
1557 | && *y == 2.0 |
1558 | && *modifier_state == NavigationModifierType::empty() |
1559 | ); |
1560 | } |
1561 | _ => unreachable!(), |
1562 | } |
1563 | let json_event = serde_json::to_string(&navigation_event).unwrap(); |
1564 | assert_eq!( |
1565 | json_event, |
1566 | r#"{"event":"MouseButtonPress","button":1,"x":1.0,"y":2.0,"modifier_state":""}"# |
1567 | ); |
1568 | let navigation_event: NavigationEvent = serde_json::from_str(&json_event).unwrap(); |
1569 | match &navigation_event { |
1570 | NavigationEvent::MouseButtonPress { |
1571 | button, |
1572 | x, |
1573 | y, |
1574 | modifier_state, |
1575 | } => { |
1576 | assert!( |
1577 | *button == 1 |
1578 | && *x == 1.0 |
1579 | && *y == 2.0 |
1580 | && *modifier_state == NavigationModifierType::empty() |
1581 | ); |
1582 | } |
1583 | _ => unreachable!(), |
1584 | } |
1585 | |
1586 | let mods = NavigationModifierType::META_MASK; |
1587 | let ev = NavigationEvent::key_release_builder("a" ) |
1588 | .modifier_state(mods) |
1589 | .build(); |
1590 | let navigation_event = NavigationEvent::parse(&ev).unwrap(); |
1591 | match &navigation_event { |
1592 | NavigationEvent::KeyRelease { |
1593 | key, |
1594 | modifier_state, |
1595 | } => { |
1596 | assert!(*key == "a" && *modifier_state == mods); |
1597 | } |
1598 | _ => unreachable!(), |
1599 | } |
1600 | |
1601 | let json_event = serde_json::to_string(&navigation_event).unwrap(); |
1602 | assert_eq!( |
1603 | json_event, |
1604 | r#"{"event":"KeyRelease","key":"a","modifier_state":"meta-mask"}"# |
1605 | ); |
1606 | let navigation_event: NavigationEvent = serde_json::from_str(&json_event).unwrap(); |
1607 | match &navigation_event { |
1608 | NavigationEvent::KeyRelease { |
1609 | key, |
1610 | modifier_state, |
1611 | } => { |
1612 | assert!(*key == "a" && *modifier_state == mods); |
1613 | } |
1614 | _ => unreachable!(), |
1615 | } |
1616 | |
1617 | let ev = NavigationEvent::new_touch_motion(0, 1.0, 2.0, 0.5).build(); |
1618 | let navigation_event = NavigationEvent::parse(&ev).unwrap(); |
1619 | match &navigation_event { |
1620 | NavigationEvent::TouchMotion { |
1621 | identifier, |
1622 | x, |
1623 | y, |
1624 | pressure, |
1625 | modifier_state, |
1626 | } => { |
1627 | assert!( |
1628 | *identifier == 0 |
1629 | && *x == 1.0 |
1630 | && *y == 2.0 |
1631 | && *pressure == 0.5 |
1632 | && *modifier_state == NavigationModifierType::empty() |
1633 | ); |
1634 | } |
1635 | _ => unreachable!(), |
1636 | } |
1637 | |
1638 | let json_event = serde_json::to_string(&navigation_event).unwrap(); |
1639 | assert_eq!( |
1640 | json_event, |
1641 | r#"{"event":"TouchMotion","identifier":0,"x":1.0,"y":2.0,"pressure":0.5,"modifier_state":""}"# |
1642 | ); |
1643 | let navigation_event: NavigationEvent = serde_json::from_str(&json_event).unwrap(); |
1644 | match &navigation_event { |
1645 | NavigationEvent::TouchMotion { |
1646 | identifier, |
1647 | x, |
1648 | y, |
1649 | pressure, |
1650 | modifier_state, |
1651 | } => { |
1652 | assert!( |
1653 | *identifier == 0 |
1654 | && *x == 1.0 |
1655 | && *y == 2.0 |
1656 | && *pressure == 0.5 |
1657 | && *modifier_state == NavigationModifierType::empty() |
1658 | ); |
1659 | } |
1660 | _ => unreachable!(), |
1661 | } |
1662 | |
1663 | let ev = NavigationEvent::touch_cancel_builder().build(); |
1664 | let navigation_event = NavigationEvent::parse(&ev).unwrap(); |
1665 | match &navigation_event { |
1666 | NavigationEvent::TouchCancel { modifier_state } => { |
1667 | assert!(*modifier_state == NavigationModifierType::empty()); |
1668 | } |
1669 | _ => unreachable!(), |
1670 | } |
1671 | |
1672 | let json_event = serde_json::to_string(&navigation_event).unwrap(); |
1673 | assert_eq!(json_event, r#"{"event":"TouchCancel","modifier_state":""}"# ); |
1674 | let navigation_event: NavigationEvent = serde_json::from_str(&json_event).unwrap(); |
1675 | match &navigation_event { |
1676 | NavigationEvent::TouchCancel { modifier_state } => { |
1677 | assert!(*modifier_state == NavigationModifierType::empty()); |
1678 | } |
1679 | _ => unreachable!(), |
1680 | } |
1681 | } |
1682 | } |
1683 | |