diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index d53d77c584..d0744a0c9e 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -56,6 +56,9 @@ static gboolean gst_gtk_base_sink_set_caps (GstBaseSink * bsink, static GstFlowReturn gst_gtk_base_sink_show_frame (GstVideoSink * bsink, GstBuffer * buf); +static void +gst_gtk_base_sink_navigation_interface_init (GstNavigationInterface * iface); + enum { PROP_0, @@ -67,7 +70,10 @@ enum #define gst_gtk_base_sink_parent_class parent_class G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstGtkBaseSink, gst_gtk_base_sink, - GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_sink, + GST_TYPE_VIDEO_SINK, + G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION, + gst_gtk_base_sink_navigation_interface_init); + GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_sink, "gtkbasesink", 0, "Gtk Video Sink base class")); static void @@ -179,6 +185,10 @@ gst_gtk_base_sink_get_widget (GstGtkBaseSink * gtk_sink) g_signal_connect (gtk_sink->widget, "destroy", G_CALLBACK (widget_destroy_cb), gtk_sink); + /* back pointer */ + gtk_gst_base_widget_set_element (GTK_GST_BASE_WIDGET (gtk_sink->widget), + GST_ELEMENT (gtk_sink)); + return gtk_sink->widget; } @@ -230,6 +240,31 @@ gst_gtk_base_sink_set_property (GObject * object, guint prop_id, } } +static void +gst_gtk_base_sink_navigation_send_event (GstNavigation * navigation, + GstStructure * structure) +{ + GstGtkBaseSink *sink = GST_GTK_BASE_SINK (navigation); + GstEvent *event; + GstPad *pad; + + event = gst_event_new_navigation (structure); + pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink)); + + GST_TRACE_OBJECT (sink, "navigation event %" GST_PTR_FORMAT, structure); + + if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) + gst_pad_send_event (pad, event); + + gst_object_unref (pad); +} + +static void +gst_gtk_base_sink_navigation_interface_init (GstNavigationInterface * iface) +{ + iface->send_event = gst_gtk_base_sink_navigation_send_event; +} + static gboolean gst_gtk_base_sink_start (GstBaseSink * bsink) { diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c index 0cfed24b17..4870fa4130 100644 --- a/ext/gtk/gtkgstbasewidget.c +++ b/ext/gtk/gtkgstbasewidget.c @@ -219,6 +219,85 @@ _queue_draw (GtkGstBaseWidget * widget) return G_SOURCE_REMOVE; } +static const gchar * +_gdk_key_to_navigation_string (guint keyval) +{ + /* TODO: expand */ + switch (keyval) { +#define KEY(key) case GDK_KEY_ ## key: return G_STRINGIFY(key) + KEY (Up); + KEY (Down); + KEY (Left); + KEY (Right); + KEY (Home); + KEY (End); +#undef KEY + default: + return NULL; + } +} + +static gboolean +gtk_gst_base_widget_key_event (GtkWidget * widget, GdkEventKey * event) +{ + GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); + GstElement *element; + + if ((element = g_weak_ref_get (&base_widget->element))) { + if (GST_IS_NAVIGATION (element)) { + const gchar *str = _gdk_key_to_navigation_string (event->keyval); + const gchar *key_type = + event->type == GDK_KEY_PRESS ? "key-press" : "key-release"; + + if (!str) + str = event->string; + + gst_navigation_send_key_event (GST_NAVIGATION (element), key_type, str); + } + g_object_unref (element); + } + + return TRUE; +} + +static gboolean +gtk_gst_base_widget_button_event (GtkWidget * widget, GdkEventButton * event) +{ + GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); + GstElement *element; + + if ((element = g_weak_ref_get (&base_widget->element))) { + if (GST_IS_NAVIGATION (element)) { + const gchar *key_type = + event->type == + GDK_BUTTON_PRESS ? "mouse-button-press" : "mouse-button-release"; + + gst_navigation_send_mouse_event (GST_NAVIGATION (element), key_type, + event->button, event->x, event->y); + } + g_object_unref (element); + } + + return TRUE; +} + +static gboolean +gtk_gst_base_widget_motion_event (GtkWidget * widget, GdkEventMotion * event) +{ + GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); + GstElement *element; + + if ((element = g_weak_ref_get (&base_widget->element))) { + if (GST_IS_NAVIGATION (element)) { + gst_navigation_send_mouse_event (GST_NAVIGATION (element), "motion-move", + 0, event->x, event->y); + } + g_object_unref (element); + } + + return TRUE; +} + void gtk_gst_base_widget_class_init (GtkGstBaseWidgetClass * klass) { @@ -247,11 +326,18 @@ gtk_gst_base_widget_class_init (GtkGstBaseWidgetClass * klass) widget_klass->get_preferred_width = gtk_gst_base_widget_get_preferred_width; widget_klass->get_preferred_height = gtk_gst_base_widget_get_preferred_height; + widget_klass->key_press_event = gtk_gst_base_widget_key_event; + widget_klass->key_release_event = gtk_gst_base_widget_key_event; + widget_klass->button_press_event = gtk_gst_base_widget_button_event; + widget_klass->button_release_event = gtk_gst_base_widget_button_event; + widget_klass->motion_notify_event = gtk_gst_base_widget_motion_event; } void gtk_gst_base_widget_init (GtkGstBaseWidget * widget) { + int event_mask; + widget->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; widget->par_n = DEFAULT_PAR_N; widget->par_d = DEFAULT_PAR_D; @@ -260,7 +346,17 @@ gtk_gst_base_widget_init (GtkGstBaseWidget * widget) gst_video_info_init (&widget->v_info); gst_video_info_init (&widget->pending_v_info); + g_weak_ref_init (&widget->element, NULL); g_mutex_init (&widget->lock); + + gtk_widget_set_can_focus (GTK_WIDGET (widget), TRUE); + event_mask = gtk_widget_get_events (GTK_WIDGET (widget)); + event_mask |= GDK_KEY_PRESS_MASK + | GDK_KEY_RELEASE_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK; + gtk_widget_set_events (GTK_WIDGET (widget), event_mask); } void @@ -270,11 +366,19 @@ gtk_gst_base_widget_finalize (GObject * object) gst_buffer_replace (&widget->buffer, NULL); g_mutex_clear (&widget->lock); + g_weak_ref_clear (&widget->element); if (widget->draw_id) g_source_remove (widget->draw_id); } +void +gtk_gst_base_widget_set_element (GtkGstBaseWidget * widget, + GstElement * element) +{ + g_weak_ref_set (&widget->element, element); +} + gboolean gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, GstVideoInfo * v_info) diff --git a/ext/gtk/gtkgstbasewidget.h b/ext/gtk/gtkgstbasewidget.h index 568027d781..a402385625 100644 --- a/ext/gtk/gtkgstbasewidget.h +++ b/ext/gtk/gtkgstbasewidget.h @@ -68,6 +68,7 @@ struct _GtkGstBaseWidget /*< private >*/ GMutex lock; + GWeakRef element; /* Pending draw idles callback */ guint draw_id; @@ -92,6 +93,7 @@ void gtk_gst_base_widget_finalize (GObject * object); /* API */ gboolean gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, GstVideoInfo * v_info); void gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer * buffer); +void gtk_gst_base_widget_set_element (GtkGstBaseWidget * widget, GstElement * element); G_END_DECLS