mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-28 20:05:38 +00:00
gtk: implement GstNavigation interface
Now we can push key/mouse input into the pipeline for DVD use cases.
This commit is contained in:
parent
711589ebde
commit
988643eb43
3 changed files with 142 additions and 1 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue