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