Coverage Report

Created: 2026-02-24 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gstreamer/subprojects/gst-plugins-base/gst-libs/gst/video/navigation.c
Line
Count
Source
1
/* GStreamer Navigation
2
 * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3
 * Copyright (C) 2007-2009 Jan Schmidt <thaytan@noraisin.net>
4
 *
5
 * navigation.c: navigation event virtual class function wrappers
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Library General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Library General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Library General Public
18
 * License along with this library; if not, write to the
19
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20
 * Boston, MA 02110-1301, USA.
21
 */
22
23
/**
24
 * SECTION:gstnavigation
25
 * @title: GstNavigation
26
 * @short_description: Interface for creating, sending and parsing navigation
27
 * events.
28
 *
29
 * The Navigation interface is used for creating and injecting navigation
30
 * related events such as mouse button presses, cursor motion and key presses.
31
 * The associated library also provides methods for parsing received events, and
32
 * for sending and receiving navigation related bus events. One main usecase is
33
 * DVD menu navigation.
34
 *
35
 * The main parts of the API are:
36
 *
37
 * * The GstNavigation interface, implemented by elements which provide an
38
 *   application with the ability to create and inject navigation events into
39
 *   the pipeline.
40
 * * GstNavigation event handling API. GstNavigation events are created in
41
 *   response to calls on a GstNavigation interface implementation, and sent in
42
 *   the pipeline. Upstream elements can use the navigation event API functions
43
 *   to parse the contents of received messages.
44
 *
45
 * * GstNavigation message handling API. GstNavigation messages may be sent on
46
 *   the message bus to inform applications of navigation related changes in the
47
 *   pipeline, such as the mouse moving over a clickable region, or the set of
48
 *   available angles changing.
49
 *
50
 * The GstNavigation message functions provide functions for creating and
51
 * parsing custom bus messages for signaling GstNavigation changes.
52
 */
53
54
#ifdef HAVE_CONFIG_H
55
#include "config.h"
56
#endif
57
58
#include <gst/video/navigation.h>
59
#include <gst/video/video-enumtypes.h>
60
61
0
#define GST_NAVIGATION_MESSAGE_NAME "GstNavigationMessage"
62
0
#define GST_NAVIGATION_QUERY_NAME "GstNavigationQuery"
63
0
#define GST_NAVIGATION_EVENT_NAME "application/x-gst-navigation"
64
65
0
#define WARN_IF_FAIL(exp,msg) if(G_UNLIKELY(!(exp))){g_warning("%s",(msg));}
66
67
8
G_DEFINE_INTERFACE (GstNavigation, gst_navigation, 0);
68
8
69
8
static void
70
8
gst_navigation_default_send_event_simple (GstNavigation * navigation,
71
8
    GstEvent * event)
72
8
{
73
0
  GstNavigationInterface *iface = GST_NAVIGATION_GET_INTERFACE (navigation);
74
75
0
  if (iface->send_event) {
76
0
    iface->send_event (navigation,
77
0
        gst_structure_copy (gst_event_get_structure (event)));
78
0
  } else {
79
0
    gst_event_unref (event);
80
0
  }
81
0
}
82
83
static void
84
gst_navigation_default_init (GstNavigationInterface * iface)
85
2
{
86
  /* default virtual functions */
87
2
  iface->send_event = NULL;
88
2
  iface->send_event_simple = gst_navigation_default_send_event_simple;
89
2
}
90
91
/* The interface implementer should make sure that the object can handle
92
 * the event. */
93
void
94
gst_navigation_send_event (GstNavigation * navigation, GstStructure * structure)
95
0
{
96
0
  GstNavigationInterface *iface;
97
98
0
  g_return_if_fail (GST_IS_NAVIGATION (navigation));
99
100
0
  iface = GST_NAVIGATION_GET_INTERFACE (navigation);
101
0
  if (iface->send_event) {
102
0
    iface->send_event (navigation, structure);
103
0
  } else if (iface->send_event_simple) {
104
0
    iface->send_event_simple (navigation, gst_event_new_navigation (structure));
105
0
  } else {
106
0
    gst_structure_free (structure);
107
0
  }
108
0
}
109
110
/**
111
 * gst_navigation_send_key_event:
112
 * @navigation: The navigation interface instance
113
 * @event: The type of the key event. Recognised values are "key-press" and
114
 * "key-release"
115
 * @key: Character representation of the key. This is typically as produced
116
 * by XKeysymToString.
117
 */
118
void
119
gst_navigation_send_key_event (GstNavigation * navigation, const char *event,
120
    const char *key)
121
0
{
122
0
  g_return_if_fail (GST_IS_NAVIGATION (navigation));
123
0
  g_return_if_fail (g_strcmp0 (event, "key-press") == 0 ||
124
0
      g_strcmp0 (event, "key-release") == 0);
125
126
0
  gst_navigation_send_event (navigation,
127
0
      gst_structure_new (GST_NAVIGATION_EVENT_NAME, "event", G_TYPE_STRING,
128
0
          event, "key", G_TYPE_STRING, key, NULL));
129
0
}
130
131
/**
132
 * gst_navigation_send_mouse_event:
133
 * @navigation: The navigation interface instance
134
 * @event: The type of mouse event, as a text string. Recognised values are
135
 * "mouse-button-press", "mouse-button-release", "mouse-move" and "mouse-double-click".
136
 * @button: The button number of the button being pressed or released. Pass 0
137
 * for mouse-move events.
138
 * @x: The x coordinate of the mouse event.
139
 * @y: The y coordinate of the mouse event.
140
 *
141
 * Sends a mouse event to the navigation interface. Mouse event coordinates
142
 * are sent relative to the display space of the related output area. This is
143
 * usually the size in pixels of the window associated with the element
144
 * implementing the #GstNavigation interface.
145
 *
146
 */
147
void
148
gst_navigation_send_mouse_event (GstNavigation * navigation, const char *event,
149
    int button, double x, double y)
150
0
{
151
0
  g_return_if_fail (GST_IS_NAVIGATION (navigation));
152
0
  g_return_if_fail (g_strcmp0 (event, "mouse-button-press") == 0 ||
153
0
      g_strcmp0 (event, "mouse-button-release") == 0 ||
154
0
      g_strcmp0 (event, "mouse-move") == 0 ||
155
0
      g_strcmp0 (event, "mouse-double-click") == 0);
156
157
0
  gst_navigation_send_event (navigation,
158
0
      gst_structure_new (GST_NAVIGATION_EVENT_NAME, "event", G_TYPE_STRING,
159
0
          event, "button", G_TYPE_INT, button, "pointer_x", G_TYPE_DOUBLE, x,
160
0
          "pointer_y", G_TYPE_DOUBLE, y, NULL));
161
0
}
162
163
/**
164
 * gst_navigation_send_mouse_scroll_event:
165
 * @navigation: The navigation interface instance
166
 * @x: The x coordinate of the mouse event.
167
 * @y: The y coordinate of the mouse event.
168
 * @delta_x: The delta_x coordinate of the mouse event.
169
 * @delta_y: The delta_y coordinate of the mouse event.
170
 *
171
 * Sends a mouse scroll event to the navigation interface. Mouse event coordinates
172
 * are sent relative to the display space of the related output area. This is
173
 * usually the size in pixels of the window associated with the element
174
 * implementing the #GstNavigation interface.
175
 *
176
 * Since: 1.18
177
 */
178
void
179
gst_navigation_send_mouse_scroll_event (GstNavigation * navigation,
180
    double x, double y, double delta_x, double delta_y)
181
0
{
182
0
  g_return_if_fail (GST_IS_NAVIGATION (navigation));
183
184
0
  gst_navigation_send_event (navigation,
185
0
      gst_structure_new (GST_NAVIGATION_EVENT_NAME,
186
0
          "event", G_TYPE_STRING, "mouse-scroll",
187
0
          "pointer_x", G_TYPE_DOUBLE, x,
188
0
          "pointer_y", G_TYPE_DOUBLE, y,
189
0
          "delta_pointer_x", G_TYPE_DOUBLE, delta_x,
190
0
          "delta_pointer_y", G_TYPE_DOUBLE, delta_y, NULL));
191
0
}
192
193
/**
194
 * gst_navigation_send_command:
195
 * @navigation: The navigation interface instance
196
 * @command: The command to issue
197
 *
198
 * Sends the indicated command to the navigation interface.
199
 */
200
void
201
gst_navigation_send_command (GstNavigation * navigation,
202
    GstNavigationCommand command)
203
0
{
204
0
  g_return_if_fail (GST_IS_NAVIGATION (navigation));
205
206
0
  gst_navigation_send_event (navigation,
207
0
      gst_structure_new (GST_NAVIGATION_EVENT_NAME, "event", G_TYPE_STRING,
208
0
          "command", "command-code", G_TYPE_UINT, (guint) command, NULL));
209
0
}
210
211
/**
212
 * gst_navigation_send_event_simple:
213
 * @navigation: The navigation interface instance
214
 * @event: (transfer full): The event to send
215
 *
216
 * Sends an event to the navigation interface.
217
 * Since: 1.22
218
 */
219
void
220
gst_navigation_send_event_simple (GstNavigation * navigation, GstEvent * event)
221
0
{
222
0
  GstNavigationInterface *iface;
223
224
0
  g_return_if_fail (GST_IS_NAVIGATION (navigation));
225
0
  g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION);
226
227
0
  iface = GST_NAVIGATION_GET_INTERFACE (navigation);
228
0
  if (iface->send_event_simple) {
229
0
    iface->send_event_simple (navigation, event);
230
0
  } else if (iface->send_event) {
231
0
    iface->send_event (navigation,
232
0
        gst_structure_copy (gst_event_get_structure (event)));
233
0
    gst_event_unref (event);
234
0
  } else {
235
0
    gst_event_unref (event);
236
0
  }
237
0
}
238
239
/* Navigation Queries */
240
241
#define GST_NAVIGATION_QUERY_HAS_TYPE(query,query_type) \
242
(gst_navigation_query_get_type (query) == GST_NAVIGATION_QUERY_ ## query_type)
243
244
/**
245
 * gst_navigation_query_get_type:
246
 * @query: The query to inspect
247
 *
248
 * Inspect a #GstQuery and return the #GstNavigationQueryType associated with
249
 * it if it is a #GstNavigation query.
250
 *
251
 * Returns: The #GstNavigationQueryType of the query, or
252
 * #GST_NAVIGATION_QUERY_INVALID
253
 */
254
GstNavigationQueryType
255
gst_navigation_query_get_type (GstQuery * query)
256
0
{
257
0
  const GstStructure *s;
258
0
  const gchar *q_type;
259
260
0
  if (query == NULL || GST_QUERY_TYPE (query) != GST_QUERY_CUSTOM)
261
0
    return GST_NAVIGATION_QUERY_INVALID;
262
263
0
  s = gst_query_get_structure (query);
264
0
  if (s == NULL || !gst_structure_has_name (s, GST_NAVIGATION_QUERY_NAME))
265
0
    return GST_NAVIGATION_QUERY_INVALID;
266
267
0
  q_type = gst_structure_get_string (s, "type");
268
0
  if (q_type == NULL)
269
0
    return GST_NAVIGATION_QUERY_INVALID;
270
271
0
  if (g_str_equal (q_type, "commands"))
272
0
    return GST_NAVIGATION_QUERY_COMMANDS;
273
0
  else if (g_str_equal (q_type, "angles"))
274
0
    return GST_NAVIGATION_QUERY_ANGLES;
275
276
0
  return GST_NAVIGATION_QUERY_INVALID;
277
0
}
278
279
/**
280
 * gst_navigation_query_new_commands:
281
 *
282
 * Create a new #GstNavigation commands query. When executed, it will
283
 * query the pipeline for the set of currently available commands.
284
 *
285
 * Returns: The new query.
286
 */
287
GstQuery *
288
gst_navigation_query_new_commands (void)
289
0
{
290
0
  GstQuery *query;
291
0
  GstStructure *structure;
292
293
0
  structure = gst_structure_new (GST_NAVIGATION_QUERY_NAME,
294
0
      "type", G_TYPE_STRING, "commands", NULL);
295
0
  query = gst_query_new_custom (GST_QUERY_CUSTOM, structure);
296
297
0
  return query;
298
0
}
299
300
static void
301
gst_query_list_add_command (GValue * list, GstNavigationCommand val)
302
0
{
303
0
  GValue item = { 0, };
304
305
0
  g_value_init (&item, GST_TYPE_NAVIGATION_COMMAND);
306
0
  g_value_set_enum (&item, val);
307
0
  gst_value_list_append_value (list, &item);
308
0
  g_value_unset (&item);
309
0
}
310
311
/**
312
 * gst_navigation_query_set_commands:
313
 * @query: a #GstQuery
314
 * @n_cmds: the number of commands to set.
315
 * @...: A list of @GstNavigationCommand values, @n_cmds entries long.
316
 *
317
 * Set the #GstNavigation command query result fields in @query. The number
318
 * of commands passed must be equal to @n_commands.
319
 */
320
void
321
gst_navigation_query_set_commands (GstQuery * query, gint n_cmds, ...)
322
0
{
323
0
  va_list ap;
324
0
  GValue list = { 0, };
325
0
  GstStructure *structure;
326
0
  gint i;
327
328
0
  g_return_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS));
329
330
0
  g_value_init (&list, GST_TYPE_LIST);
331
332
0
  va_start (ap, n_cmds);
333
0
  for (i = 0; i < n_cmds; i++) {
334
0
    GstNavigationCommand val = va_arg (ap, GstNavigationCommand);
335
0
    gst_query_list_add_command (&list, val);
336
0
  }
337
0
  va_end (ap);
338
339
0
  structure = gst_query_writable_structure (query);
340
0
  gst_structure_take_value (structure, "commands", &list);
341
0
}
342
343
/**
344
 * gst_navigation_query_set_commandsv:
345
 * @query: a #GstQuery
346
 * @n_cmds: the number of commands to set.
347
 * @cmds: (array length=n_cmds): An array containing @n_cmds
348
 *     @GstNavigationCommand values.
349
 *
350
 * Set the #GstNavigation command query result fields in @query. The number
351
 * of commands passed must be equal to @n_commands.
352
 */
353
void
354
gst_navigation_query_set_commandsv (GstQuery * query, gint n_cmds,
355
    GstNavigationCommand * cmds)
356
0
{
357
0
  GValue list = { 0, };
358
0
  GstStructure *structure;
359
0
  gint i;
360
361
0
  g_return_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS));
362
363
0
  g_value_init (&list, GST_TYPE_LIST);
364
0
  for (i = 0; i < n_cmds; i++) {
365
0
    gst_query_list_add_command (&list, cmds[i]);
366
0
  }
367
0
  structure = gst_query_writable_structure (query);
368
0
  gst_structure_take_value (structure, "commands", &list);
369
0
}
370
371
/**
372
 * gst_navigation_query_parse_commands_length:
373
 * @query: a #GstQuery
374
 * @n_cmds: (out) (optional): the number of commands in this query.
375
 *
376
 * Parse the number of commands in the #GstNavigation commands @query.
377
 *
378
 * Returns: %TRUE if the query could be successfully parsed. %FALSE if not.
379
 */
380
gboolean
381
gst_navigation_query_parse_commands_length (GstQuery * query, guint * n_cmds)
382
0
{
383
0
  const GstStructure *structure;
384
0
  const GValue *list;
385
386
0
  g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS), FALSE);
387
388
0
  if (n_cmds == NULL)
389
0
    return TRUE;
390
391
0
  structure = gst_query_get_structure (query);
392
0
  list = gst_structure_get_value (structure, "commands");
393
0
  if (list == NULL)
394
0
    *n_cmds = 0;
395
0
  else
396
0
    *n_cmds = gst_value_list_get_size (list);
397
398
0
  return TRUE;
399
0
}
400
401
/**
402
 * gst_navigation_query_parse_commands_nth:
403
 * @query: a #GstQuery
404
 * @nth: the nth command to retrieve.
405
 * @cmd: (out) (optional): a pointer to store the nth command into.
406
 *
407
 * Parse the #GstNavigation command query and retrieve the @nth command from
408
 * it into @cmd. If the list contains less elements than @nth, @cmd will be
409
 * set to #GST_NAVIGATION_COMMAND_INVALID.
410
 *
411
 * Returns: %TRUE if the query could be successfully parsed. %FALSE if not.
412
 */
413
gboolean
414
gst_navigation_query_parse_commands_nth (GstQuery * query, guint nth,
415
    GstNavigationCommand * cmd)
416
0
{
417
0
  const GstStructure *structure;
418
0
  const GValue *list;
419
420
0
  g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS), FALSE);
421
422
0
  if (cmd == NULL)
423
0
    return TRUE;
424
425
0
  structure = gst_query_get_structure (query);
426
0
  list = gst_structure_get_value (structure, "commands");
427
0
  if (list == NULL) {
428
0
    *cmd = GST_NAVIGATION_COMMAND_INVALID;
429
0
  } else {
430
0
    if (nth < gst_value_list_get_size (list)) {
431
0
      *cmd = (GstNavigationCommand)
432
0
          g_value_get_enum (gst_value_list_get_value (list, nth));
433
0
    } else
434
0
      *cmd = GST_NAVIGATION_COMMAND_INVALID;
435
0
  }
436
437
0
  return TRUE;
438
0
}
439
440
/**
441
 * gst_navigation_query_new_angles:
442
 *
443
 * Create a new #GstNavigation angles query. When executed, it will
444
 * query the pipeline for the set of currently available angles, which may be
445
 * greater than one in a multiangle video.
446
 *
447
 * Returns: The new query.
448
 */
449
GstQuery *
450
gst_navigation_query_new_angles (void)
451
0
{
452
0
  GstQuery *query;
453
0
  GstStructure *structure;
454
455
0
  structure = gst_structure_new (GST_NAVIGATION_QUERY_NAME,
456
0
      "type", G_TYPE_STRING, "angles", NULL);
457
0
  query = gst_query_new_custom (GST_QUERY_CUSTOM, structure);
458
459
0
  return query;
460
0
}
461
462
/**
463
 * gst_navigation_query_set_angles:
464
 * @query: a #GstQuery
465
 * @cur_angle: the current viewing angle to set.
466
 * @n_angles: the number of viewing angles to set.
467
 *
468
 * Set the #GstNavigation angles query result field in @query.
469
 */
470
void
471
gst_navigation_query_set_angles (GstQuery * query, guint cur_angle,
472
    guint n_angles)
473
0
{
474
0
  GstStructure *structure;
475
476
0
  g_return_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, ANGLES));
477
478
0
  structure = gst_query_writable_structure (query);
479
0
  gst_structure_set (structure,
480
0
      "angle", G_TYPE_UINT, cur_angle, "angles", G_TYPE_UINT, n_angles, NULL);
481
0
}
482
483
/**
484
 * gst_navigation_query_parse_angles:
485
 * @query: a #GstQuery
486
 * @cur_angle: (out) (optional): Pointer to a #guint into which to store the
487
 *     currently selected angle value from the query, or NULL
488
 * @n_angles: (out) (optional): Pointer to a #guint into which to store the
489
 *     number of angles value from the query, or NULL
490
 *
491
 * Parse the current angle number in the #GstNavigation angles @query into the
492
 * #guint pointed to by the @cur_angle variable, and the number of available
493
 * angles into the #guint pointed to by the @n_angles variable.
494
 *
495
 * Returns: %TRUE if the query could be successfully parsed. %FALSE if not.
496
 */
497
gboolean
498
gst_navigation_query_parse_angles (GstQuery * query, guint * cur_angle,
499
    guint * n_angles)
500
0
{
501
0
  const GstStructure *structure;
502
0
  gboolean ret = TRUE;
503
504
0
  g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, ANGLES), FALSE);
505
506
0
  structure = gst_query_get_structure (query);
507
508
0
  if (cur_angle)
509
0
    ret &= gst_structure_get_uint (structure, "angle", cur_angle);
510
511
0
  if (n_angles)
512
0
    ret &= gst_structure_get_uint (structure, "angles", n_angles);
513
514
0
  WARN_IF_FAIL (ret, "Couldn't extract details from angles query");
515
516
0
  return ret;
517
0
}
518
519
/* Navigation Messages */
520
521
0
#define GST_NAVIGATION_MESSAGE_HAS_TYPE(msg,msg_type) \
522
0
(gst_navigation_message_get_type (msg) == GST_NAVIGATION_MESSAGE_ ## msg_type)
523
524
/**
525
 * gst_navigation_message_get_type:
526
 * @message: A #GstMessage to inspect.
527
 *
528
 * Check a bus message to see if it is a #GstNavigation event, and return
529
 * the #GstNavigationMessageType identifying the type of the message if so.
530
 *
531
 * Returns: The type of the #GstMessage, or
532
 * #GST_NAVIGATION_MESSAGE_INVALID if the message is not a #GstNavigation
533
 * notification.
534
 */
535
GstNavigationMessageType
536
gst_navigation_message_get_type (GstMessage * message)
537
0
{
538
0
  const GstStructure *s;
539
0
  const gchar *m_type;
540
541
0
  if (message == NULL || GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
542
0
    return GST_NAVIGATION_MESSAGE_INVALID;
543
544
0
  s = gst_message_get_structure (message);
545
0
  if (s == NULL || !gst_structure_has_name (s, GST_NAVIGATION_MESSAGE_NAME))
546
0
    return GST_NAVIGATION_MESSAGE_INVALID;
547
548
0
  m_type = gst_structure_get_string (s, "type");
549
0
  if (m_type == NULL)
550
0
    return GST_NAVIGATION_MESSAGE_INVALID;
551
552
0
  if (g_str_equal (m_type, "mouse-over"))
553
0
    return GST_NAVIGATION_MESSAGE_MOUSE_OVER;
554
0
  else if (g_str_equal (m_type, "commands-changed"))
555
0
    return GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED;
556
0
  else if (g_str_equal (m_type, "angles-changed"))
557
0
    return GST_NAVIGATION_MESSAGE_ANGLES_CHANGED;
558
0
  else if (g_str_equal (m_type, "event"))
559
0
    return GST_NAVIGATION_MESSAGE_EVENT;
560
561
0
  return GST_NAVIGATION_MESSAGE_INVALID;
562
0
}
563
564
/**
565
 * gst_navigation_message_new_mouse_over:
566
 * @src: A #GstObject to set as source of the new message.
567
 * @active: %TRUE if the mouse has entered a clickable area of the display.
568
 * %FALSE if it over a non-clickable area.
569
 *
570
 * Creates a new #GstNavigation message with type
571
 * #GST_NAVIGATION_MESSAGE_MOUSE_OVER.
572
 *
573
 * Returns: The new #GstMessage.
574
 */
575
GstMessage *
576
gst_navigation_message_new_mouse_over (GstObject * src, gboolean active)
577
0
{
578
0
  GstStructure *s;
579
0
  GstMessage *m;
580
581
0
  s = gst_structure_new (GST_NAVIGATION_MESSAGE_NAME,
582
0
      "type", G_TYPE_STRING, "mouse-over", "active", G_TYPE_BOOLEAN, active,
583
0
      NULL);
584
585
0
  m = gst_message_new_custom (GST_MESSAGE_ELEMENT, src, s);
586
587
0
  return m;
588
0
}
589
590
/**
591
 * gst_navigation_message_parse_mouse_over:
592
 * @message: A #GstMessage to inspect.
593
 * @active: (out) (optional): A pointer to a gboolean to receive the
594
 *     active/inactive state, or NULL.
595
 *
596
 * Parse a #GstNavigation message of type #GST_NAVIGATION_MESSAGE_MOUSE_OVER
597
 * and extract the active/inactive flag. If the mouse over event is marked
598
 * active, it indicates that the mouse is over a clickable area.
599
 *
600
 * Returns: %TRUE if the message could be successfully parsed. %FALSE if not.
601
 */
602
gboolean
603
gst_navigation_message_parse_mouse_over (GstMessage * message,
604
    gboolean * active)
605
0
{
606
0
  if (!GST_NAVIGATION_MESSAGE_HAS_TYPE (message, MOUSE_OVER))
607
0
    return FALSE;
608
609
0
  if (active) {
610
0
    const GstStructure *s = gst_message_get_structure (message);
611
0
    if (!gst_structure_get_boolean (s, "active", active))
612
0
      return FALSE;
613
0
  }
614
615
0
  return TRUE;
616
0
}
617
618
/**
619
 * gst_navigation_message_new_event:
620
 * @src: A #GstObject to set as source of the new message.
621
 * @event: (transfer none): A navigation #GstEvent
622
 *
623
 * Creates a new #GstNavigation message with type
624
 * #GST_NAVIGATION_MESSAGE_EVENT.
625
 *
626
 * Returns: The new #GstMessage.
627
 *
628
 * Since: 1.6
629
 */
630
GstMessage *
631
gst_navigation_message_new_event (GstObject * src, GstEvent * event)
632
0
{
633
0
  GstStructure *s;
634
0
  GstMessage *m;
635
636
0
  s = gst_structure_new (GST_NAVIGATION_MESSAGE_NAME,
637
0
      "type", G_TYPE_STRING, "event", "event", GST_TYPE_EVENT, event, NULL);
638
639
0
  m = gst_message_new_custom (GST_MESSAGE_ELEMENT, src, s);
640
641
0
  return m;
642
0
}
643
644
/**
645
 * gst_navigation_message_parse_event:
646
 * @message: A #GstMessage to inspect.
647
 * @event: (out) (optional) (transfer full): a pointer to a #GstEvent to receive
648
 *     the contained navigation event.
649
 *
650
 * Parse a #GstNavigation message of type #GST_NAVIGATION_MESSAGE_EVENT
651
 * and extract contained #GstEvent. The caller must unref the @event when done
652
 * with it.
653
 *
654
 * Returns: %TRUE if the message could be successfully parsed. %FALSE if not.
655
 *
656
 * Since: 1.6
657
 */
658
gboolean
659
gst_navigation_message_parse_event (GstMessage * message, GstEvent ** event)
660
0
{
661
0
  if (!GST_NAVIGATION_MESSAGE_HAS_TYPE (message, EVENT))
662
0
    return FALSE;
663
664
0
  if (event) {
665
0
    const GstStructure *s = gst_message_get_structure (message);
666
0
    if (!gst_structure_get (s, "event", GST_TYPE_EVENT, event, NULL))
667
0
      return FALSE;
668
0
  }
669
670
0
  return TRUE;
671
0
}
672
673
/**
674
 * gst_navigation_message_new_commands_changed:
675
 * @src: A #GstObject to set as source of the new message.
676
 *
677
 * Creates a new #GstNavigation message with type
678
 * #GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED
679
 *
680
 * Returns: The new #GstMessage.
681
 */
682
GstMessage *
683
gst_navigation_message_new_commands_changed (GstObject * src)
684
0
{
685
0
  GstStructure *s;
686
0
  GstMessage *m;
687
688
0
  s = gst_structure_new (GST_NAVIGATION_MESSAGE_NAME,
689
0
      "type", G_TYPE_STRING, "commands-changed", NULL);
690
691
0
  m = gst_message_new_custom (GST_MESSAGE_ELEMENT, src, s);
692
693
0
  return m;
694
0
}
695
696
/**
697
 * gst_navigation_message_new_angles_changed:
698
 * @src: A #GstObject to set as source of the new message.
699
 * @cur_angle: The currently selected angle.
700
 * @n_angles: The number of viewing angles now available.
701
 *
702
 * Creates a new #GstNavigation message with type
703
 * #GST_NAVIGATION_MESSAGE_ANGLES_CHANGED for notifying an application
704
 * that the current angle, or current number of angles available in a
705
 * multiangle video has changed.
706
 *
707
 * Returns: The new #GstMessage.
708
 */
709
GstMessage *
710
gst_navigation_message_new_angles_changed (GstObject * src, guint cur_angle,
711
    guint n_angles)
712
0
{
713
0
  GstStructure *s;
714
0
  GstMessage *m;
715
716
0
  s = gst_structure_new (GST_NAVIGATION_MESSAGE_NAME,
717
0
      "type", G_TYPE_STRING, "angles-changed",
718
0
      "angle", G_TYPE_UINT, cur_angle, "angles", G_TYPE_UINT, n_angles, NULL);
719
720
0
  m = gst_message_new_custom (GST_MESSAGE_ELEMENT, src, s);
721
722
0
  return m;
723
0
}
724
725
/**
726
 * gst_navigation_message_parse_angles_changed:
727
 * @message: A #GstMessage to inspect.
728
 * @cur_angle: (out) (optional): A pointer to a #guint to receive the new
729
 *     current angle number, or NULL
730
 * @n_angles: (out) (optional): A pointer to a #guint to receive the new angle
731
 *     count, or NULL.
732
 *
733
 * Parse a #GstNavigation message of type GST_NAVIGATION_MESSAGE_ANGLES_CHANGED
734
 * and extract the @cur_angle and @n_angles parameters.
735
 *
736
 * Returns: %TRUE if the message could be successfully parsed. %FALSE if not.
737
 */
738
gboolean
739
gst_navigation_message_parse_angles_changed (GstMessage * message,
740
    guint * cur_angle, guint * n_angles)
741
0
{
742
0
  const GstStructure *s;
743
0
  gboolean ret = TRUE;
744
745
0
  g_return_val_if_fail (GST_NAVIGATION_MESSAGE_HAS_TYPE (message,
746
0
          ANGLES_CHANGED), FALSE);
747
748
0
  s = gst_message_get_structure (message);
749
0
  if (cur_angle)
750
0
    ret &= gst_structure_get_uint (s, "angle", cur_angle);
751
752
0
  if (n_angles)
753
0
    ret &= gst_structure_get_uint (s, "angles", n_angles);
754
755
0
  WARN_IF_FAIL (ret, "Couldn't extract details from angles-changed event");
756
757
0
  return ret;
758
0
}
759
760
#define GST_NAVIGATION_EVENT_HAS_TYPE(event,event_type) \
761
(gst_navigation_event_get_type (event) == GST_NAVIGATION_EVENT_ ## event_type)
762
763
/**
764
 * gst_navigation_event_get_type:
765
 * @event: A #GstEvent to inspect.
766
 *
767
 * Inspect a #GstEvent and return the #GstNavigationEventType of the event, or
768
 * #GST_NAVIGATION_EVENT_INVALID if the event is not a #GstNavigation event.
769
 */
770
GstNavigationEventType
771
gst_navigation_event_get_type (GstEvent * event)
772
0
{
773
0
  const GstStructure *s;
774
0
  const gchar *e_type;
775
776
0
  if (event == NULL || GST_EVENT_TYPE (event) != GST_EVENT_NAVIGATION)
777
0
    return GST_NAVIGATION_EVENT_INVALID;
778
779
0
  s = gst_event_get_structure (event);
780
0
  if (s == NULL || !gst_structure_has_name (s, GST_NAVIGATION_EVENT_NAME))
781
0
    return GST_NAVIGATION_EVENT_INVALID;
782
783
0
  e_type = gst_structure_get_string (s, "event");
784
0
  if (e_type == NULL)
785
0
    return GST_NAVIGATION_EVENT_INVALID;
786
787
0
  if (g_str_equal (e_type, "mouse-button-press"))
788
0
    return GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS;
789
0
  else if (g_str_equal (e_type, "mouse-button-release"))
790
0
    return GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE;
791
0
  else if (g_str_equal (e_type, "mouse-move"))
792
0
    return GST_NAVIGATION_EVENT_MOUSE_MOVE;
793
0
  else if (g_str_equal (e_type, "mouse-scroll"))
794
0
    return GST_NAVIGATION_EVENT_MOUSE_SCROLL;
795
0
  else if (g_str_equal (e_type, "key-press"))
796
0
    return GST_NAVIGATION_EVENT_KEY_PRESS;
797
0
  else if (g_str_equal (e_type, "key-release"))
798
0
    return GST_NAVIGATION_EVENT_KEY_RELEASE;
799
0
  else if (g_str_equal (e_type, "command"))
800
0
    return GST_NAVIGATION_EVENT_COMMAND;
801
0
  else if (g_str_equal (e_type, "touch-down"))
802
0
    return GST_NAVIGATION_EVENT_TOUCH_DOWN;
803
0
  else if (g_str_equal (e_type, "touch-up"))
804
0
    return GST_NAVIGATION_EVENT_TOUCH_UP;
805
0
  else if (g_str_equal (e_type, "touch-cancel"))
806
0
    return GST_NAVIGATION_EVENT_TOUCH_CANCEL;
807
0
  else if (g_str_equal (e_type, "touch-motion"))
808
0
    return GST_NAVIGATION_EVENT_TOUCH_MOTION;
809
0
  else if (g_str_equal (e_type, "touch-frame"))
810
0
    return GST_NAVIGATION_EVENT_TOUCH_FRAME;
811
0
  else if (g_str_equal (e_type, "mouse-double-click"))
812
0
    return GST_NAVIGATION_EVENT_MOUSE_DOUBLE_CLICK;
813
814
0
  return GST_NAVIGATION_EVENT_INVALID;
815
0
}
816
817
/**
818
 * gst_navigation_event_new_key_press:
819
 * @key: A string identifying the key press.
820
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
821
 * Shift and Alt).
822
 *
823
 * Create a new navigation event for the given key press.
824
 *
825
 * Returns: (transfer full): a new #GstEvent
826
 *
827
 * Since: 1.22
828
 */
829
GstEvent *
830
gst_navigation_event_new_key_press (const gchar * key,
831
    GstNavigationModifierType state)
832
0
{
833
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
834
0
          "event", G_TYPE_STRING, "key-press", "key", G_TYPE_STRING, key,
835
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
836
0
}
837
838
/**
839
 * gst_navigation_event_new_key_release:
840
 * @key: A string identifying the released key.
841
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
842
 * Shift and Alt).
843
 *
844
 * Create a new navigation event for the given key release.
845
 *
846
 * Returns: (transfer full): a new #GstEvent
847
 *
848
 * Since: 1.22
849
 */
850
GstEvent *
851
gst_navigation_event_new_key_release (const gchar * key,
852
    GstNavigationModifierType state)
853
0
{
854
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
855
0
          "event", G_TYPE_STRING, "key-release", "key", G_TYPE_STRING, key,
856
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
857
0
}
858
859
/**
860
 * gst_navigation_event_new_mouse_button_press:
861
 * @button: The number of the pressed mouse button.
862
 * @x: The x coordinate of the mouse cursor.
863
 * @y: The y coordinate of the mouse cursor.
864
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
865
 * Shift and Alt).
866
 *
867
 * Create a new navigation event for the given key mouse button press.
868
 *
869
 * Returns: (transfer full): a new #GstEvent
870
 *
871
 * Since: 1.22
872
 */
873
GstEvent *
874
gst_navigation_event_new_mouse_button_press (gint button, gdouble x, gdouble y,
875
    GstNavigationModifierType state)
876
0
{
877
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
878
0
          "event", G_TYPE_STRING, "mouse-button-press",
879
0
          "button", G_TYPE_INT, button, "pointer_x", G_TYPE_DOUBLE, x,
880
0
          "pointer_y", G_TYPE_DOUBLE, y,
881
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
882
0
}
883
884
/**
885
 * gst_navigation_event_new_mouse_double_click:
886
 * @button: The number of the pressed mouse button.
887
 * @x: The x coordinate of the mouse cursor.
888
 * @y: The y coordinate of the mouse cursor.
889
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
890
 * Shift and Alt).
891
 *
892
 * Create a new navigation event for the given key mouse double click.
893
 *
894
 * Returns: (transfer full): a new #GstEvent
895
 *
896
 * Since: 1.26
897
 */
898
GstEvent *
899
gst_navigation_event_new_mouse_double_click (gint button, gdouble x, gdouble y,
900
    GstNavigationModifierType state)
901
0
{
902
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
903
0
          "event", G_TYPE_STRING, "mouse-double-click",
904
0
          "button", G_TYPE_INT, button, "pointer_x", G_TYPE_DOUBLE, x,
905
0
          "pointer_y", G_TYPE_DOUBLE, y,
906
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
907
0
}
908
909
/**
910
 * gst_navigation_event_new_mouse_button_release:
911
 * @button: The number of the released mouse button.
912
 * @x: The x coordinate of the mouse cursor.
913
 * @y: The y coordinate of the mouse cursor.
914
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
915
 * Shift and Alt).
916
 *
917
 * Create a new navigation event for the given key mouse button release.
918
 *
919
 * Returns: (transfer full): a new #GstEvent
920
 *
921
 * Since: 1.22
922
 */
923
GstEvent *
924
gst_navigation_event_new_mouse_button_release (gint button, gdouble x,
925
    gdouble y, GstNavigationModifierType state)
926
0
{
927
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
928
0
          "event", G_TYPE_STRING, "mouse-button-release",
929
0
          "button", G_TYPE_INT, button, "pointer_x", G_TYPE_DOUBLE, x,
930
0
          "pointer_y", G_TYPE_DOUBLE, y,
931
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
932
0
}
933
934
/**
935
 * gst_navigation_event_new_mouse_move:
936
 * @x: The x coordinate of the mouse cursor.
937
 * @y: The y coordinate of the mouse cursor.
938
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
939
 * Shift and Alt).
940
 *
941
 * Create a new navigation event for the new mouse location.
942
 *
943
 * Returns: (transfer full): a new #GstEvent
944
 *
945
 * Since: 1.22
946
 */
947
GstEvent *
948
gst_navigation_event_new_mouse_move (gdouble x, gdouble y,
949
    GstNavigationModifierType state)
950
0
{
951
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
952
0
          "event", G_TYPE_STRING, "mouse-move",
953
0
          "pointer_x", G_TYPE_DOUBLE, x,
954
0
          "pointer_y", G_TYPE_DOUBLE, y,
955
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
956
0
}
957
958
/**
959
 * gst_navigation_event_new_mouse_scroll:
960
 * @x: The x coordinate of the mouse cursor.
961
 * @y: The y coordinate of the mouse cursor.
962
 * @delta_x: The x component of the scroll movement.
963
 * @delta_y: The y component of the scroll movement.
964
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
965
 * Shift and Alt).
966
 *
967
 * Create a new navigation event for the mouse scroll.
968
 *
969
 * Returns: (transfer full): a new #GstEvent
970
 *
971
 * Since: 1.22
972
 */
973
GstEvent *
974
gst_navigation_event_new_mouse_scroll (gdouble x, gdouble y, gdouble delta_x,
975
    gdouble delta_y, GstNavigationModifierType state)
976
0
{
977
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
978
0
          "event", G_TYPE_STRING, "mouse-scroll",
979
0
          "pointer_x", G_TYPE_DOUBLE, x, "pointer_y", G_TYPE_DOUBLE, y,
980
0
          "delta_pointer_x", G_TYPE_DOUBLE, delta_x,
981
0
          "delta_pointer_y", G_TYPE_DOUBLE, delta_y,
982
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
983
0
}
984
985
/**
986
 * gst_navigation_event_new_command:
987
 * @command: The navigation command to use.
988
 *
989
 * Create a new navigation event given navigation command..
990
 *
991
 * Returns: (transfer full): a new #GstEvent
992
 *
993
 * Since: 1.22
994
 */
995
GstEvent *
996
gst_navigation_event_new_command (GstNavigationCommand command)
997
0
{
998
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
999
0
          "event", G_TYPE_STRING, "command",
1000
0
          "command-code", G_TYPE_UINT, (guint) command, NULL));
1001
0
}
1002
1003
/**
1004
 * gst_navigation_event_new_touch_down:
1005
 * @identifier: A number uniquely identifying this touch point. It must stay
1006
 *    unique to this touch point at least until an up event is sent for
1007
 *    the same identifier, or all touch points are cancelled.
1008
 * @x: The x coordinate of the new touch point.
1009
 * @y: The y coordinate of the new touch point.
1010
 * @pressure: Pressure data of the touch point, from 0.0 to 1.0, or NaN if no
1011
 *    data is available.
1012
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
1013
 * Shift and Alt).
1014
 *
1015
 * Create a new navigation event for an added touch point.
1016
 *
1017
 * Returns: (transfer full): a new #GstEvent
1018
 *
1019
 * Since: 1.22
1020
 */
1021
GstEvent *
1022
gst_navigation_event_new_touch_down (guint identifier, gdouble x, gdouble y,
1023
    gdouble pressure, GstNavigationModifierType state)
1024
0
{
1025
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
1026
0
          "event", G_TYPE_STRING, "touch-down",
1027
0
          "identifier", G_TYPE_UINT, identifier,
1028
0
          "pointer_x", G_TYPE_DOUBLE, x,
1029
0
          "pointer_y", G_TYPE_DOUBLE, y,
1030
0
          "pressure", G_TYPE_DOUBLE, pressure,
1031
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
1032
0
}
1033
1034
/**
1035
 * gst_navigation_event_new_touch_motion:
1036
 * @identifier: A number uniquely identifying this touch point. It must
1037
 *    correlate to exactly one previous touch_start event.
1038
 * @x: The x coordinate of the touch point.
1039
 * @y: The y coordinate of the touch point.
1040
 * @pressure: Pressure data of the touch point, from 0.0 to 1.0, or NaN if no
1041
 *    data is available.
1042
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
1043
 * Shift and Alt).
1044
 *
1045
 * Create a new navigation event for a moved touch point.
1046
 *
1047
 * Returns: (transfer full): a new #GstEvent
1048
 *
1049
 * Since: 1.22
1050
 */
1051
GstEvent *
1052
gst_navigation_event_new_touch_motion (guint identifier, gdouble x, gdouble y,
1053
    gdouble pressure, GstNavigationModifierType state)
1054
0
{
1055
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
1056
0
          "event", G_TYPE_STRING, "touch-motion",
1057
0
          "identifier", G_TYPE_UINT, identifier,
1058
0
          "pointer_x", G_TYPE_DOUBLE, x,
1059
0
          "pointer_y", G_TYPE_DOUBLE, y,
1060
0
          "pressure", G_TYPE_DOUBLE, pressure,
1061
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
1062
0
}
1063
1064
/**
1065
 * gst_navigation_event_new_touch_up:
1066
 * @identifier: A number uniquely identifying this touch point. It must
1067
 *    correlate to exactly one previous down event, but can be reused
1068
 *    after sending this event.
1069
 * @x: The x coordinate of the touch point.
1070
 * @y: The y coordinate of the touch point.
1071
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
1072
 * Shift and Alt).
1073
 *
1074
 * Create a new navigation event for a removed touch point.
1075
 *
1076
 * Returns: (transfer full): a new #GstEvent
1077
 *
1078
 * Since: 1.22
1079
 */
1080
GstEvent *
1081
gst_navigation_event_new_touch_up (guint identifier, gdouble x, gdouble y,
1082
    GstNavigationModifierType state)
1083
0
{
1084
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
1085
0
          "event", G_TYPE_STRING, "touch-up",
1086
0
          "identifier", G_TYPE_UINT, identifier,
1087
0
          "pointer_x", G_TYPE_DOUBLE, x, "pointer_y", G_TYPE_DOUBLE, y,
1088
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
1089
0
}
1090
1091
/**
1092
 * gst_navigation_event_new_touch_frame:
1093
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
1094
 * Shift and Alt).
1095
 *
1096
 * Create a new navigation event signalling the end of a touch frame. Touch
1097
 * frames signal that all previous down, motion and up events not followed by
1098
 * another touch frame event already should be considered simultaneous.
1099
 *
1100
 * Returns: (transfer full): a new #GstEvent
1101
 *
1102
 * Since: 1.22
1103
 */
1104
GstEvent *
1105
gst_navigation_event_new_touch_frame (GstNavigationModifierType state)
1106
0
{
1107
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
1108
0
          "event", G_TYPE_STRING, "touch-frame",
1109
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
1110
0
}
1111
1112
1113
/**
1114
 * gst_navigation_event_new_touch_cancel:
1115
 * @state: a bit-mask representing the state of the modifier keys (e.g. Control,
1116
 * Shift and Alt).
1117
 *
1118
 * Create a new navigation event signalling that all currently active touch
1119
 * points are cancelled and should be discarded. For example, under Wayland
1120
 * this event might be sent when a swipe passes the threshold to be recognized
1121
 * as a gesture by the compositor.
1122
 *
1123
 * Returns: (transfer full): a new #GstEvent
1124
 *
1125
 * Since: 1.22
1126
 */
1127
GstEvent *
1128
gst_navigation_event_new_touch_cancel (GstNavigationModifierType state)
1129
0
{
1130
0
  return gst_event_new_navigation (gst_structure_new (GST_NAVIGATION_EVENT_NAME,
1131
0
          "event", G_TYPE_STRING, "touch-cancel",
1132
0
          "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state, NULL));
1133
0
}
1134
1135
/**
1136
 * gst_navigation_event_parse_key_event:
1137
 * @event: A #GstEvent to inspect.
1138
 * @key: (out) (optional) (transfer none): A pointer to a location to receive
1139
 *     the string identifying the key press. The returned string is owned by the
1140
 *     event, and valid only until the event is unreffed.
1141
 *
1142
 * Note: Modifier keys (as defined in #GstNavigationModifierType)
1143
 * [press](GST_NAVIGATION_EVENT_KEY_PRESS) and
1144
 * [release](GST_NAVIGATION_KEY_PRESS) events are generated even if those states are
1145
 * present on all other related events
1146
 */
1147
gboolean
1148
gst_navigation_event_parse_key_event (GstEvent * event, const gchar ** key)
1149
0
{
1150
0
  GstNavigationEventType e_type GST_UNUSED_CHECKS;
1151
0
  const GstStructure *s;
1152
1153
0
#ifndef G_DISABLE_CHECKS
1154
0
  e_type = gst_navigation_event_get_type (event);
1155
0
  g_return_val_if_fail (e_type == GST_NAVIGATION_EVENT_KEY_PRESS ||
1156
0
      e_type == GST_NAVIGATION_EVENT_KEY_RELEASE, FALSE);
1157
0
#endif
1158
1159
0
  if (key) {
1160
0
    s = gst_event_get_structure (event);
1161
0
    *key = gst_structure_get_string (s, "key");
1162
0
    if (*key == NULL)
1163
0
      return FALSE;
1164
0
  }
1165
1166
0
  return TRUE;
1167
0
}
1168
1169
/**
1170
 * gst_navigation_event_parse_mouse_button_event:
1171
 * @event: A #GstEvent to inspect.
1172
 * @button: (out) (optional): Pointer to a gint that will receive the button
1173
 *     number associated with the event.
1174
 * @x: (out) (optional): Pointer to a gdouble to receive the x coordinate of the
1175
 *     mouse button event.
1176
 * @y: (out) (optional): Pointer to a gdouble to receive the y coordinate of the
1177
 *     mouse button event.
1178
 *
1179
 * Retrieve the details of either a #GstNavigation mouse button press event or
1180
 * a mouse button release event. Determine which type the event is using
1181
 * gst_navigation_event_get_type() to retrieve the #GstNavigationEventType.
1182
 *
1183
 * Returns: TRUE if the button number and both coordinates could be extracted,
1184
 *     otherwise FALSE.
1185
 */
1186
gboolean
1187
gst_navigation_event_parse_mouse_button_event (GstEvent * event, gint * button,
1188
    gdouble * x, gdouble * y)
1189
0
{
1190
0
  GstNavigationEventType e_type GST_UNUSED_CHECKS;
1191
0
  const GstStructure *s;
1192
0
  gboolean ret = TRUE;
1193
1194
0
#ifndef G_DISABLE_CHECKS
1195
0
  e_type = gst_navigation_event_get_type (event);
1196
0
  g_return_val_if_fail (e_type == GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS ||
1197
0
      e_type == GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE ||
1198
0
      e_type == GST_NAVIGATION_EVENT_MOUSE_DOUBLE_CLICK, FALSE);
1199
0
#endif
1200
1201
0
  s = gst_event_get_structure (event);
1202
0
  if (x)
1203
0
    ret &= gst_structure_get_double (s, "pointer_x", x);
1204
0
  if (y)
1205
0
    ret &= gst_structure_get_double (s, "pointer_y", y);
1206
0
  if (button)
1207
0
    ret &= gst_structure_get_int (s, "button", button);
1208
1209
0
  WARN_IF_FAIL (ret, "Couldn't extract details from mouse button event");
1210
1211
0
  return ret;
1212
0
}
1213
1214
/**
1215
 * gst_navigation_event_parse_mouse_move_event:
1216
 * @event: A #GstEvent to inspect.
1217
 * @x: (out) (optional): Pointer to a gdouble to receive the x coordinate of the
1218
 *     mouse movement.
1219
 * @y: (out) (optional): Pointer to a gdouble to receive the y coordinate of the
1220
 *     mouse movement.
1221
 *
1222
 * Inspect a #GstNavigation mouse movement event and extract the coordinates
1223
 * of the event.
1224
 *
1225
 * Returns: TRUE if both coordinates could be extracted, otherwise FALSE.
1226
 */
1227
gboolean
1228
gst_navigation_event_parse_mouse_move_event (GstEvent * event, gdouble * x,
1229
    gdouble * y)
1230
0
{
1231
0
  const GstStructure *s;
1232
0
  gboolean ret = TRUE;
1233
1234
0
  g_return_val_if_fail (GST_NAVIGATION_EVENT_HAS_TYPE (event, MOUSE_MOVE),
1235
0
      FALSE);
1236
1237
0
  s = gst_event_get_structure (event);
1238
0
  if (x)
1239
0
    ret &= gst_structure_get_double (s, "pointer_x", x);
1240
0
  if (y)
1241
0
    ret &= gst_structure_get_double (s, "pointer_y", y);
1242
1243
0
  WARN_IF_FAIL (ret, "Couldn't extract positions from mouse move event");
1244
1245
0
  return ret;
1246
0
}
1247
1248
/**
1249
 * gst_navigation_event_parse_mouse_scroll_event:
1250
 * @event: A #GstEvent to inspect.
1251
 * @x: (out) (optional): Pointer to a gdouble to receive the x coordinate of the
1252
 *     mouse movement.
1253
 * @y: (out) (optional): Pointer to a gdouble to receive the y coordinate of the
1254
 *     mouse movement.
1255
 * @delta_x: (out) (optional): Pointer to a gdouble to receive the delta_x coordinate of the
1256
 *     mouse movement.
1257
 * @delta_y: (out) (optional): Pointer to a gdouble to receive the delta_y coordinate of the
1258
 *     mouse movement.
1259
 *
1260
 * Inspect a #GstNavigation mouse scroll event and extract the coordinates
1261
 * of the event.
1262
 *
1263
 * Returns: TRUE if all coordinates could be extracted, otherwise FALSE.
1264
 *
1265
 * Since: 1.18
1266
 */
1267
gboolean
1268
gst_navigation_event_parse_mouse_scroll_event (GstEvent * event,
1269
    gdouble * x, gdouble * y, gdouble * delta_x, gdouble * delta_y)
1270
0
{
1271
0
  const GstStructure *s;
1272
0
  gboolean ret = TRUE;
1273
1274
0
  g_return_val_if_fail (GST_NAVIGATION_EVENT_HAS_TYPE (event, MOUSE_SCROLL),
1275
0
      FALSE);
1276
1277
0
  s = gst_event_get_structure (event);
1278
0
  if (x)
1279
0
    ret &= gst_structure_get_double (s, "pointer_x", x);
1280
0
  if (y)
1281
0
    ret &= gst_structure_get_double (s, "pointer_y", y);
1282
0
  if (delta_x)
1283
0
    ret &= gst_structure_get_double (s, "delta_pointer_x", delta_x);
1284
0
  if (delta_y)
1285
0
    ret &= gst_structure_get_double (s, "delta_pointer_y", delta_y);
1286
1287
0
  WARN_IF_FAIL (ret, "Couldn't extract positions from mouse scroll event");
1288
1289
0
  return ret;
1290
0
}
1291
1292
/**
1293
 * gst_navigation_event_parse_command:
1294
 * @event: A #GstEvent to inspect.
1295
 * @command: (out) (optional): Pointer to GstNavigationCommand to receive the
1296
 *     type of the navigation event.
1297
 *
1298
 * Inspect a #GstNavigation command event and retrieve the enum value of the
1299
 * associated command.
1300
 *
1301
 * Returns: TRUE if the navigation command could be extracted, otherwise FALSE.
1302
 */
1303
gboolean
1304
gst_navigation_event_parse_command (GstEvent * event,
1305
    GstNavigationCommand * command)
1306
0
{
1307
0
  const GstStructure *s;
1308
0
  gboolean ret = TRUE;
1309
1310
0
  g_return_val_if_fail (GST_NAVIGATION_EVENT_HAS_TYPE (event, COMMAND), FALSE);
1311
1312
0
  if (command) {
1313
0
    s = gst_event_get_structure (event);
1314
0
    ret = gst_structure_get_uint (s, "command-code", (guint *) command);
1315
0
    WARN_IF_FAIL (ret, "Couldn't extract command code from command event");
1316
0
  }
1317
1318
0
  return ret;
1319
0
}
1320
1321
/**
1322
 * gst_navigation_event_parse_touch_event:
1323
 * @event: A #GstEvent to inspect.
1324
 * @identifier: (out) (optional): Pointer to a guint that will receive the
1325
 *     identifier unique to this touch point.
1326
 * @x: (out) (optional): Pointer to a gdouble that will receive the x
1327
 *     coordinate of the touch event.
1328
 * @y: (out) (optional): Pointer to a gdouble that will receive the y
1329
 *     coordinate of the touch event.
1330
 * @pressure: (out) (optional): Pointer to a gdouble that will receive the
1331
 *     force of the touch event, in the range from 0.0 to 1.0. If pressure
1332
 *     data is not available, NaN will be set instead.
1333
 *
1334
 * Retrieve the details of a #GstNavigation touch-down or touch-motion event.
1335
 * Determine which type the event is using gst_navigation_event_get_type()
1336
 * to retrieve the #GstNavigationEventType.
1337
 *
1338
 * Returns: TRUE if all details could be extracted, otherwise FALSE.
1339
 *
1340
 * Since: 1.22
1341
 */
1342
gboolean
1343
gst_navigation_event_parse_touch_event (GstEvent * event, guint * identifier,
1344
    gdouble * x, gdouble * y, gdouble * pressure)
1345
0
{
1346
0
  GstNavigationEventType e_type GST_UNUSED_CHECKS;
1347
0
  const GstStructure *s;
1348
0
  gboolean ret = TRUE;
1349
1350
0
#ifndef G_DISABLE_CHECKS
1351
0
  e_type = gst_navigation_event_get_type (event);
1352
0
  g_return_val_if_fail (e_type == GST_NAVIGATION_EVENT_TOUCH_DOWN ||
1353
0
      e_type == GST_NAVIGATION_EVENT_TOUCH_MOTION, FALSE);
1354
0
#endif
1355
1356
0
  s = gst_event_get_structure (event);
1357
0
  if (identifier)
1358
0
    ret &= gst_structure_get_uint (s, "identifier", identifier);
1359
0
  if (x)
1360
0
    ret &= gst_structure_get_double (s, "pointer_x", x);
1361
0
  if (y)
1362
0
    ret &= gst_structure_get_double (s, "pointer_y", y);
1363
0
  if (pressure)
1364
0
    ret &= gst_structure_get_double (s, "pressure", pressure);
1365
1366
0
  WARN_IF_FAIL (ret, "Couldn't extract details from touch event");
1367
1368
0
  return ret;
1369
0
}
1370
1371
/**
1372
 * gst_navigation_event_parse_touch_up_event:
1373
 * @event: A #GstEvent to inspect.
1374
 * @identifier: (out) (optional): Pointer to a guint that will receive the
1375
 *     identifier unique to this touch point.
1376
 * @x: (out) (optional): Pointer to a gdouble that will receive the x
1377
 *     coordinate of the touch event.
1378
 * @y: (out) (optional): Pointer to a gdouble that will receive the y
1379
 *     coordinate of the touch event.
1380
 *
1381
 * Retrieve the details of a #GstNavigation touch-up event.
1382
 *
1383
 * Returns: TRUE if all details could be extracted, otherwise FALSE.
1384
 *
1385
 * Since: 1.22
1386
 */
1387
gboolean
1388
gst_navigation_event_parse_touch_up_event (GstEvent * event,
1389
    guint * identifier, gdouble * x, gdouble * y)
1390
0
{
1391
0
  const GstStructure *s;
1392
0
  gboolean ret = TRUE;
1393
1394
0
  g_return_val_if_fail (GST_NAVIGATION_EVENT_HAS_TYPE (event, TOUCH_UP), FALSE);
1395
1396
0
  s = gst_event_get_structure (event);
1397
0
  if (identifier)
1398
0
    ret &= gst_structure_get_uint (s, "identifier", identifier);
1399
0
  if (x)
1400
0
    ret &= gst_structure_get_double (s, "pointer_x", x);
1401
0
  if (y)
1402
0
    ret &= gst_structure_get_double (s, "pointer_y", y);
1403
1404
0
  WARN_IF_FAIL (ret, "Couldn't extract details from touch-up event");
1405
1406
0
  return ret;
1407
0
}
1408
1409
/**
1410
 * gst_navigation_event_get_coordinates:
1411
 * @event: The #GstEvent to inspect.
1412
 * @x: (out) (optional): Pointer to a gdouble to receive the x coordinate of the
1413
 *     navigation event.
1414
 * @y: (out) (optional): Pointer to a gdouble to receive the y coordinate of the
1415
 *     navigation event.
1416
 *
1417
 * Try to retrieve x and y coordinates of a #GstNavigation event.
1418
 *
1419
 * Returns: A boolean indicating success.
1420
 *
1421
 * Since: 1.22
1422
 */
1423
gboolean
1424
gst_navigation_event_get_coordinates (GstEvent * event,
1425
    gdouble * x, gdouble * y)
1426
0
{
1427
0
  GstNavigationEventType e_type;
1428
0
  const GstStructure *s;
1429
0
  gboolean ret = TRUE;
1430
1431
0
  e_type = gst_navigation_event_get_type (event);
1432
0
  if (e_type != GST_NAVIGATION_EVENT_MOUSE_MOVE
1433
0
      && e_type != GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS
1434
0
      && e_type != GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE
1435
0
      && e_type != GST_NAVIGATION_EVENT_TOUCH_DOWN
1436
0
      && e_type != GST_NAVIGATION_EVENT_TOUCH_MOTION
1437
0
      && e_type != GST_NAVIGATION_EVENT_TOUCH_UP) {
1438
0
    return FALSE;
1439
0
  }
1440
1441
0
  s = gst_event_get_structure (event);
1442
0
  if (x)
1443
0
    ret &= gst_structure_get_double (s, "pointer_x", x);
1444
0
  if (y)
1445
0
    ret &= gst_structure_get_double (s, "pointer_y", y);
1446
1447
0
  WARN_IF_FAIL (ret, "Couldn't extract coordinates from the event");
1448
1449
0
  return ret;
1450
0
}
1451
1452
/**
1453
 * gst_navigation_event_set_coordinates:
1454
 * @event: The #GstEvent to modify.
1455
 * @x: The x coordinate to set.
1456
 * @y: The y coordinate to set.
1457
 *
1458
 * Try to set x and y coordinates on a #GstNavigation event. The event must
1459
 * be writable.
1460
 *
1461
 * Returns: A boolean indicating success.
1462
 *
1463
 * Since: 1.22
1464
 */
1465
gboolean
1466
gst_navigation_event_set_coordinates (GstEvent * event, gdouble x, gdouble y)
1467
0
{
1468
0
  GstNavigationEventType e_type;
1469
0
  GstStructure *s;
1470
1471
0
  g_return_val_if_fail (gst_event_is_writable (event), FALSE);
1472
1473
0
  e_type = gst_navigation_event_get_type (event);
1474
0
  if (e_type != GST_NAVIGATION_EVENT_MOUSE_MOVE
1475
0
      && e_type != GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS
1476
0
      && e_type != GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE
1477
0
      && e_type != GST_NAVIGATION_EVENT_TOUCH_DOWN
1478
0
      && e_type != GST_NAVIGATION_EVENT_TOUCH_MOTION
1479
0
      && e_type != GST_NAVIGATION_EVENT_TOUCH_UP) {
1480
0
    return FALSE;
1481
0
  }
1482
1483
0
  s = gst_event_writable_structure (event);
1484
0
  gst_structure_set (s, "pointer_x", G_TYPE_DOUBLE, x,
1485
0
      "pointer_y", G_TYPE_DOUBLE, y, NULL);
1486
1487
0
  return TRUE;
1488
0
}
1489
1490
1491
/**
1492
 * gst_navigation_event_parse_modifier_state:
1493
 * @event: The #GstEvent to modify.
1494
 * @state: (out): a bit-mask representing the state of the modifier keys (e.g. Control,
1495
 * Shift and Alt).
1496
 *
1497
 * Returns: TRUE if the event is a #GstNavigation event with associated
1498
 * modifiers state, otherwise FALSE.
1499
 *
1500
 * Since: 1.22
1501
 */
1502
gboolean
1503
gst_navigation_event_parse_modifier_state (GstEvent * event,
1504
    GstNavigationModifierType * state)
1505
0
{
1506
0
  GstNavigationEventType e_type;
1507
0
  const GstStructure *s;
1508
1509
0
  g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
1510
1511
0
  e_type = gst_navigation_event_get_type (event);
1512
0
  if (e_type == GST_NAVIGATION_EVENT_COMMAND) {
1513
0
    return FALSE;
1514
0
  }
1515
1516
0
  s = gst_event_get_structure (event);
1517
0
  if (!gst_structure_get (s, "state", GST_TYPE_NAVIGATION_MODIFIER_TYPE, state,
1518
0
          NULL))
1519
0
    *state = GST_NAVIGATION_MODIFIER_NONE;
1520
1521
0
  return TRUE;
1522
0
}