1 /*
2  * e-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-extension
20  * @include: libedataserver/libedataserver.h
21  * @short_description: An abstract base class for extensions
22  *
23  * #EExtension provides a way to extend the functionality of objects
24  * that implement the #EExtensible interface.  #EExtension subclasses
25  * can target a particular extensible object type.  New instances of
26  * an extensible object type get paired with a new instance of each
27  * #EExtension subclass that targets the extensible object type.
28  *
29  * The first steps of writing a new extension are as follows:
30  *
31  * 1. Subclass #EExtension.
32  *
33  * 2. In the class initialization function, specify the #GType being
34  *    extended.  The #GType must implement the #EExtensible interface.
35  *
36  * 3. Register the extension's own #GType.  If the extension is to
37  *    be loaded dynamically using #GTypeModule, the type should be
38  *    registered in the library module's e_module_load() function.
39  **/
40 
41 #include "evolution-data-server-config.h"
42 
43 #include "e-extension.h"
44 
45 struct _EExtensionPrivate {
46 	gpointer extensible;  /* weak pointer */
47 };
48 
49 enum {
50 	PROP_0,
51 	PROP_EXTENSIBLE
52 };
53 
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(EExtension,e_extension,G_TYPE_OBJECT)54 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (
55 	EExtension,
56 	e_extension,
57 	G_TYPE_OBJECT)
58 
59 static void
60 extension_set_extensible (EExtension *extension,
61                           EExtensible *extensible)
62 {
63 	EExtensionClass *class;
64 	GType extensible_type;
65 
66 	g_return_if_fail (E_IS_EXTENSIBLE (extensible));
67 	g_return_if_fail (extension->priv->extensible == NULL);
68 
69 	class = E_EXTENSION_GET_CLASS (extension);
70 	g_return_if_fail (class != NULL);
71 
72 	extensible_type = G_OBJECT_TYPE (extensible);
73 
74 	/* Verify the EExtensible object is the type we want. */
75 	if (!g_type_is_a (extensible_type, class->extensible_type)) {
76 		g_warning (
77 			"%s is meant to extend %s but was given an %s",
78 			G_OBJECT_TYPE_NAME (extension),
79 			g_type_name (class->extensible_type),
80 			g_type_name (extensible_type));
81 		return;
82 	}
83 
84 	extension->priv->extensible = extensible;
85 
86 	g_object_add_weak_pointer (
87 		G_OBJECT (extensible), &extension->priv->extensible);
88 }
89 
90 static void
extension_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)91 extension_set_property (GObject *object,
92                         guint property_id,
93                         const GValue *value,
94                         GParamSpec *pspec)
95 {
96 	switch (property_id) {
97 		case PROP_EXTENSIBLE:
98 			extension_set_extensible (
99 				E_EXTENSION (object),
100 				g_value_get_object (value));
101 			return;
102 	}
103 
104 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
105 }
106 
107 static void
extension_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)108 extension_get_property (GObject *object,
109                         guint property_id,
110                         GValue *value,
111                         GParamSpec *pspec)
112 {
113 	switch (property_id) {
114 		case PROP_EXTENSIBLE:
115 			g_value_set_object (
116 				value, e_extension_get_extensible (
117 				E_EXTENSION (object)));
118 			return;
119 	}
120 
121 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
122 }
123 
124 static void
extension_dispose(GObject * object)125 extension_dispose (GObject *object)
126 {
127 	EExtensionPrivate *priv;
128 
129 	priv = E_EXTENSION (object)->priv;
130 
131 	if (priv->extensible != NULL) {
132 		g_object_remove_weak_pointer (
133 			G_OBJECT (priv->extensible), &priv->extensible);
134 		priv->extensible = NULL;
135 	}
136 
137 	/* Chain up to parent's dispose() method. */
138 	G_OBJECT_CLASS (e_extension_parent_class)->dispose (object);
139 }
140 
141 static void
e_extension_class_init(EExtensionClass * class)142 e_extension_class_init (EExtensionClass *class)
143 {
144 	GObjectClass *object_class;
145 
146 	object_class = G_OBJECT_CLASS (class);
147 	object_class->set_property = extension_set_property;
148 	object_class->get_property = extension_get_property;
149 	object_class->dispose = extension_dispose;
150 
151 	g_object_class_install_property (
152 		object_class,
153 		PROP_EXTENSIBLE,
154 		g_param_spec_object (
155 			"extensible",
156 			"Extensible Object",
157 			"The object being extended",
158 			E_TYPE_EXTENSIBLE,
159 			G_PARAM_READWRITE |
160 			G_PARAM_CONSTRUCT_ONLY));
161 }
162 
163 static void
e_extension_init(EExtension * extension)164 e_extension_init (EExtension *extension)
165 {
166 	extension->priv = e_extension_get_instance_private (extension);
167 }
168 
169 /**
170  * e_extension_get_extensible:
171  * @extension: an #EExtension
172  *
173  * Returns the object that @extension extends.
174  *
175  * Returns: (transfer none): the object being extended
176  *
177  * Since: 3.4
178  **/
179 EExtensible *
e_extension_get_extensible(EExtension * extension)180 e_extension_get_extensible (EExtension *extension)
181 {
182 	g_return_val_if_fail (E_IS_EXTENSION (extension), NULL);
183 
184 	return E_EXTENSIBLE (extension->priv->extensible);
185 }
186