1 /*
2  * e-source-extension.c
3  *
4  * This library is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library. If not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17 
18 /**
19  * SECTION: e-source-extension
20  * @include: libedataserver/libedataserver.h
21  * @short_description: Base class for #ESource extensions
22  *
23  * #ESourceExtension is an abstract base class for #ESource extension
24  * objects.  An #ESourceExtension object basically just maps the keys in
25  * a key file group to a set of #GObject properties.  The name of the key
26  * file group doubles as the name of the #ESourceExtension object.
27  *
28  * #ESourceExtension objects are accessed through e_source_get_extension().
29  **/
30 
31 #include "e-source-extension.h"
32 
33 struct _ESourceExtensionPrivate {
34 	GWeakRef source;
35 	GRecMutex property_lock;
36 };
37 
38 enum {
39 	PROP_0,
40 	PROP_SOURCE
41 };
42 
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(ESourceExtension,e_source_extension,G_TYPE_OBJECT)43 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (
44 	ESourceExtension,
45 	e_source_extension,
46 	G_TYPE_OBJECT)
47 
48 static void
49 source_extension_set_source (ESourceExtension *extension,
50                              ESource *source)
51 {
52 	g_return_if_fail (E_IS_SOURCE (source));
53 
54 	g_weak_ref_set (&extension->priv->source, source);
55 }
56 
57 static void
source_extension_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)58 source_extension_set_property (GObject *object,
59                                guint property_id,
60                                const GValue *value,
61                                GParamSpec *pspec)
62 {
63 	switch (property_id) {
64 		case PROP_SOURCE:
65 			source_extension_set_source (
66 				E_SOURCE_EXTENSION (object),
67 				g_value_get_object (value));
68 			return;
69 	}
70 
71 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
72 }
73 
74 static void
source_extension_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)75 source_extension_get_property (GObject *object,
76                                guint property_id,
77                                GValue *value,
78                                GParamSpec *pspec)
79 {
80 	switch (property_id) {
81 		case PROP_SOURCE:
82 			g_value_take_object (
83 				value, e_source_extension_ref_source (
84 				E_SOURCE_EXTENSION (object)));
85 			return;
86 	}
87 
88 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
89 }
90 
91 static void
source_extension_dispose(GObject * object)92 source_extension_dispose (GObject *object)
93 {
94 	ESourceExtensionPrivate *priv;
95 
96 	priv = E_SOURCE_EXTENSION (object)->priv;
97 
98 	g_weak_ref_set (&priv->source, NULL);
99 
100 	/* Chain up to parent's dispose() method. */
101 	G_OBJECT_CLASS (e_source_extension_parent_class)->dispose (object);
102 }
103 
104 static void
source_extension_finalize(GObject * object)105 source_extension_finalize (GObject *object)
106 {
107 	ESourceExtensionPrivate *priv;
108 
109 	priv = E_SOURCE_EXTENSION (object)->priv;
110 
111 	g_weak_ref_clear (&priv->source);
112 	g_rec_mutex_clear (&priv->property_lock);
113 
114 	/* Chain up to parent's finalize() method. */
115 	G_OBJECT_CLASS (e_source_extension_parent_class)->finalize (object);
116 }
117 
118 static void
source_extension_notify(GObject * object,GParamSpec * pspec)119 source_extension_notify (GObject *object,
120                          GParamSpec *pspec)
121 {
122 	ESource *source;
123 	ESourceExtension *extension;
124 
125 	extension = E_SOURCE_EXTENSION (object);
126 	source = e_source_extension_ref_source (extension);
127 	g_return_if_fail (source != NULL);
128 
129 	if ((pspec->flags & E_SOURCE_PARAM_SETTING) != 0)
130 		e_source_changed (source);
131 
132 	g_object_unref (source);
133 }
134 
135 static void
e_source_extension_class_init(ESourceExtensionClass * class)136 e_source_extension_class_init (ESourceExtensionClass *class)
137 {
138 	GObjectClass *object_class;
139 
140 	object_class = G_OBJECT_CLASS (class);
141 	object_class->set_property = source_extension_set_property;
142 	object_class->get_property = source_extension_get_property;
143 	object_class->dispose = source_extension_dispose;
144 	object_class->finalize = source_extension_finalize;
145 	object_class->notify = source_extension_notify;
146 
147 	g_object_class_install_property (
148 		object_class,
149 		PROP_SOURCE,
150 		g_param_spec_object (
151 			"source",
152 			"Source",
153 			"The ESource being extended",
154 			E_TYPE_SOURCE,
155 			G_PARAM_READWRITE |
156 			G_PARAM_CONSTRUCT_ONLY |
157 			G_PARAM_STATIC_STRINGS));
158 }
159 
160 static void
e_source_extension_init(ESourceExtension * extension)161 e_source_extension_init (ESourceExtension *extension)
162 {
163 	extension->priv = e_source_extension_get_instance_private (extension);
164 	g_weak_ref_init (&extension->priv->source, NULL);
165 	g_rec_mutex_init (&extension->priv->property_lock);
166 }
167 
168 /**
169  * e_source_extension_ref_source:
170  * @extension: an #ESourceExtension
171  *
172  * Returns the #ESource instance to which the @extension belongs.
173  *
174  * The returned #ESource is referenced for thread-safety.  Unreference
175  * the #ESource with g_object_unref() when finished with it.
176  *
177  * Returns: (transfer full): the #ESource instance
178  *
179  * Since: 3.8
180  **/
181 ESource *
e_source_extension_ref_source(ESourceExtension * extension)182 e_source_extension_ref_source (ESourceExtension *extension)
183 {
184 	g_return_val_if_fail (E_IS_SOURCE_EXTENSION (extension), NULL);
185 
186 	return g_weak_ref_get (&extension->priv->source);
187 }
188 
189 /**
190  * e_source_extension_get_source:
191  * @extension: an #ESourceExtension
192  *
193  * Returns the #ESource instance to which @extension belongs.
194  *
195  * Note this function is not thread-safe.  The returned #ESource could
196  * be finalized by another thread while the caller is still using it.
197  *
198  * Returns: (transfer none): the #ESource instance
199  *
200  * Since: 3.6
201  *
202  * Deprecated: 3.8: Use e_source_extension_ref_source() instead.
203  **/
204 ESource *
e_source_extension_get_source(ESourceExtension * extension)205 e_source_extension_get_source (ESourceExtension *extension)
206 {
207 	ESource *source;
208 
209 	g_return_val_if_fail (E_IS_SOURCE_EXTENSION (extension), NULL);
210 
211 	source = e_source_extension_ref_source (extension);
212 
213 	/* XXX Drop the ESource reference for backward-compatibility.
214 	 *     This is risky.  Without a reference, the ESource could
215 	 *     be finalized while the caller is still using it. */
216 	if (source != NULL)
217 		g_object_unref (source);
218 
219 	return source;
220 }
221 
222 /**
223  * e_source_extension_property_lock:
224  * @extension: an #ESourceExtension
225  *
226  * Acquires a property lock, thus no other thread can change properties
227  * of the @extension until the lock is released.
228  *
229  * Since: 3.18
230  **/
231 void
e_source_extension_property_lock(ESourceExtension * extension)232 e_source_extension_property_lock (ESourceExtension *extension)
233 {
234 	g_return_if_fail (E_IS_SOURCE_EXTENSION (extension));
235 
236 	g_rec_mutex_lock (&extension->priv->property_lock);
237 }
238 
239 /**
240  * e_source_extension_property_unlock:
241  * @extension: an #ESourceExtension
242  *
243  * Releases a property lock, previously acquired with e_source_extension_property_lock(),
244  * thus other threads can change properties of the @extension.
245  *
246  * Since: 3.18
247  **/
248 void
e_source_extension_property_unlock(ESourceExtension * extension)249 e_source_extension_property_unlock (ESourceExtension *extension)
250 {
251 	g_return_if_fail (E_IS_SOURCE_EXTENSION (extension));
252 
253 	g_rec_mutex_unlock (&extension->priv->property_lock);
254 }
255