1 /* GStreamer
2  *
3  * Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 /**
22  * SECTION:gstplayer-gmaincontextsignaldispatcher
23  * @title: GstPlayerGMainContextSignalDispatcher
24  * @short_description: Player GLib MainContext dispatcher
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include "gstplayer-g-main-context-signal-dispatcher.h"
33 
34 struct _GstPlayerGMainContextSignalDispatcher
35 {
36   GObject parent;
37   GMainContext *application_context;
38 };
39 
40 struct _GstPlayerGMainContextSignalDispatcherClass
41 {
42   GObjectClass parent_class;
43 };
44 
45 static void
46     gst_player_g_main_context_signal_dispatcher_interface_init
47     (GstPlayerSignalDispatcherInterface * iface);
48 
49 enum
50 {
51   G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_0,
52   G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT,
53   G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST
54 };
55 
56 G_DEFINE_TYPE_WITH_CODE (GstPlayerGMainContextSignalDispatcher,
57     gst_player_g_main_context_signal_dispatcher, G_TYPE_OBJECT,
58     G_IMPLEMENT_INTERFACE (GST_TYPE_PLAYER_SIGNAL_DISPATCHER,
59         gst_player_g_main_context_signal_dispatcher_interface_init));
60 
61 static GParamSpec
62     * g_main_context_signal_dispatcher_param_specs
63     [G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST] = { NULL, };
64 
65 static void
gst_player_g_main_context_signal_dispatcher_finalize(GObject * object)66 gst_player_g_main_context_signal_dispatcher_finalize (GObject * object)
67 {
68   GstPlayerGMainContextSignalDispatcher *self =
69       GST_PLAYER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
70 
71   if (self->application_context)
72     g_main_context_unref (self->application_context);
73 
74   G_OBJECT_CLASS
75       (gst_player_g_main_context_signal_dispatcher_parent_class)->finalize
76       (object);
77 }
78 
79 static void
gst_player_g_main_context_signal_dispatcher_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)80 gst_player_g_main_context_signal_dispatcher_set_property (GObject * object,
81     guint prop_id, const GValue * value, GParamSpec * pspec)
82 {
83   GstPlayerGMainContextSignalDispatcher *self =
84       GST_PLAYER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
85 
86   switch (prop_id) {
87     case G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT:
88       self->application_context = g_value_dup_boxed (value);
89       if (!self->application_context)
90         self->application_context = g_main_context_ref_thread_default ();
91       break;
92     default:
93       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
94       break;
95   }
96 }
97 
98 static void
gst_player_g_main_context_signal_dispatcher_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)99 gst_player_g_main_context_signal_dispatcher_get_property (GObject * object,
100     guint prop_id, GValue * value, GParamSpec * pspec)
101 {
102   GstPlayerGMainContextSignalDispatcher *self =
103       GST_PLAYER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
104 
105   switch (prop_id) {
106     case G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT:
107       g_value_set_boxed (value, self->application_context);
108       break;
109     default:
110       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
111       break;
112   }
113 }
114 
115 static void
gst_player_g_main_context_signal_dispatcher_class_init(GstPlayerGMainContextSignalDispatcherClass * klass)116     gst_player_g_main_context_signal_dispatcher_class_init
117     (GstPlayerGMainContextSignalDispatcherClass * klass)
118 {
119   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
120 
121   gobject_class->finalize =
122       gst_player_g_main_context_signal_dispatcher_finalize;
123   gobject_class->set_property =
124       gst_player_g_main_context_signal_dispatcher_set_property;
125   gobject_class->get_property =
126       gst_player_g_main_context_signal_dispatcher_get_property;
127 
128   g_main_context_signal_dispatcher_param_specs
129       [G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT] =
130       g_param_spec_boxed ("application-context", "Application Context",
131       "Application GMainContext to dispatch signals to", G_TYPE_MAIN_CONTEXT,
132       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
133 
134   g_object_class_install_properties (gobject_class,
135       G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST,
136       g_main_context_signal_dispatcher_param_specs);
137 }
138 
139 static void
gst_player_g_main_context_signal_dispatcher_init(G_GNUC_UNUSED GstPlayerGMainContextSignalDispatcher * self)140     gst_player_g_main_context_signal_dispatcher_init
141     (G_GNUC_UNUSED GstPlayerGMainContextSignalDispatcher * self)
142 {
143 }
144 
145 typedef struct
146 {
147   void (*emitter) (gpointer data);
148   gpointer data;
149   GDestroyNotify destroy;
150 } GMainContextSignalDispatcherData;
151 
152 static gboolean
g_main_context_signal_dispatcher_dispatch_gsourcefunc(gpointer user_data)153 g_main_context_signal_dispatcher_dispatch_gsourcefunc (gpointer user_data)
154 {
155   GMainContextSignalDispatcherData *data = user_data;
156 
157   data->emitter (data->data);
158 
159   return G_SOURCE_REMOVE;
160 }
161 
162 static void
g_main_context_signal_dispatcher_dispatch_destroy(gpointer user_data)163 g_main_context_signal_dispatcher_dispatch_destroy (gpointer user_data)
164 {
165   GMainContextSignalDispatcherData *data = user_data;
166 
167   if (data->destroy)
168     data->destroy (data->data);
169   g_free (data);
170 }
171 
172 static void
gst_player_g_main_context_signal_dispatcher_dispatch(GstPlayerSignalDispatcher * iface,G_GNUC_UNUSED GstPlayer * player,void (* emitter)(gpointer data),gpointer data,GDestroyNotify destroy)173 gst_player_g_main_context_signal_dispatcher_dispatch (GstPlayerSignalDispatcher
174     * iface, G_GNUC_UNUSED GstPlayer * player, void (*emitter) (gpointer data),
175     gpointer data, GDestroyNotify destroy)
176 {
177   GstPlayerGMainContextSignalDispatcher *self =
178       GST_PLAYER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (iface);
179   GMainContextSignalDispatcherData *gsourcefunc_data =
180       g_new (GMainContextSignalDispatcherData, 1);
181 
182   gsourcefunc_data->emitter = emitter;
183   gsourcefunc_data->data = data;
184   gsourcefunc_data->destroy = destroy;
185 
186   g_main_context_invoke_full (self->application_context,
187       G_PRIORITY_DEFAULT, g_main_context_signal_dispatcher_dispatch_gsourcefunc,
188       gsourcefunc_data, g_main_context_signal_dispatcher_dispatch_destroy);
189 }
190 
191 static void
gst_player_g_main_context_signal_dispatcher_interface_init(GstPlayerSignalDispatcherInterface * iface)192     gst_player_g_main_context_signal_dispatcher_interface_init
193     (GstPlayerSignalDispatcherInterface * iface)
194 {
195   iface->dispatch = gst_player_g_main_context_signal_dispatcher_dispatch;
196 }
197 
198 /**
199  * gst_player_g_main_context_signal_dispatcher_new:
200  * @application_context: (allow-none): GMainContext to use or %NULL
201  *
202  * Creates a new GstPlayerSignalDispatcher that uses @application_context,
203  * or the thread default one if %NULL is used. See gst_player_new_full().
204  *
205  * Returns: (transfer full): the new GstPlayerSignalDispatcher
206  */
207 GstPlayerSignalDispatcher *
gst_player_g_main_context_signal_dispatcher_new(GMainContext * application_context)208 gst_player_g_main_context_signal_dispatcher_new (GMainContext *
209     application_context)
210 {
211   return g_object_new (GST_TYPE_PLAYER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER,
212       "application-context", application_context, NULL);
213 }
214