diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt
index 340cffce72..15d2a9c5f1 100644
--- a/docs/libs/gst-plugins-base-libs-sections.txt
+++ b/docs/libs/gst-plugins-base-libs-sections.txt
@@ -506,16 +506,50 @@ gst_mixer_track_get_type
gst/interfaces/navigation.h
GstNavigation
GstNavigationInterface
+GstNavigationCommand
+GstNavigationMessageType
+GstNavigationQueryType
gst_navigation_send_event
gst_navigation_send_key_event
gst_navigation_send_mouse_event
+gst_navigation_send_command
+
+gst_navigation_message_get_type
+gst_navigation_message_new_angles_changed
+gst_navigation_message_new_commands_changed
+gst_navigation_message_new_mouse_over
+gst_navigation_message_parse_mouse_over
+gst_navigation_query_new_angles
+gst_navigation_query_get_type
+gst_navigation_query_new_commands
+gst_navigation_query_parse_angles
+gst_navigation_query_parse_commands_length
+gst_navigation_query_parse_commands_nth
+gst_navigation_query_set_angles
+gst_navigation_query_set_commands
+gst_navigation_query_set_commandsv
+
+GST_NAVIGATION_COMMAND_DVD_ANGLE_MENU
+GST_NAVIGATION_COMMAND_DVD_AUDIO_MENU
+GST_NAVIGATION_COMMAND_DVD_CHAPTER_MENU
+GST_NAVIGATION_COMMAND_DVD_MENU
+GST_NAVIGATION_COMMAND_DVD_ROOT_MENU
+GST_NAVIGATION_COMMAND_DVD_SUBPICTURE_MENU
+GST_NAVIGATION_COMMAND_DVD_TITLE_MENU
+
GST_TYPE_NAVIGATION
GST_NAVIGATION
GST_NAVIGATION_GET_IFACE
+GST_TYPE_NAVIGATION_COMMAND
+GST_TYPE_NAVIGATION_MESSAGE_TYPE
+GST_TYPE_NAVIGATION_QUERY_TYPE
GST_IS_NAVIGATION
gst_navigation_get_type
+gst_navigation_message_type_get_type
+gst_navigation_query_type_get_type
+gst_navigation_command_get_type
diff --git a/gst-libs/gst/interfaces/navigation.c b/gst-libs/gst/interfaces/navigation.c
index cd1f844336..892ee75323 100644
--- a/gst-libs/gst/interfaces/navigation.c
+++ b/gst-libs/gst/interfaces/navigation.c
@@ -24,9 +24,14 @@
#endif
#include
+#include
static void gst_navigation_class_init (GstNavigationInterface * iface);
+#define GST_NAVIGATION_MESSAGE_NAME "GstNavigationMessage"
+#define GST_NAVIGATION_QUERY_NAME "GstNavigationQuery"
+#define GST_NAVIGATION_EVENT_NAME "application/x-gst-navigation"
+
GType
gst_navigation_get_type (void)
{
@@ -71,21 +76,714 @@ gst_navigation_send_event (GstNavigation * navigation, GstStructure * structure)
}
}
+/**
+ * gst_navigation_send_mouse_event:
+ * @navigation: The navigation interface instance
+ * @event: The type of the key event. Recognised values are "key-press" and
+ * "key-release"
+ * @key: Character representation of the key. This is typically as produced
+ * by XKeysymToString.
+ */
void
gst_navigation_send_key_event (GstNavigation * navigation, const char *event,
const char *key)
{
gst_navigation_send_event (navigation,
- gst_structure_new ("application/x-gst-navigation", "event", G_TYPE_STRING,
+ gst_structure_new (GST_NAVIGATION_EVENT_NAME, "event", G_TYPE_STRING,
event, "key", G_TYPE_STRING, key, NULL));
}
+/**
+ * gst_navigation_send_mouse_event:
+ * @navigation: The navigation interface instance
+ * @event: The type of mouse event, as a text string. Recognised values are
+ * "mouse-button-press", "mouse-button-release" and "mouse-move".
+ * @button: The button number of the button being pressed or released. Pass 0
+ * for mouse-move events.
+ * @x: The x coordinate of the mouse event.
+ * @y: The y coordinate of the mouse event.
+ *
+ * Sends a mouse event to the navigation interface. Mouse event coordinates
+ * are sent relative to the display space of the related output area. This is
+ * usually the size in pixels of the window associated with the element
+ * implementing the #GstNavigation interface.
+ *
+ */
void
gst_navigation_send_mouse_event (GstNavigation * navigation, const char *event,
int button, double x, double y)
{
gst_navigation_send_event (navigation,
- gst_structure_new ("application/x-gst-navigation", "event", G_TYPE_STRING,
+ gst_structure_new (GST_NAVIGATION_EVENT_NAME, "event", G_TYPE_STRING,
event, "button", G_TYPE_INT, button, "pointer_x", G_TYPE_DOUBLE, x,
"pointer_y", G_TYPE_DOUBLE, y, NULL));
}
+
+/**
+ * gst_navigation_send_command:
+ * @navigation: The navigation interface instance
+ * @command: The command to issue
+ *
+ * Sends the indicated command to the navigation interface.
+ *
+ * Since: 0.10.23
+ */
+void
+gst_navigation_send_command (GstNavigation * navigation,
+ GstNavigationCommand command)
+{
+ gst_navigation_send_event (navigation,
+ gst_structure_new (GST_NAVIGATION_EVENT_NAME, "event", G_TYPE_STRING,
+ "command", "command-code", G_TYPE_UINT, (guint) command, NULL));
+}
+
+/* Navigation Queries */
+
+#define GST_NAVIGATION_QUERY_HAS_TYPE(query,query_type) \
+(gst_navigation_query_get_type (query) == GST_NAVIGATION_QUERY_ ## query_type)
+
+/**
+ * gst_navigation_query_get_type:
+ * @query: The query to inspect
+ *
+ * Inspect a #GstQuery and return the #GstNavigationQueryType associated with
+ * it if it is a #GstNavigation query.
+ *
+ * Returns: The #GstNavigationQueryType of the query, or
+ * #GST_NAVIGATION_QUERY_INVALID
+ * Since: 0.10.23
+ */
+GstNavigationQueryType
+gst_navigation_query_get_type (GstQuery * query)
+{
+ const GstStructure *s;
+ const gchar *q_type;
+
+ if (query == NULL || GST_QUERY_TYPE (query) != GST_QUERY_CUSTOM)
+ return GST_NAVIGATION_QUERY_INVALID;
+
+ s = gst_query_get_structure (query);
+ if (s == NULL || !gst_structure_has_name (s, GST_NAVIGATION_QUERY_NAME))
+ return GST_NAVIGATION_QUERY_INVALID;
+
+ q_type = gst_structure_get_string (s, "type");
+ if (q_type == NULL)
+ return GST_NAVIGATION_QUERY_INVALID;
+
+ if (g_str_equal (q_type, "commands"))
+ return GST_NAVIGATION_QUERY_COMMANDS;
+ else if (g_str_equal (q_type, "angles"))
+ return GST_NAVIGATION_QUERY_ANGLES;
+
+ return GST_NAVIGATION_QUERY_INVALID;
+}
+
+/**
+ * gst_navigation_query_new_commands:
+ *
+ * Create a new #GstNavigation commands query. When executed, it will
+ * query the pipeline for the set of currently available commands.
+ *
+ * Returns: The new query.
+ * Since: 0.10.23
+ */
+GstQuery *
+gst_navigation_query_new_commands (void)
+{
+ GstQuery *query;
+ GstStructure *structure;
+
+ structure = gst_structure_new (GST_NAVIGATION_QUERY_NAME,
+ "type", G_TYPE_STRING, "commands", NULL);
+ query = gst_query_new_application (GST_QUERY_CUSTOM, structure);
+
+ return query;
+}
+
+static void
+gst_query_list_add_command (GValue * list, GstNavigationCommand val)
+{
+ GValue item = { 0, };
+
+ g_value_init (&item, GST_TYPE_NAVIGATION_COMMAND);
+ g_value_set_enum (&item, val);
+ gst_value_list_append_value (list, &item);
+ g_value_unset (&item);
+}
+
+/**
+ * gst_navigation_query_set_commands:
+ * @query: a #GstQuery
+ * @n_cmds: the number of commands to set.
+ * @...: A list of @GstNavigationCommand values, @n_cmds entries long.
+ *
+ * Set the #GstNavigation command query result fields in @query. The number
+ * of commands passed must be equal to @n_commands.
+ *
+ * Since: 0.10.23
+ */
+void
+gst_navigation_query_set_commands (GstQuery * query, gint n_cmds, ...)
+{
+ va_list ap;
+ GValue list = { 0, };
+ GstStructure *structure;
+ gint i;
+
+ g_return_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS));
+
+ g_value_init (&list, GST_TYPE_LIST);
+
+ va_start (ap, n_cmds);
+ for (i = 0; i < n_cmds; i++) {
+ GstNavigationCommand val = va_arg (ap, GstNavigationCommand);
+ gst_query_list_add_command (&list, val);
+ }
+ va_end (ap);
+
+ structure = gst_query_get_structure (query);
+ gst_structure_set_value (structure, "commands", &list);
+
+ g_value_unset (&list);
+}
+
+/**
+ * gst_navigation_query_set_commandsv:
+ * @query: a #GstQuery
+ * @n_cmds: the number of commands to set.
+ * @cmds: An array containing @n_cmds @GstNavigationCommand values.
+ *
+ * Set the #GstNavigation command query result fields in @query. The number
+ * of commands passed must be equal to @n_commands.
+ *
+ * Since: 0.10.23
+ */
+void
+gst_navigation_query_set_commandsv (GstQuery * query, gint n_cmds,
+ GstNavigationCommand * cmds)
+{
+ GValue list = { 0, };
+ GstStructure *structure;
+ gint i;
+
+ g_return_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS));
+
+ g_value_init (&list, GST_TYPE_LIST);
+ for (i = 0; i < n_cmds; i++) {
+ gst_query_list_add_command (&list, cmds[i]);
+ }
+ structure = gst_query_get_structure (query);
+ gst_structure_set_value (structure, "commands", &list);
+
+ g_value_unset (&list);
+}
+
+/**
+ * gst_navigation_query_parse_commands_length:
+ * @query: a #GstQuery
+ * @n_cmds: the number of commands in this query.
+ *
+ * Parse the number of commands in the #GstNavigation commands @query.
+ *
+ * Returns: %TRUE if the query could be successfully parsed. %FALSE if not.
+ * Since: 0.10.23
+ */
+gboolean
+gst_navigation_query_parse_commands_length (GstQuery * query, guint * n_cmds)
+{
+ GstStructure *structure;
+ const GValue *list;
+
+ g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS), FALSE);
+
+ if (n_cmds == NULL)
+ return TRUE;
+
+ structure = gst_query_get_structure (query);
+ list = gst_structure_get_value (structure, "commands");
+ if (list == NULL)
+ *n_cmds = 0;
+ else
+ *n_cmds = gst_value_list_get_size (list);
+
+ return TRUE;
+}
+
+/**
+ * gst_navigation_query_parse_commands_nth:
+ * @query: a #GstQuery
+ * @nth: the nth command to retrieve.
+ * @cmd: a pointer to store the nth command into.
+ *
+ * Parse the #GstNavigation command query and retrieve the @nth command from
+ * it into @cmd. If the list contains less elements than @nth, @cmd will be
+ * set to #GST_NAVIGATION_COMMAND_INVALID.
+ *
+ * Returns: %TRUE if the query could be successfully parsed. %FALSE if not.
+ * Since: 0.10.23
+ */
+gboolean
+gst_navigation_query_parse_commands_nth (GstQuery * query, guint nth,
+ GstNavigationCommand * cmd)
+{
+ GstStructure *structure;
+ const GValue *list;
+
+ g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS), FALSE);
+
+ if (cmd == NULL)
+ return TRUE;
+
+ structure = gst_query_get_structure (query);
+ list = gst_structure_get_value (structure, "commands");
+ if (list == NULL) {
+ *cmd = GST_NAVIGATION_COMMAND_INVALID;
+ } else {
+ if (nth < gst_value_list_get_size (list)) {
+ *cmd = (GstNavigationCommand)
+ g_value_get_enum (gst_value_list_get_value (list, nth));
+ } else
+ *cmd = GST_NAVIGATION_COMMAND_INVALID;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_navigation_query_new_angles:
+ *
+ * Create a new #GstNavigation angles query. When executed, it will
+ * query the pipeline for the set of currently available angles, which may be
+ * greater than one in a multiangle video.
+ *
+ * Returns: The new query.
+ * Since: 0.10.23
+ */
+GstQuery *
+gst_navigation_query_new_angles (void)
+{
+ GstQuery *query;
+ GstStructure *structure;
+
+ structure = gst_structure_new (GST_NAVIGATION_QUERY_NAME,
+ "type", G_TYPE_STRING, "angles", NULL);
+ query = gst_query_new_application (GST_QUERY_CUSTOM, structure);
+
+ return query;
+}
+
+/**
+ * gst_navigation_query_set_angles:
+ * @query: a #GstQuery
+ * @cur_angle: the current viewing angle to set.
+ * @n_angles: the number of viewing angles to set.
+ *
+ * Set the #GstNavigation angles query result field in @query.
+ *
+ * Since: 0.10.23
+ */
+void
+gst_navigation_query_set_angles (GstQuery * query, guint cur_angle,
+ guint n_angles)
+{
+ GstStructure *structure;
+
+ g_return_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, ANGLES));
+
+ structure = gst_query_get_structure (query);
+ gst_structure_set (structure,
+ "angle", G_TYPE_UINT, cur_angle, "angles", G_TYPE_UINT, n_angles, NULL);
+}
+
+/**
+ * gst_navigation_query_parse_angles:
+ * @query: a #GstQuery
+ * @cur_angle: Pointer to a #guint into which to store the currently selected
+ * angle value from the query, or NULL
+ * @n_angles: Pointer to a #guint into which to store the number of angles
+ * value from the query, or NULL
+ *
+ * Parse the current angle number in the #GstNavigation angles @query into the
+ * #guint pointed to by the @cur_angle variable, and the number of available
+ * angles into the #guint pointed to by the @n_angles variable.
+ *
+ * Returns: %TRUE if the query could be successfully parsed. %FALSE if not.
+ * Since: 0.10.23
+ */
+gboolean
+gst_navigation_query_parse_angles (GstQuery * query, guint * cur_angle,
+ guint * n_angles)
+{
+ GstStructure *structure;
+
+ g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, ANGLES), FALSE);
+
+ structure = gst_query_get_structure (query);
+
+ if (cur_angle)
+ g_return_val_if_fail (gst_structure_get_uint (structure,
+ "angle", cur_angle), FALSE);
+
+ if (n_angles)
+ g_return_val_if_fail (gst_structure_get_uint (structure,
+ "angles", n_angles), FALSE);
+
+ return TRUE;
+}
+
+/* Navigation Messages */
+
+#define GST_NAVIGATION_MESSAGE_HAS_TYPE(msg,msg_type) \
+(gst_navigation_message_get_type (msg) == GST_NAVIGATION_MESSAGE_ ## msg_type)
+
+/**
+ * gst_navigation_message_get_type:
+ * @message: A #GstMessage to inspect.
+ *
+ * Check a bus message to see if it is a #GstNavigation event, and return
+ * the #GstNavigationMessageType identifying the type of the message if so.
+ *
+ * Returns: The type of the #GstNavigationMessage, or
+ * #GST_NAVIGATION_MESSAGE_INVALID if the message is not a #GstNavigation
+ * notification.
+ *
+ * Since: 0.10.23
+ */
+GstNavigationMessageType
+gst_navigation_message_get_type (GstMessage * message)
+{
+ const GstStructure *s;
+ const gchar *m_type;
+
+ if (message == NULL || GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
+ return GST_NAVIGATION_MESSAGE_INVALID;
+
+ s = gst_message_get_structure (message);
+ if (s == NULL || !gst_structure_has_name (s, GST_NAVIGATION_MESSAGE_NAME))
+ return GST_NAVIGATION_MESSAGE_INVALID;
+
+ m_type = gst_structure_get_string (s, "type");
+ if (m_type == NULL)
+ return GST_NAVIGATION_MESSAGE_INVALID;
+
+ if (g_str_equal (m_type, "mouse-over"))
+ return GST_NAVIGATION_MESSAGE_MOUSE_OVER;
+ else if (g_str_equal (m_type, "commands-changed"))
+ return GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED;
+ else if (g_str_equal (m_type, "angles-changed"))
+ return GST_NAVIGATION_MESSAGE_ANGLES_CHANGED;
+
+ return GST_NAVIGATION_MESSAGE_INVALID;
+}
+
+/**
+ * gst_navigation_message_new_mouse_over:
+ * @src: A #GstObject to set as source of the new message.
+ * @active: %TRUE if the mouse has entered a clickable area of the display.
+ * %FALSE if it over a non-clickable area.
+ *
+ * Creates a new #GstNavigation message with type
+ * #GST_NAVIGATION_MESSAGE_MOUSE_OVER.
+ *
+ * Returns: The new #GstMessage.
+ * Since: 0.10.23
+ */
+GstMessage *
+gst_navigation_message_new_mouse_over (GstObject * src, gboolean active)
+{
+ GstStructure *s;
+ GstMessage *m;
+
+ s = gst_structure_new (GST_NAVIGATION_MESSAGE_NAME,
+ "type", G_TYPE_STRING, "mouse-over", "active", G_TYPE_BOOLEAN, active,
+ NULL);
+
+ m = gst_message_new_custom (GST_MESSAGE_ELEMENT, src, s);
+
+ return m;
+}
+
+/**
+ * gst_navigation_message_parse_mouse_over:
+ * @message: A #GstMessage to inspect.
+ * @active: A pointer to a gboolean to receive the active/inactive state,
+ * or NULL.
+ *
+ * Parse a #GstNavigation message of type #GST_NAVIGATION_MESSAGE_MOUSE_OVER
+ * and extract the active/inactive flag. If the mouse over event is marked
+ * active, it indicates that the mouse is over a clickable area.
+ *
+ * Returns: %TRUE if the message could be successfully parsed. %FALSE if not.
+ * Since: 0.10.23
+ */
+gboolean
+gst_navigation_message_parse_mouse_over (GstMessage * message,
+ gboolean * active)
+{
+ g_return_val_if_fail (GST_NAVIGATION_MESSAGE_HAS_TYPE (message, MOUSE_OVER),
+ FALSE);
+
+ if (active) {
+ const GstStructure *s = gst_message_get_structure (message);
+ g_return_val_if_fail (gst_structure_get_boolean (s, "active", active),
+ FALSE);
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_navigation_message_new_commands_changed:
+ * @src: A #GstObject to set as source of the new message.
+ *
+ * Creates a new #GstNavigation message with type
+ * #GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED
+ *
+ * Returns: The new #GstMessage.
+ * Since: 0.10.23
+ */
+GstMessage *
+gst_navigation_message_new_commands_changed (GstObject * src)
+{
+ GstStructure *s;
+ GstMessage *m;
+
+ s = gst_structure_new (GST_NAVIGATION_MESSAGE_NAME,
+ "type", G_TYPE_STRING, "commands-changed", NULL);
+
+ m = gst_message_new_custom (GST_MESSAGE_ELEMENT, src, s);
+
+ return m;
+}
+
+/**
+ * gst_navigation_message_new_angles_changed:
+ * @src: A #GstObject to set as source of the new message.
+ * @cur_angle: The currently selected angle.
+ * @n_angles: The number of viewing angles now available.
+ *
+ * Creates a new #GstNavigation message with type
+ * #GST_NAVIGATION_MESSAGE_ANGLES_CHANGED for notifying an application
+ * that the current angle, or current number of angles available in a
+ * multiangle video has changed.
+ *
+ * Returns: The new #GstMessage.
+ * Since: 0.10.23
+ */
+GstMessage *
+gst_navigation_message_new_angles_changed (GstObject * src, guint cur_angle,
+ guint n_angles)
+{
+ GstStructure *s;
+ GstMessage *m;
+
+ s = gst_structure_new (GST_NAVIGATION_MESSAGE_NAME,
+ "type", G_TYPE_STRING, "angles-changed",
+ "angle", G_TYPE_UINT, cur_angle, "angles", G_TYPE_UINT, n_angles, NULL);
+
+ m = gst_message_new_custom (GST_MESSAGE_ELEMENT, src, s);
+
+ return m;
+}
+
+/**
+ * gst_navigation_message_parse_angles_changed:
+ * @message: A #GstMessage to inspect.
+ * @cur_angle: A pointer to a #guint to receive the new current angle number,
+ * or NULL
+ * @n_angles: A pointer to a #guint to receive the new angle count, or NULL.
+ *
+ * Parse a #GstNavigation message of type GST_NAVIGATION_MESSAGE_ANGLES_CHANGED
+ * and extract the @cur_angle and @n_angles parameters.
+ *
+ * Returns: %TRUE if the message could be successfully parsed. %FALSE if not.
+ * Since: 0.10.23
+ */
+gboolean
+gst_navigation_message_parse_angles_changed (GstMessage * message,
+ guint * cur_angle, guint * n_angles)
+{
+ const GstStructure *s;
+
+ g_return_val_if_fail (GST_NAVIGATION_MESSAGE_HAS_TYPE (message,
+ ANGLES_CHANGED), FALSE);
+
+ s = gst_message_get_structure (message);
+ if (cur_angle)
+ g_return_val_if_fail (gst_structure_get_uint (s, "angle", cur_angle),
+ FALSE);
+
+ if (n_angles)
+ g_return_val_if_fail (gst_structure_get_uint (s, "angles", n_angles),
+ FALSE);
+
+ return TRUE;
+}
+
+#define GST_NAVIGATION_EVENT_HAS_TYPE(event,event_type) \
+(gst_navigation_event_get_type (event) == GST_NAVIGATION_EVENT_ ## event_type)
+
+/**
+ * gst_navigation_event_get_type:
+ * @event: A #GstEvent to inspect.
+ *
+ * Inspect a #GstEvent and return the #GstNavigationEventType of the event, or
+ * #GST_NAVIGATION_EVENT_INVALID if the event is not a #GstNavigation event.
+ *
+ * Since: 0.10.23
+ */
+GstNavigationEventType
+gst_navigation_event_get_type (GstEvent * event)
+{
+ const GstStructure *s;
+ const gchar *e_type;
+
+ if (event == NULL || GST_EVENT_TYPE (event) != GST_EVENT_NAVIGATION)
+ return GST_NAVIGATION_EVENT_INVALID;
+
+ s = gst_event_get_structure (event);
+ if (s == NULL || !gst_structure_has_name (s, GST_NAVIGATION_EVENT_NAME))
+ return GST_NAVIGATION_EVENT_INVALID;
+
+ e_type = gst_structure_get_string (s, "event");
+ if (e_type == NULL)
+ return GST_NAVIGATION_EVENT_INVALID;
+
+ if (g_str_equal (e_type, "mouse-button-press"))
+ return GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS;
+ else if (g_str_equal (e_type, "mouse-button-release"))
+ return GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE;
+ else if (g_str_equal (e_type, "mouse-move"))
+ return GST_NAVIGATION_EVENT_MOUSE_MOVE;
+ else if (g_str_equal (e_type, "key-press"))
+ return GST_NAVIGATION_EVENT_KEY_PRESS;
+ else if (g_str_equal (e_type, "key-release"))
+ return GST_NAVIGATION_EVENT_KEY_RELEASE;
+ else if (g_str_equal (e_type, "command"))
+ return GST_NAVIGATION_EVENT_COMMAND;
+
+ return GST_NAVIGATION_EVENT_INVALID;
+}
+
+/**
+ * gst_navigation_event_parse_key_event:
+ * @event: A #GstEvent to inspect.
+ * @key: A pointer to a location to receive the string identifying the key
+ * press. The returned string is owned by the event, and valid only until the
+ * event is unreffed.
+ *
+ * Since: 0.10.23
+ */
+gboolean
+gst_navigation_event_parse_key_event (GstEvent * event, const gchar ** key)
+{
+ GstNavigationEventType e_type;
+ const GstStructure *s;
+
+ e_type = gst_navigation_event_get_type (event);
+ g_return_val_if_fail (e_type == GST_NAVIGATION_EVENT_KEY_PRESS ||
+ e_type == GST_NAVIGATION_EVENT_KEY_RELEASE, FALSE);
+
+ if (key) {
+ s = gst_event_get_structure (event);
+ *key = gst_structure_get_string (s, "key");
+ if (*key == NULL)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_navigation_event_parse_mouse_button_event:
+ * @event: A #GstEvent to inspect.
+ * @button: Pointer to a gint that will receive the button number associated
+ * with the event.
+ * @x: Pointer to a gdouble to receive the x coordinate of the mouse button
+ * event.
+ * @y: Pointer to a gdouble to receive the y coordinate of the mouse button
+ * event.
+ *
+ * Retrieve the details of either a #GstNavigation mouse button press event or
+ * a mouse button release event. Determine which type the event is using
+ * gst_navigation_event_get_type() to retrieve the #GstNavigationEventType.
+ *
+ * Since: 0.10.23
+ */
+gboolean
+gst_navigation_event_parse_mouse_button_event (GstEvent * event, gint * button,
+ gdouble * x, gdouble * y)
+{
+ GstNavigationEventType e_type;
+ const GstStructure *s;
+
+ e_type = gst_navigation_event_get_type (event);
+ g_return_val_if_fail (e_type == GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS ||
+ e_type == GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE, FALSE);
+
+ s = gst_event_get_structure (event);
+ if (x)
+ g_return_val_if_fail (gst_structure_get_double (s, "pointer_x", x), FALSE);
+ if (y)
+ g_return_val_if_fail (gst_structure_get_double (s, "pointer_y", y), FALSE);
+ if (button)
+ g_return_val_if_fail (gst_structure_get_int (s, "button", button), FALSE);
+
+ return TRUE;
+}
+
+/**
+ * gst_navigation_event_parse_mouse_move_event:
+ * @event: A #GstEvent to inspect.
+ * @x: Pointer to a gdouble to receive the x coordinate of the mouse movement.
+ * @y: Pointer to a gdouble to receive the y coordinate of the mouse movement.
+ *
+ * Inspect a #GstNavigation mouse movement event and extract the coordinates
+ * of the event.
+ *
+ * Since: 0.10.23
+ */
+gboolean
+gst_navigation_event_parse_mouse_move_event (GstEvent * event, gdouble * x,
+ gdouble * y)
+{
+ const GstStructure *s;
+
+ g_return_val_if_fail (GST_NAVIGATION_EVENT_HAS_TYPE (event, MOUSE_MOVE),
+ FALSE);
+
+ s = gst_event_get_structure (event);
+ if (x)
+ g_return_val_if_fail (gst_structure_get_double (s, "pointer_x", x), FALSE);
+ if (y)
+ g_return_val_if_fail (gst_structure_get_double (s, "pointer_y", y), FALSE);
+
+ return TRUE;
+}
+
+/**
+ * gst_navigation_event_parse_command:
+ * @event: A #GstEvent to inspect.
+ * @command: Pointer to GstNavigationCommand to receive the type of the
+ * navigation event.
+ *
+ * Inspect a #GstNavigation command event and retrieve the enum value of the
+ * associated command.
+ *
+ * Since: 0.10.23
+ */
+gboolean
+gst_navigation_event_parse_command (GstEvent * event,
+ GstNavigationCommand * command)
+{
+ const GstStructure *s;
+ g_return_val_if_fail (GST_NAVIGATION_EVENT_HAS_TYPE (event, COMMAND), FALSE);
+
+ if (command) {
+ s = gst_event_get_structure (event);
+ g_return_val_if_fail (gst_structure_get_uint (s, "command-code", command),
+ FALSE);
+ }
+
+ return TRUE;
+}
diff --git a/gst-libs/gst/interfaces/navigation.h b/gst-libs/gst/interfaces/navigation.h
index b67130a10c..33bf4629d9 100644
--- a/gst-libs/gst/interfaces/navigation.h
+++ b/gst-libs/gst/interfaces/navigation.h
@@ -49,13 +49,207 @@ typedef struct _GstNavigationInterface {
GType gst_navigation_get_type (void);
-/* virtual class function wrappers */
-void gst_navigation_send_event (GstNavigation *navigation, GstStructure *structure);
+/* Navigation commands */
+/**
+ * GstNavigationCommand:
+ * @GST_NAVIGATION_COMMAND_INVALID: An invalid command entry
+ * @GST_NAVIGATION_COMMAND_MENU1: Execute navigation menu command 1. For DVD,
+ * this enters the DVD root menu, or exits back to the title from the menu.
+ * @GST_NAVIGATION_COMMAND_MENU2: Execute navigation menu command 2. For DVD,
+ * this jumps to the DVD title menu.
+ * @GST_NAVIGATION_COMMAND_MENU3: Execute navigation menu command 3. For DVD,
+ * this jumps into the DVD root menu.
+ * @GST_NAVIGATION_COMMAND_MENU4: Execute navigation menu command 4. For DVD,
+ * this jumps to the Subpicture menu.
+ * @GST_NAVIGATION_COMMAND_MENU5: Execute navigation menu command 5. For DVD,
+ * the jumps to the audio menu.
+ * @GST_NAVIGATION_COMMAND_MENU6: Execute navigation menu command 6. For DVD,
+ * this jumps to the angles menu.
+ * @GST_NAVIGATION_COMMAND_MENU7: Execute navigation menu command 7. For DVD,
+ * this jumps to the chapter menu.
+ * @GST_NAVIGATION_COMMAND_LEFT: Select the next button to the left in a menu,
+ * if such a button exists.
+ * @GST_NAVIGATION_COMMAND_RIGHT: Select the next button to the right in a menu,
+ * if such a button exists.
+ * @GST_NAVIGATION_COMMAND_UP: Select the button above the current one in a
+ * menu, if such a button exists.
+ * @GST_NAVIGATION_COMMAND_DOWN: Select the button below the current one in a
+ * menu, if such a button exists.
+ * @GST_NAVIGATION_COMMAND_ACTIVATE: Activate (click) the currently selected
+ * button in a menu, if such a button exists.
+ * @GST_NAVIGATION_COMMAND_PREV_ANGLE: Switch to the previous angle in a
+ * multiangle feature.
+ * @GST_NAVIGATION_COMMAND_NEXT_ANGLE: Switch to the next angle in a multiangle
+ * feature.
+ *
+ * A set of commands that may be issued to an element providing the
+ * #GstNavigation interface. The available commands can be queried via
+ * the gst_navigation_query_new_commands() query.
+ *
+ * For convenience in handling DVD navigation, the MENU commands are aliased as:
+ * GST_NAVIGATION_COMMAND_DVD_MENU = @GST_NAVIGATION_COMMAND_MENU1
+ * GST_NAVIGATION_COMMAND_DVD_TITLE_MENU = @GST_NAVIGATION_COMMAND_MENU2
+ * GST_NAVIGATION_COMMAND_DVD_ROOT_MENU = @GST_NAVIGATION_COMMAND_MENU3
+ * GST_NAVIGATION_COMMAND_DVD_SUBPICTURE_MENU = @GST_NAVIGATION_COMMAND_MENU4
+ * GST_NAVIGATION_COMMAND_DVD_AUDIO_MENU = @GST_NAVIGATION_COMMAND_MENU5
+ * GST_NAVIGATION_COMMAND_DVD_ANGLE_MENU = @GST_NAVIGATION_COMMAND_MENU6
+ * GST_NAVIGATION_COMMAND_DVD_CHAPTER_MENU = @GST_NAVIGATION_COMMAND_MENU7
+ *
+ * Since: 0.10.23
+ */
+typedef enum {
+ GST_NAVIGATION_COMMAND_INVALID = 0,
+
+ GST_NAVIGATION_COMMAND_MENU1 = 1,
+ GST_NAVIGATION_COMMAND_MENU2 = 2,
+ GST_NAVIGATION_COMMAND_MENU3 = 3,
+ GST_NAVIGATION_COMMAND_MENU4 = 4,
+ GST_NAVIGATION_COMMAND_MENU5 = 5,
+ GST_NAVIGATION_COMMAND_MENU6 = 6,
+ GST_NAVIGATION_COMMAND_MENU7 = 7,
+
+ GST_NAVIGATION_COMMAND_LEFT = 20,
+ GST_NAVIGATION_COMMAND_RIGHT = 21,
+ GST_NAVIGATION_COMMAND_UP = 22,
+ GST_NAVIGATION_COMMAND_DOWN = 23,
+ GST_NAVIGATION_COMMAND_ACTIVATE = 24,
+
+ GST_NAVIGATION_COMMAND_PREV_ANGLE = 30,
+ GST_NAVIGATION_COMMAND_NEXT_ANGLE = 31
+} GstNavigationCommand;
+
+/* Some aliases for the menu command types */
+#define GST_NAVIGATION_COMMAND_DVD_MENU GST_NAVIGATION_COMMAND_MENU1
+#define GST_NAVIGATION_COMMAND_DVD_TITLE_MENU GST_NAVIGATION_COMMAND_MENU2
+#define GST_NAVIGATION_COMMAND_DVD_ROOT_MENU GST_NAVIGATION_COMMAND_MENU3
+#define GST_NAVIGATION_COMMAND_DVD_SUBPICTURE_MENU GST_NAVIGATION_COMMAND_MENU4
+#define GST_NAVIGATION_COMMAND_DVD_AUDIO_MENU GST_NAVIGATION_COMMAND_MENU5
+#define GST_NAVIGATION_COMMAND_DVD_ANGLE_MENU GST_NAVIGATION_COMMAND_MENU6
+#define GST_NAVIGATION_COMMAND_DVD_CHAPTER_MENU GST_NAVIGATION_COMMAND_MENU7
+
+/* Queries */
+typedef enum
+{
+ GST_NAVIGATION_QUERY_INVALID = 0,
+ GST_NAVIGATION_QUERY_COMMANDS = 1,
+ GST_NAVIGATION_QUERY_ANGLES = 2
+} GstNavigationQueryType;
+
+GstNavigationQueryType gst_navigation_query_get_type (GstQuery *query);
+
+GstQuery *gst_navigation_query_new_commands (void);
+void gst_navigation_query_set_commands (GstQuery *query, gint n_cmds, ...);
+void gst_navigation_query_set_commandsv (GstQuery *query, gint n_cmds,
+ GstNavigationCommand *cmds);
+gboolean gst_navigation_query_parse_commands_length (GstQuery *query,
+ guint *n_cmds);
+gboolean gst_navigation_query_parse_commands_nth (GstQuery *query, guint nth,
+ GstNavigationCommand *cmd);
+
+GstQuery *gst_navigation_query_new_angles (void);
+void gst_navigation_query_set_angles (GstQuery *query, guint cur_angle,
+ guint n_angles);
+gboolean gst_navigation_query_parse_angles (GstQuery *query, guint *cur_angle,
+ guint *n_angles);
+
+/* Element messages */
+/**
+ * GstNavigationMessageType:
+ * @GST_NAVIGATION_MESSAGE_INVALID: Returned from
+ * gst_navigation_message_get_type() when the passed message is not a
+ * navigation message.
+ * @GST_NAVIGATION_MESSAGE_MOUSE_OVER: Sent when the mouse moves over or leaves a
+ * clickable region of the output, such as a DVD menu button.
+ * @GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED: Sent when the set of available commands
+ * changes and should re-queried by interested applications.
+ * @GST_NAVIGATION_MESSAGE_ANGLES_CHANGED: Sent when display angles in a multi-angle
+ * feature (such as a multiangle DVD) change - either angles have appeared or
+ * disappeared.
+ *
+ * A set of notifications that may be received on the bus when navigation
+ * related status changes.
+ *
+ * Since: 0.10.23
+ */
+typedef enum {
+ GST_NAVIGATION_MESSAGE_INVALID,
+ GST_NAVIGATION_MESSAGE_MOUSE_OVER,
+ GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED,
+ GST_NAVIGATION_MESSAGE_ANGLES_CHANGED
+} GstNavigationMessageType;
+
+GstNavigationMessageType gst_navigation_message_get_type (GstMessage *message);
+
+GstMessage *gst_navigation_message_new_mouse_over (GstObject *src,
+ gboolean active);
+gboolean gst_navigation_message_parse_mouse_over (GstMessage *message,
+ gboolean *active);
+
+GstMessage *gst_navigation_message_new_commands_changed (GstObject *src);
+
+GstMessage *gst_navigation_message_new_angles_changed (GstObject *src,
+ guint cur_angle,
+ guint n_angles);
+gboolean gst_navigation_message_parse_angles_changed (GstMessage *message,
+ guint *cur_angle,
+ guint *n_angles);
+
+/* event parsing functions */
+/**
+ * GstNavigationEventType:
+ * @GST_NAVIGATION_EVENT_INVALID: Returned from
+ * gst_navigation_event_get_type() when the passed event is not a navigation event.
+ * @GST_NAVIGATION_EVENT_KEY_PRESS: A key press event. Use
+ * gst_navigation_event_parse_key_event() to extract the details from the event.
+ * @GST_NAVIGATION_EVENT_KEY_RELEASE: A key release event. Use
+ * gst_navigation_event_parse_key_event() to extract the details from the event.
+ * @GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS: A mouse button press event. Use
+ * gst_navigation_event_parse_mouse_button_event() to extract the details from the
+ * event.
+ * @GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE: A mouse button release event. Use
+ * gst_navigation_event_parse_mouse_button_event() to extract the details from the
+ * event.
+ * @GST_NAVIGATION_EVENT_MOUSE_MOVE: A mouse movement event. Use
+ * gst_navigation_event_parse_mouse_move_event() to extract the details from the
+ * event.
+ * @GST_NAVIGATION_EVENT_COMMAND: A navigation command event. Use
+ * gst_navigation_event_parse_command() to extract the details from the event.
+ *
+ * Enum values for the various events that an element implementing the
+ * GstNavigation interface might send up the pipeline.
+ *
+ * Since: 0.10.23
+ */
+typedef enum {
+ GST_NAVIGATION_EVENT_INVALID = 0,
+ GST_NAVIGATION_EVENT_KEY_PRESS = 1,
+ GST_NAVIGATION_EVENT_KEY_RELEASE = 2,
+ GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS = 3,
+ GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE = 4,
+ GST_NAVIGATION_EVENT_MOUSE_MOVE = 5,
+ GST_NAVIGATION_EVENT_COMMAND = 6
+} GstNavigationEventType;
+
+GstNavigationEventType gst_navigation_event_get_type (GstEvent *event);
+gboolean gst_navigation_event_parse_key_event (GstEvent *event,
+ const gchar **key);
+gboolean gst_navigation_event_parse_mouse_button_event (GstEvent *event,
+ gint *button, gdouble *x, gdouble *y);
+gboolean gst_navigation_event_parse_mouse_move_event (GstEvent *event,
+ gdouble *x, gdouble *y);
+gboolean gst_navigation_event_parse_command (GstEvent *event,
+ GstNavigationCommand *command);
+
+/* interface virtual function wrappers */
+void gst_navigation_send_event (GstNavigation *navigation,
+ GstStructure *structure);
void gst_navigation_send_key_event (GstNavigation *navigation,
const char *event, const char *key);
void gst_navigation_send_mouse_event (GstNavigation *navigation,
const char *event, int button, double x, double y);
+void gst_navigation_send_command (GstNavigation *navigation,
+ GstNavigationCommand command);
G_END_DECLS
diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am
index 60e8f6a350..f6d1b24179 100644
--- a/tests/check/Makefile.am
+++ b/tests/check/Makefile.am
@@ -112,6 +112,7 @@ check_PROGRAMS = \
libs/cddabasesrc \
libs/fft \
libs/mixer \
+ libs/navigation \
libs/netbuffer \
libs/pbutils \
libs/rtp \
@@ -181,6 +182,16 @@ libs_mixer_LDADD = \
$(GST_BASE_LIBS) \
$(LDADD)
+libs_navigation_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(AM_CFLAGS)
+
+libs_navigation_LDADD = \
+ $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-@GST_MAJORMINOR@.la \
+ $(GST_BASE_LIBS) \
+ $(LDADD)
+
libs_netbuffer_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) \
$(AM_CFLAGS)
diff --git a/tests/check/libs/.gitignore b/tests/check/libs/.gitignore
index d57728a1ec..cd372588c4 100644
--- a/tests/check/libs/.gitignore
+++ b/tests/check/libs/.gitignore
@@ -3,6 +3,7 @@ audio
cddabasesrc
fft
mixer
+navigation
netbuffer
pbutils
rtp
diff --git a/tests/check/libs/navigation.c b/tests/check/libs/navigation.c
new file mode 100644
index 0000000000..4712947b80
--- /dev/null
+++ b/tests/check/libs/navigation.c
@@ -0,0 +1,351 @@
+/* GStreamer
+ *
+ * unit tests for the navigation interface library
+ *
+ * Copyright (C) 2009 Jan Schmidt
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+
+#include
+
+#include
+
+#define TEST_ELEMENT_TYPE (test_element_get_type())
+
+typedef struct TestElement TestElement;
+typedef struct TestElementClass TestElementClass;
+
+struct TestElement
+{
+ GstElement parent;
+
+ GstNavigationEventType sent_type;
+ const gchar *sent_key;
+ gdouble sent_x, sent_y;
+ gint sent_button;
+ GstNavigationCommand sent_command;
+};
+
+struct TestElementClass
+{
+ GstElementClass parent_class;
+};
+
+static void init_interface (GType type);
+static void gst_implements_interface_init (GstImplementsInterfaceClass * klass);
+static void nav_send_event (GstNavigation * navigation,
+ GstStructure * structure);
+
+GST_BOILERPLATE_FULL (TestElement, test_element, GstElement, GST_TYPE_ELEMENT,
+ init_interface);
+
+static void
+test_element_navigation_interface_init (GstNavigationInterface * klass)
+{
+ klass->send_event = nav_send_event;
+}
+
+static void
+init_interface (GType type)
+{
+ static const GInterfaceInfo navigation_iface_info = {
+ (GInterfaceInitFunc) test_element_navigation_interface_init,
+ NULL,
+ NULL,
+ };
+ static const GInterfaceInfo implements_iface_info = {
+ (GInterfaceInitFunc) gst_implements_interface_init,
+ NULL,
+ NULL,
+ };
+
+ g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
+ &implements_iface_info);
+ g_type_add_interface_static (type, GST_TYPE_NAVIGATION,
+ &navigation_iface_info);
+}
+
+static void
+test_element_base_init (gpointer klass)
+{
+}
+
+static void
+test_element_class_init (TestElementClass * klass)
+{
+}
+
+static gboolean
+test_element_interface_supported (GstImplementsInterface * ifacE,
+ GType interface_type)
+{
+ if (interface_type == GST_TYPE_NAVIGATION)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+gst_implements_interface_init (GstImplementsInterfaceClass * klass)
+{
+ klass->supported = test_element_interface_supported;
+}
+
+static void
+test_element_init (TestElement * this, TestElementClass * klass)
+{
+}
+
+static void
+nav_send_event (GstNavigation * navigation, GstStructure * structure)
+{
+ GstEvent *event = gst_event_new_navigation (structure);
+ GstNavigationEventType etype = gst_navigation_event_get_type (event);
+ TestElement *self = (TestElement *) (navigation);
+
+ fail_if (etype == GST_NAVIGATION_EVENT_INVALID,
+ "Received navigation event could not be parsed");
+ fail_unless (etype == self->sent_type,
+ "Received navigation event did not match sent");
+
+ switch (etype) {
+ case GST_NAVIGATION_EVENT_KEY_PRESS:
+ case GST_NAVIGATION_EVENT_KEY_RELEASE:{
+ const gchar *key;
+ fail_unless (gst_navigation_event_parse_key_event (event, &key));
+ fail_unless (strcmp (key, self->sent_key) == 0);
+ break;
+ }
+ case GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS:
+ case GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE:{
+ gint button;
+ gdouble x, y;
+ fail_unless (gst_navigation_event_parse_mouse_button_event (event,
+ &button, &x, &y));
+ fail_unless (button == self->sent_button);
+ fail_unless (x == self->sent_x);
+ fail_unless (y == self->sent_y);
+ break;
+ }
+ case GST_NAVIGATION_EVENT_MOUSE_MOVE:{
+ gdouble x, y;
+ fail_unless (gst_navigation_event_parse_mouse_move_event (event, &x, &y));
+ fail_unless (x == self->sent_x);
+ fail_unless (y == self->sent_y);
+ break;
+ }
+ case GST_NAVIGATION_EVENT_COMMAND:{
+ GstNavigationCommand cmd;
+ fail_unless (gst_navigation_event_parse_command (event, &cmd));
+ fail_unless (cmd == self->sent_command);
+ }
+ default:
+ break;
+ }
+
+ gst_event_unref (event);
+}
+
+GST_START_TEST (test_events)
+{
+ /* Create an empty GstElement that has a GstNavigation interface and then
+ * send some navigation events and validate them */
+ TestElement *test_element =
+ (TestElement *) g_object_new (TEST_ELEMENT_TYPE, NULL);
+ GstNavigationCommand cmds[] = {
+ GST_NAVIGATION_COMMAND_MENU1, GST_NAVIGATION_COMMAND_MENU2,
+ GST_NAVIGATION_COMMAND_MENU3, GST_NAVIGATION_COMMAND_MENU4,
+ GST_NAVIGATION_COMMAND_MENU5, GST_NAVIGATION_COMMAND_MENU6,
+ GST_NAVIGATION_COMMAND_MENU7, GST_NAVIGATION_COMMAND_LEFT,
+ GST_NAVIGATION_COMMAND_RIGHT, GST_NAVIGATION_COMMAND_UP,
+ GST_NAVIGATION_COMMAND_DOWN, GST_NAVIGATION_COMMAND_ACTIVATE,
+ GST_NAVIGATION_COMMAND_PREV_ANGLE, GST_NAVIGATION_COMMAND_NEXT_ANGLE
+ };
+ gint i;
+
+ test_element->sent_type = GST_NAVIGATION_EVENT_KEY_PRESS;
+ test_element->sent_key = "1";
+ gst_navigation_send_key_event (GST_NAVIGATION (test_element), "key-press",
+ "1");
+
+ test_element->sent_type = GST_NAVIGATION_EVENT_KEY_RELEASE;
+ test_element->sent_key = "2";
+ gst_navigation_send_key_event (GST_NAVIGATION (test_element), "key-release",
+ "2");
+
+ test_element->sent_type = GST_NAVIGATION_EVENT_MOUSE_MOVE;
+ test_element->sent_x = 50;
+ test_element->sent_y = 100;
+ gst_navigation_send_mouse_event (GST_NAVIGATION (test_element), "mouse-move",
+ 0, 50, 100);
+
+ test_element->sent_type = GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS;
+ test_element->sent_x = 10;
+ test_element->sent_y = 20;
+ test_element->sent_button = 1;
+ gst_navigation_send_mouse_event (GST_NAVIGATION (test_element),
+ "mouse-button-press", 1, 10, 20);
+
+ for (i = 0; i < G_N_ELEMENTS (cmds); i++) {
+ test_element->sent_type = GST_NAVIGATION_EVENT_COMMAND;
+ test_element->sent_command = cmds[i];
+ gst_navigation_send_command (GST_NAVIGATION (test_element), cmds[i]);
+ }
+
+ gst_object_unref (test_element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_messages)
+{
+ GstMessage *m;
+ /* GST_NAVIGATION_MESSAGE_MOUSE_OVER */
+ {
+ gboolean active;
+ m = gst_navigation_message_new_mouse_over (NULL, TRUE);
+ fail_if (m == NULL);
+ fail_unless (gst_navigation_message_get_type (m) ==
+ GST_NAVIGATION_MESSAGE_MOUSE_OVER);
+ fail_unless (GST_MESSAGE_SRC (m) == NULL);
+ fail_unless (gst_navigation_message_parse_mouse_over (m, &active));
+ fail_unless (active == TRUE);
+ gst_message_unref (m);
+
+ m = gst_navigation_message_new_mouse_over (NULL, FALSE);
+ fail_if (m == NULL);
+ fail_unless (GST_MESSAGE_SRC (m) == NULL);
+ fail_unless (gst_navigation_message_get_type (m) ==
+ GST_NAVIGATION_MESSAGE_MOUSE_OVER);
+ fail_unless (gst_navigation_message_parse_mouse_over (m, &active));
+ fail_unless (active == FALSE);
+ gst_message_unref (m);
+ }
+
+ /* GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED */
+ {
+ m = gst_navigation_message_new_commands_changed (NULL);
+ fail_if (m == NULL);
+ fail_unless (GST_MESSAGE_SRC (m) == NULL);
+ fail_unless (gst_navigation_message_get_type (m) ==
+ GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED);
+ gst_message_unref (m);
+ }
+
+ /* GST_NAVIGATION_MESSAGE_ANGLES_CHANGED */
+ {
+ guint angle, angles;
+ m = gst_navigation_message_new_angles_changed (NULL, 1, 5);
+ fail_if (m == NULL);
+ fail_unless (GST_MESSAGE_SRC (m) == NULL);
+ fail_unless (gst_navigation_message_get_type (m) ==
+ GST_NAVIGATION_MESSAGE_ANGLES_CHANGED);
+ fail_unless (gst_navigation_message_parse_angles_changed (m, &angle,
+ &angles));
+ fail_unless (angle == 1);
+ fail_unless (angles == 5);
+ gst_message_unref (m);
+ }
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_queries)
+{
+ GstQuery *q;
+
+ /* GST_NAVIGATION_QUERY_COMMANDS */
+ {
+ guint n;
+ GstNavigationCommand cmd;
+
+ q = gst_navigation_query_new_commands ();
+ fail_unless (q != NULL);
+ fail_unless (gst_navigation_query_get_type (q) ==
+ GST_NAVIGATION_QUERY_COMMANDS);
+ gst_navigation_query_set_commands (q, 3, GST_NAVIGATION_COMMAND_LEFT,
+ GST_NAVIGATION_COMMAND_MENU1, GST_NAVIGATION_COMMAND_MENU5);
+ fail_unless (gst_navigation_query_parse_commands_length (q, &n));
+ fail_unless (n == 3);
+ fail_unless (gst_navigation_query_parse_commands_nth (q, 1, &cmd));
+ fail_unless (cmd == GST_NAVIGATION_COMMAND_MENU1);
+
+ fail_unless (gst_navigation_query_parse_commands_length (q, NULL));
+ fail_unless (gst_navigation_query_parse_commands_nth (q, 2, NULL));
+
+ gst_query_unref (q);
+ }
+
+ /* GST_NAVIGATION_QUERY_ANGLES */
+ {
+ guint angle, angles;
+ q = gst_navigation_query_new_angles ();
+ fail_unless (q != NULL);
+ fail_unless (gst_navigation_query_get_type (q) ==
+ GST_NAVIGATION_QUERY_ANGLES);
+ gst_navigation_query_set_angles (q, 4, 8);
+ fail_unless (gst_navigation_query_parse_angles (q, &angle, &angles));
+ fail_unless (angle == 4);
+ fail_unless (angles == 8);
+
+ fail_unless (gst_navigation_query_parse_angles (q, NULL, &angles));
+ fail_unless (gst_navigation_query_parse_angles (q, &angle, NULL));
+ fail_unless (gst_navigation_query_parse_angles (q, NULL, NULL));
+
+ gst_query_unref (q);
+ }
+
+}
+
+GST_END_TEST;
+
+static Suite *
+navigation_suite (void)
+{
+ Suite *s = suite_create ("navigation interface");
+ TCase *tc_chain = tcase_create ("notifications");
+
+ suite_add_tcase (s, tc_chain);
+ tcase_add_test (tc_chain, test_events);
+ tcase_add_test (tc_chain, test_messages);
+ tcase_add_test (tc_chain, test_queries);
+
+ return s;
+}
+
+int
+main (int argc, char **argv)
+{
+ int nf;
+
+ Suite *s = navigation_suite ();
+ SRunner *sr = srunner_create (s);
+
+ gst_check_init (&argc, &argv);
+
+ srunner_run_all (sr, CK_NORMAL);
+ nf = srunner_ntests_failed (sr);
+ srunner_free (sr);
+
+ return nf;
+}
diff --git a/win32/common/libgstinterfaces.def b/win32/common/libgstinterfaces.def
index a034b97610..1e7009d9b5 100644
--- a/win32/common/libgstinterfaces.def
+++ b/win32/common/libgstinterfaces.def
@@ -34,7 +34,32 @@ EXPORTS
gst_mixer_track_get_type
gst_mixer_type_get_type
gst_mixer_volume_changed
+ gst_navigation_command_get_type
+ gst_navigation_event_get_type
+ gst_navigation_event_parse_command
+ gst_navigation_event_parse_key_event
+ gst_navigation_event_parse_mouse_button_event
+ gst_navigation_event_parse_mouse_move_event
+ gst_navigation_event_type_get_type
gst_navigation_get_type
+ gst_navigation_message_get_type
+ gst_navigation_message_new_angles_changed
+ gst_navigation_message_new_commands_changed
+ gst_navigation_message_new_mouse_over
+ gst_navigation_message_parse_angles_changed
+ gst_navigation_message_parse_mouse_over
+ gst_navigation_message_type_get_type
+ gst_navigation_query_get_type
+ gst_navigation_query_new_angles
+ gst_navigation_query_new_commands
+ gst_navigation_query_parse_angles
+ gst_navigation_query_parse_commands_length
+ gst_navigation_query_parse_commands_nth
+ gst_navigation_query_set_angles
+ gst_navigation_query_set_commands
+ gst_navigation_query_set_commandsv
+ gst_navigation_query_type_get_type
+ gst_navigation_send_command
gst_navigation_send_event
gst_navigation_send_key_event
gst_navigation_send_mouse_event