tizen 2.0 init
[framework/multimedia/gst-plugins-base0.10.git] / gst-libs / gst / interfaces / navigation.c
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., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /**
24  * SECTION:gstnavigation
25  * @short_description: Interface for creating, sending and parsing navigation
26  * events.
27  *
28  * The Navigation interface is used for creating and injecting navigation related
29  * events such as mouse button presses, cursor motion and key presses. The associated
30  * library also provides methods for parsing received events, and for sending and
31  * receiving navigation related bus events. One main usecase is DVD menu navigation.
32  *
33  * The main parts of the API are:
34  * <itemizedlist>
35  * <listitem>
36  * <para>
37  * The GstNavigation interface, implemented by elements which provide an application
38  * with the ability to create and inject navigation events into the pipeline.
39  * </para>
40  * </listitem>
41  * <listitem>
42  * <para>
43  * GstNavigation event handling API. GstNavigation events are created in response to
44  * calls on a GstNavigation interface implementation, and sent in the pipeline. Upstream
45  * elements can use the navigation event API functions to parse the contents of received
46  * messages.
47  * </para>
48  * </listitem>
49  * <listitem>
50  * <para>
51  * GstNavigation message handling API. GstNavigation messages may be sent on the message
52  * bus to inform applications of navigation related changes in the pipeline, such as the
53  * mouse moving over a clickable region, or the set of available angles changing.
54  * </para><para>
55  * The GstNavigation message functions provide functions for creating and parsing
56  * custom bus messages for signaling GstNavigation changes.
57  * </para>
58  * </listitem>
59  * </itemizedlist>
60  */
61
62 #ifdef HAVE_CONFIG_H
63 #include "config.h"
64 #endif
65
66 #include <gst/interfaces/navigation.h>
67 #include <gst/interfaces/interfaces-enumtypes.h>
68
69 static void gst_navigation_class_init (GstNavigationInterface * iface);
70
71 #define GST_NAVIGATION_MESSAGE_NAME "GstNavigationMessage"
72 #define GST_NAVIGATION_QUERY_NAME "GstNavigationQuery"
73 #define GST_NAVIGATION_EVENT_NAME "application/x-gst-navigation"
74
75 #define WARN_IF_FAIL(exp,msg) if(G_UNLIKELY(!(exp))){g_warning("%s",(msg));}
76
77 GType
78 gst_navigation_get_type (void)
79 {
80   static GType gst_navigation_type = 0;
81
82   if (!gst_navigation_type) {
83     static const GTypeInfo gst_navigation_info = {
84       sizeof (GstNavigationInterface),
85       (GBaseInitFunc) gst_navigation_class_init,
86       NULL,
87       NULL,
88       NULL,
89       NULL,
90       0,
91       0,
92       NULL,
93     };
94
95     gst_navigation_type = g_type_register_static (G_TYPE_INTERFACE,
96         "GstNavigation", &gst_navigation_info, 0);
97   }
98
99   return gst_navigation_type;
100 }
101
102 static void
103 gst_navigation_class_init (GstNavigationInterface * iface)
104 {
105   /* default virtual functions */
106   iface->send_event = NULL;
107 }
108
109 /* The interface implementer should make sure that the object can handle
110  * the event. */
111 void
112 gst_navigation_send_event (GstNavigation * navigation, GstStructure * structure)
113 {
114   GstNavigationInterface *iface = GST_NAVIGATION_GET_IFACE (navigation);
115
116   if (iface->send_event) {
117     iface->send_event (navigation, structure);
118   }
119 }
120
121 /**
122  * gst_navigation_send_key_event:
123  * @navigation: The navigation interface instance
124  * @event: The type of the key event. Recognised values are "key-press" and
125  * "key-release"
126  * @key: Character representation of the key. This is typically as produced
127  * by XKeysymToString.
128  */
129 void
130 gst_navigation_send_key_event (GstNavigation * navigation, const char *event,
131     const char *key)
132 {
133   gst_navigation_send_event (navigation,
134       gst_structure_new (GST_NAVIGATION_EVENT_NAME, "event", G_TYPE_STRING,
135           event, "key", G_TYPE_STRING, key, NULL));
136 }
137
138 /**
139  * gst_navigation_send_mouse_event:
140  * @navigation: The navigation interface instance
141  * @event: The type of mouse event, as a text string. Recognised values are
142  * "mouse-button-press", "mouse-button-release" and "mouse-move".
143  * @button: The button number of the button being pressed or released. Pass 0
144  * for mouse-move events.
145  * @x: The x coordinate of the mouse event.
146  * @y: The y coordinate of the mouse event.
147  *
148  * Sends a mouse event to the navigation interface. Mouse event coordinates
149  * are sent relative to the display space of the related output area. This is
150  * usually the size in pixels of the window associated with the element
151  * implementing the #GstNavigation interface.
152  *
153  */
154 void
155 gst_navigation_send_mouse_event (GstNavigation * navigation, const char *event,
156     int button, double x, double y)
157 {
158   gst_navigation_send_event (navigation,
159       gst_structure_new (GST_NAVIGATION_EVENT_NAME, "event", G_TYPE_STRING,
160           event, "button", G_TYPE_INT, button, "pointer_x", G_TYPE_DOUBLE, x,
161           "pointer_y", G_TYPE_DOUBLE, y, NULL));
162 }
163
164 /**
165  * gst_navigation_send_command:
166  * @navigation: The navigation interface instance
167  * @command: The command to issue
168  *
169  * Sends the indicated command to the navigation interface.
170  *
171  * Since: 0.10.23
172  */
173 void
174 gst_navigation_send_command (GstNavigation * navigation,
175     GstNavigationCommand command)
176 {
177   gst_navigation_send_event (navigation,
178       gst_structure_new (GST_NAVIGATION_EVENT_NAME, "event", G_TYPE_STRING,
179           "command", "command-code", G_TYPE_UINT, (guint) command, NULL));
180 }
181
182 /* Navigation Queries */
183
184 #define GST_NAVIGATION_QUERY_HAS_TYPE(query,query_type) \
185 (gst_navigation_query_get_type (query) == GST_NAVIGATION_QUERY_ ## query_type)
186
187 /**
188  * gst_navigation_query_get_type:
189  * @query: The query to inspect
190  *
191  * Inspect a #GstQuery and return the #GstNavigationQueryType associated with
192  * it if it is a #GstNavigation query.
193  *
194  * Returns: The #GstNavigationQueryType of the query, or
195  * #GST_NAVIGATION_QUERY_INVALID
196  * Since: 0.10.23
197  */
198 GstNavigationQueryType
199 gst_navigation_query_get_type (GstQuery * query)
200 {
201   const GstStructure *s;
202   const gchar *q_type;
203
204   if (query == NULL || GST_QUERY_TYPE (query) != GST_QUERY_CUSTOM)
205     return GST_NAVIGATION_QUERY_INVALID;
206
207   s = gst_query_get_structure (query);
208   if (s == NULL || !gst_structure_has_name (s, GST_NAVIGATION_QUERY_NAME))
209     return GST_NAVIGATION_QUERY_INVALID;
210
211   q_type = gst_structure_get_string (s, "type");
212   if (q_type == NULL)
213     return GST_NAVIGATION_QUERY_INVALID;
214
215   if (g_str_equal (q_type, "commands"))
216     return GST_NAVIGATION_QUERY_COMMANDS;
217   else if (g_str_equal (q_type, "angles"))
218     return GST_NAVIGATION_QUERY_ANGLES;
219
220   return GST_NAVIGATION_QUERY_INVALID;
221 }
222
223 /**
224  * gst_navigation_query_new_commands:
225  *
226  * Create a new #GstNavigation commands query. When executed, it will
227  * query the pipeline for the set of currently available commands.
228  *
229  * Returns: The new query.
230  * Since: 0.10.23
231  */
232 GstQuery *
233 gst_navigation_query_new_commands (void)
234 {
235   GstQuery *query;
236   GstStructure *structure;
237
238   structure = gst_structure_new (GST_NAVIGATION_QUERY_NAME,
239       "type", G_TYPE_STRING, "commands", NULL);
240   query = gst_query_new_application (GST_QUERY_CUSTOM, structure);
241
242   return query;
243 }
244
245 static void
246 gst_query_list_add_command (GValue * list, GstNavigationCommand val)
247 {
248   GValue item = { 0, };
249
250   g_value_init (&item, GST_TYPE_NAVIGATION_COMMAND);
251   g_value_set_enum (&item, val);
252   gst_value_list_append_value (list, &item);
253   g_value_unset (&item);
254 }
255
256 /**
257  * gst_navigation_query_set_commands:
258  * @query: a #GstQuery
259  * @n_cmds: the number of commands to set.
260  * @...: A list of @GstNavigationCommand values, @n_cmds entries long.
261  *
262  * Set the #GstNavigation command query result fields in @query. The number
263  * of commands passed must be equal to @n_commands.
264  *
265  * Since: 0.10.23
266  */
267 void
268 gst_navigation_query_set_commands (GstQuery * query, gint n_cmds, ...)
269 {
270   va_list ap;
271   GValue list = { 0, };
272   GstStructure *structure;
273   gint i;
274
275   g_return_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS));
276
277   g_value_init (&list, GST_TYPE_LIST);
278
279   va_start (ap, n_cmds);
280   for (i = 0; i < n_cmds; i++) {
281     GstNavigationCommand val = va_arg (ap, GstNavigationCommand);
282     gst_query_list_add_command (&list, val);
283   }
284   va_end (ap);
285
286   structure = gst_query_get_structure (query);
287   gst_structure_set_value (structure, "commands", &list);
288
289   g_value_unset (&list);
290 }
291
292 /**
293  * gst_navigation_query_set_commandsv:
294  * @query: a #GstQuery
295  * @n_cmds: the number of commands to set.
296  * @cmds: An array containing @n_cmds @GstNavigationCommand values.
297  *
298  * Set the #GstNavigation command query result fields in @query. The number
299  * of commands passed must be equal to @n_commands.
300  *
301  * Since: 0.10.23
302  */
303 void
304 gst_navigation_query_set_commandsv (GstQuery * query, gint n_cmds,
305     GstNavigationCommand * cmds)
306 {
307   GValue list = { 0, };
308   GstStructure *structure;
309   gint i;
310
311   g_return_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS));
312
313   g_value_init (&list, GST_TYPE_LIST);
314   for (i = 0; i < n_cmds; i++) {
315     gst_query_list_add_command (&list, cmds[i]);
316   }
317   structure = gst_query_get_structure (query);
318   gst_structure_set_value (structure, "commands", &list);
319
320   g_value_unset (&list);
321 }
322
323 /**
324  * gst_navigation_query_parse_commands_length:
325  * @query: a #GstQuery
326  * @n_cmds: the number of commands in this query.
327  *
328  * Parse the number of commands in the #GstNavigation commands @query.
329  *
330  * Returns: %TRUE if the query could be successfully parsed. %FALSE if not.
331  * Since: 0.10.23
332  */
333 gboolean
334 gst_navigation_query_parse_commands_length (GstQuery * query, guint * n_cmds)
335 {
336   GstStructure *structure;
337   const GValue *list;
338
339   g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS), FALSE);
340
341   if (n_cmds == NULL)
342     return TRUE;
343
344   structure = gst_query_get_structure (query);
345   list = gst_structure_get_value (structure, "commands");
346   if (list == NULL)
347     *n_cmds = 0;
348   else
349     *n_cmds = gst_value_list_get_size (list);
350
351   return TRUE;
352 }
353
354 /**
355  * gst_navigation_query_parse_commands_nth:
356  * @query: a #GstQuery
357  * @nth: the nth command to retrieve.
358  * @cmd: a pointer to store the nth command into.
359  *
360  * Parse the #GstNavigation command query and retrieve the @nth command from
361  * it into @cmd. If the list contains less elements than @nth, @cmd will be
362  * set to #GST_NAVIGATION_COMMAND_INVALID.
363  *
364  * Returns: %TRUE if the query could be successfully parsed. %FALSE if not.
365  * Since: 0.10.23
366  */
367 gboolean
368 gst_navigation_query_parse_commands_nth (GstQuery * query, guint nth,
369     GstNavigationCommand * cmd)
370 {
371   GstStructure *structure;
372   const GValue *list;
373
374   g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS), FALSE);
375
376   if (cmd == NULL)
377     return TRUE;
378
379   structure = gst_query_get_structure (query);
380   list = gst_structure_get_value (structure, "commands");
381   if (list == NULL) {
382     *cmd = GST_NAVIGATION_COMMAND_INVALID;
383   } else {
384     if (nth < gst_value_list_get_size (list)) {
385       *cmd = (GstNavigationCommand)
386           g_value_get_enum (gst_value_list_get_value (list, nth));
387     } else
388       *cmd = GST_NAVIGATION_COMMAND_INVALID;
389   }
390
391   return TRUE;
392 }
393
394 /**
395  * gst_navigation_query_new_angles:
396  *
397  * Create a new #GstNavigation angles query. When executed, it will
398  * query the pipeline for the set of currently available angles, which may be
399  * greater than one in a multiangle video.
400  *
401  * Returns: The new query.
402  * Since: 0.10.23
403  */
404 GstQuery *
405 gst_navigation_query_new_angles (void)
406 {
407   GstQuery *query;
408   GstStructure *structure;
409
410   structure = gst_structure_new (GST_NAVIGATION_QUERY_NAME,
411       "type", G_TYPE_STRING, "angles", NULL);
412   query = gst_query_new_application (GST_QUERY_CUSTOM, structure);
413
414   return query;
415 }
416
417 /**
418  * gst_navigation_query_set_angles:
419  * @query: a #GstQuery
420  * @cur_angle: the current viewing angle to set.
421  * @n_angles: the number of viewing angles to set.
422  *
423  * Set the #GstNavigation angles query result field in @query.
424  *
425  * Since: 0.10.23
426  */
427 void
428 gst_navigation_query_set_angles (GstQuery * query, guint cur_angle,
429     guint n_angles)
430 {
431   GstStructure *structure;
432
433   g_return_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, ANGLES));
434
435   structure = gst_query_get_structure (query);
436   gst_structure_set (structure,
437       "angle", G_TYPE_UINT, cur_angle, "angles", G_TYPE_UINT, n_angles, NULL);
438 }
439
440 /**
441  * gst_navigation_query_parse_angles:
442  * @query: a #GstQuery
443  * @cur_angle: Pointer to a #guint into which to store the currently selected
444  * angle value from the query, or NULL
445  * @n_angles: Pointer to a #guint into which to store the number of angles
446  * value from the query, or NULL
447  *
448  * Parse the current angle number in the #GstNavigation angles @query into the
449  * #guint pointed to by the @cur_angle variable, and the number of available
450  * angles into the #guint pointed to by the @n_angles variable.
451  *
452  * Returns: %TRUE if the query could be successfully parsed. %FALSE if not.
453  * Since: 0.10.23
454  */
455 gboolean
456 gst_navigation_query_parse_angles (GstQuery * query, guint * cur_angle,
457     guint * n_angles)
458 {
459   GstStructure *structure;
460   gboolean ret = TRUE;
461
462   g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, ANGLES), FALSE);
463
464   structure = gst_query_get_structure (query);
465
466   if (cur_angle)
467     ret &= gst_structure_get_uint (structure, "angle", cur_angle);
468
469   if (n_angles)
470     ret &= gst_structure_get_uint (structure, "angles", n_angles);
471
472   WARN_IF_FAIL (ret, "Couldn't extract details from angles query");
473
474   return ret;
475 }
476
477 /* Navigation Messages */
478
479 #define GST_NAVIGATION_MESSAGE_HAS_TYPE(msg,msg_type) \
480 (gst_navigation_message_get_type (msg) == GST_NAVIGATION_MESSAGE_ ## msg_type)
481
482 /**
483  * gst_navigation_message_get_type:
484  * @message: A #GstMessage to inspect.
485  *
486  * Check a bus message to see if it is a #GstNavigation event, and return
487  * the #GstNavigationMessageType identifying the type of the message if so.
488  *
489  * Returns: The type of the #GstMessage, or
490  * #GST_NAVIGATION_MESSAGE_INVALID if the message is not a #GstNavigation
491  * notification.
492  *
493  * Since: 0.10.23
494  */
495 GstNavigationMessageType
496 gst_navigation_message_get_type (GstMessage * message)
497 {
498   const GstStructure *s;
499   const gchar *m_type;
500
501   if (message == NULL || GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
502     return GST_NAVIGATION_MESSAGE_INVALID;
503
504   s = gst_message_get_structure (message);
505   if (s == NULL || !gst_structure_has_name (s, GST_NAVIGATION_MESSAGE_NAME))
506     return GST_NAVIGATION_MESSAGE_INVALID;
507
508   m_type = gst_structure_get_string (s, "type");
509   if (m_type == NULL)
510     return GST_NAVIGATION_MESSAGE_INVALID;
511
512   if (g_str_equal (m_type, "mouse-over"))
513     return GST_NAVIGATION_MESSAGE_MOUSE_OVER;
514   else if (g_str_equal (m_type, "commands-changed"))
515     return GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED;
516   else if (g_str_equal (m_type, "angles-changed"))
517     return GST_NAVIGATION_MESSAGE_ANGLES_CHANGED;
518
519   return GST_NAVIGATION_MESSAGE_INVALID;
520 }
521
522 /**
523  * gst_navigation_message_new_mouse_over:
524  * @src: A #GstObject to set as source of the new message.
525  * @active: %TRUE if the mouse has entered a clickable area of the display.
526  * %FALSE if it over a non-clickable area.
527  *
528  * Creates a new #GstNavigation message with type
529  * #GST_NAVIGATION_MESSAGE_MOUSE_OVER.
530  *
531  * Returns: The new #GstMessage.
532  * Since: 0.10.23
533  */
534 GstMessage *
535 gst_navigation_message_new_mouse_over (GstObject * src, gboolean active)
536 {
537   GstStructure *s;
538   GstMessage *m;
539
540   s = gst_structure_new (GST_NAVIGATION_MESSAGE_NAME,
541       "type", G_TYPE_STRING, "mouse-over", "active", G_TYPE_BOOLEAN, active,
542       NULL);
543
544   m = gst_message_new_custom (GST_MESSAGE_ELEMENT, src, s);
545
546   return m;
547 }
548
549 /**
550  * gst_navigation_message_parse_mouse_over:
551  * @message: A #GstMessage to inspect.
552  * @active: A pointer to a gboolean to receive the active/inactive state,
553  * or NULL.
554  *
555  * Parse a #GstNavigation message of type #GST_NAVIGATION_MESSAGE_MOUSE_OVER
556  * and extract the active/inactive flag. If the mouse over event is marked
557  * active, it indicates that the mouse is over a clickable area.
558  *
559  * Returns: %TRUE if the message could be successfully parsed. %FALSE if not.
560  * Since: 0.10.23
561  */
562 gboolean
563 gst_navigation_message_parse_mouse_over (GstMessage * message,
564     gboolean * active)
565 {
566   if (!GST_NAVIGATION_MESSAGE_HAS_TYPE (message, MOUSE_OVER))
567     return FALSE;
568
569   if (active) {
570     const GstStructure *s = gst_message_get_structure (message);
571     if (gst_structure_get_boolean (s, "active", active) == FALSE)
572       return FALSE;
573   }
574
575   return TRUE;
576 }
577
578 /**
579  * gst_navigation_message_new_commands_changed:
580  * @src: A #GstObject to set as source of the new message.
581  *
582  * Creates a new #GstNavigation message with type
583  * #GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED
584  *
585  * Returns: The new #GstMessage.
586  * Since: 0.10.23
587  */
588 GstMessage *
589 gst_navigation_message_new_commands_changed (GstObject * src)
590 {
591   GstStructure *s;
592   GstMessage *m;
593
594   s = gst_structure_new (GST_NAVIGATION_MESSAGE_NAME,
595       "type", G_TYPE_STRING, "commands-changed", NULL);
596
597   m = gst_message_new_custom (GST_MESSAGE_ELEMENT, src, s);
598
599   return m;
600 }
601
602 /**
603  * gst_navigation_message_new_angles_changed:
604  * @src: A #GstObject to set as source of the new message.
605  * @cur_angle: The currently selected angle.
606  * @n_angles: The number of viewing angles now available.
607  *
608  * Creates a new #GstNavigation message with type
609  * #GST_NAVIGATION_MESSAGE_ANGLES_CHANGED for notifying an application
610  * that the current angle, or current number of angles available in a
611  * multiangle video has changed.
612  *
613  * Returns: The new #GstMessage.
614  * Since: 0.10.23
615  */
616 GstMessage *
617 gst_navigation_message_new_angles_changed (GstObject * src, guint cur_angle,
618     guint n_angles)
619 {
620   GstStructure *s;
621   GstMessage *m;
622
623   s = gst_structure_new (GST_NAVIGATION_MESSAGE_NAME,
624       "type", G_TYPE_STRING, "angles-changed",
625       "angle", G_TYPE_UINT, cur_angle, "angles", G_TYPE_UINT, n_angles, NULL);
626
627   m = gst_message_new_custom (GST_MESSAGE_ELEMENT, src, s);
628
629   return m;
630 }
631
632 /**
633  * gst_navigation_message_parse_angles_changed:
634  * @message: A #GstMessage to inspect.
635  * @cur_angle: A pointer to a #guint to receive the new current angle number,
636  * or NULL
637  * @n_angles: A pointer to a #guint to receive the new angle count, or NULL.
638  *
639  * Parse a #GstNavigation message of type GST_NAVIGATION_MESSAGE_ANGLES_CHANGED
640  * and extract the @cur_angle and @n_angles parameters.
641  *
642  * Returns: %TRUE if the message could be successfully parsed. %FALSE if not.
643  * Since: 0.10.23
644  */
645 gboolean
646 gst_navigation_message_parse_angles_changed (GstMessage * message,
647     guint * cur_angle, guint * n_angles)
648 {
649   const GstStructure *s;
650   gboolean ret = TRUE;
651
652   g_return_val_if_fail (GST_NAVIGATION_MESSAGE_HAS_TYPE (message,
653           ANGLES_CHANGED), FALSE);
654
655   s = gst_message_get_structure (message);
656   if (cur_angle)
657     ret &= gst_structure_get_uint (s, "angle", cur_angle);
658
659   if (n_angles)
660     ret &= gst_structure_get_uint (s, "angles", n_angles);
661
662   WARN_IF_FAIL (ret, "Couldn't extract details from angles-changed event");
663
664   return ret;
665 }
666
667 #define GST_NAVIGATION_EVENT_HAS_TYPE(event,event_type) \
668 (gst_navigation_event_get_type (event) == GST_NAVIGATION_EVENT_ ## event_type)
669
670 /**
671  * gst_navigation_event_get_type:
672  * @event: A #GstEvent to inspect.
673  *
674  * Inspect a #GstEvent and return the #GstNavigationEventType of the event, or
675  * #GST_NAVIGATION_EVENT_INVALID if the event is not a #GstNavigation event.
676  *
677  * Since: 0.10.23
678  */
679 GstNavigationEventType
680 gst_navigation_event_get_type (GstEvent * event)
681 {
682   const GstStructure *s;
683   const gchar *e_type;
684
685   if (event == NULL || GST_EVENT_TYPE (event) != GST_EVENT_NAVIGATION)
686     return GST_NAVIGATION_EVENT_INVALID;
687
688   s = gst_event_get_structure (event);
689   if (s == NULL || !gst_structure_has_name (s, GST_NAVIGATION_EVENT_NAME))
690     return GST_NAVIGATION_EVENT_INVALID;
691
692   e_type = gst_structure_get_string (s, "event");
693   if (e_type == NULL)
694     return GST_NAVIGATION_EVENT_INVALID;
695
696   if (g_str_equal (e_type, "mouse-button-press"))
697     return GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS;
698   else if (g_str_equal (e_type, "mouse-button-release"))
699     return GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE;
700   else if (g_str_equal (e_type, "mouse-move"))
701     return GST_NAVIGATION_EVENT_MOUSE_MOVE;
702   else if (g_str_equal (e_type, "key-press"))
703     return GST_NAVIGATION_EVENT_KEY_PRESS;
704   else if (g_str_equal (e_type, "key-release"))
705     return GST_NAVIGATION_EVENT_KEY_RELEASE;
706   else if (g_str_equal (e_type, "command"))
707     return GST_NAVIGATION_EVENT_COMMAND;
708
709   return GST_NAVIGATION_EVENT_INVALID;
710 }
711
712 /**
713  * gst_navigation_event_parse_key_event:
714  * @event: A #GstEvent to inspect.
715  * @key: A pointer to a location to receive the string identifying the key
716  * press. The returned string is owned by the event, and valid only until the
717  * event is unreffed.
718  *
719  * Since: 0.10.23
720  */
721 gboolean
722 gst_navigation_event_parse_key_event (GstEvent * event, const gchar ** key)
723 {
724   GstNavigationEventType e_type;
725   const GstStructure *s;
726
727   e_type = gst_navigation_event_get_type (event);
728   g_return_val_if_fail (e_type == GST_NAVIGATION_EVENT_KEY_PRESS ||
729       e_type == GST_NAVIGATION_EVENT_KEY_RELEASE, FALSE);
730
731   if (key) {
732     s = gst_event_get_structure (event);
733     *key = gst_structure_get_string (s, "key");
734     if (*key == NULL)
735       return FALSE;
736   }
737
738   return TRUE;
739 }
740
741 /**
742  * gst_navigation_event_parse_mouse_button_event:
743  * @event: A #GstEvent to inspect.
744  * @button: Pointer to a gint that will receive the button number associated
745  * with the event.
746  * @x: Pointer to a gdouble to receive the x coordinate of the mouse button
747  * event.
748  * @y: Pointer to a gdouble to receive the y coordinate of the mouse button
749  * event.
750  * 
751  * Retrieve the details of either a #GstNavigation mouse button press event or
752  * a mouse button release event. Determine which type the event is using
753  * gst_navigation_event_get_type() to retrieve the #GstNavigationEventType.
754  *
755  * Returns: TRUE if the button number and both coordinates could be extracted,
756  *     otherwise FALSE.
757  *
758  * Since: 0.10.23
759  */
760 gboolean
761 gst_navigation_event_parse_mouse_button_event (GstEvent * event, gint * button,
762     gdouble * x, gdouble * y)
763 {
764   GstNavigationEventType e_type;
765   const GstStructure *s;
766   gboolean ret = TRUE;
767
768   e_type = gst_navigation_event_get_type (event);
769   g_return_val_if_fail (e_type == GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS ||
770       e_type == GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE, FALSE);
771
772   s = gst_event_get_structure (event);
773   if (x)
774     ret &= gst_structure_get_double (s, "pointer_x", x);
775   if (y)
776     ret &= gst_structure_get_double (s, "pointer_y", y);
777   if (button)
778     ret &= gst_structure_get_int (s, "button", button);
779
780   WARN_IF_FAIL (ret, "Couldn't extract details from mouse button event");
781
782   return ret;
783 }
784
785 /**
786  * gst_navigation_event_parse_mouse_move_event:
787  * @event: A #GstEvent to inspect.
788  * @x: Pointer to a gdouble to receive the x coordinate of the mouse movement.
789  * @y: Pointer to a gdouble to receive the y coordinate of the mouse movement.
790  *
791  * Inspect a #GstNavigation mouse movement event and extract the coordinates
792  * of the event.
793  *
794  * Returns: TRUE if both coordinates could be extracted, otherwise FALSE.
795  *
796  * Since: 0.10.23
797  */
798 gboolean
799 gst_navigation_event_parse_mouse_move_event (GstEvent * event, gdouble * x,
800     gdouble * y)
801 {
802   const GstStructure *s;
803   gboolean ret = TRUE;
804
805   g_return_val_if_fail (GST_NAVIGATION_EVENT_HAS_TYPE (event, MOUSE_MOVE),
806       FALSE);
807
808   s = gst_event_get_structure (event);
809   if (x)
810     ret &= gst_structure_get_double (s, "pointer_x", x);
811   if (y)
812     ret &= gst_structure_get_double (s, "pointer_y", y);
813
814   WARN_IF_FAIL (ret, "Couldn't extract positions from mouse move event");
815
816   return ret;
817 }
818
819 /**
820  * gst_navigation_event_parse_command:
821  * @event: A #GstEvent to inspect.
822  * @command: Pointer to GstNavigationCommand to receive the type of the
823  * navigation event.
824  *
825  * Inspect a #GstNavigation command event and retrieve the enum value of the
826  * associated command.
827  *
828  * Returns: TRUE if the navigation command could be extracted, otherwise FALSE.
829  *
830  * Since: 0.10.23
831  */
832 gboolean
833 gst_navigation_event_parse_command (GstEvent * event,
834     GstNavigationCommand * command)
835 {
836   const GstStructure *s;
837   gboolean ret = TRUE;
838
839   g_return_val_if_fail (GST_NAVIGATION_EVENT_HAS_TYPE (event, COMMAND), FALSE);
840
841   if (command) {
842     s = gst_event_get_structure (event);
843     ret = gst_structure_get_uint (s, "command-code", (guint *) command);
844     WARN_IF_FAIL (ret, "Couldn't extract command code from command event");
845   }
846
847   return ret;
848 }