1 /*
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail    : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #ifndef __CAIRO_DOCK_OBJECT__
21 #define  __CAIRO_DOCK_OBJECT__
22 
23 #include <glib.h>
24 #include "cairo-dock-struct.h"
25 
26 G_BEGIN_DECLS
27 
28 /**
29 *@file cairo-dock-object.h This class defines the Objects, the base class of libgldi.
30 * Every element in this library is an Object.
31 * An object is defined by an ObjectManager, which defines its capabilities and signals.
32 *
33 * Any object is created with \ref gldi_object_new and destroyed with \ref gldi_object_unref.
34 * An object can be deleted from the current theme with \ref gldi_object_delete.
35 * An object can be reloaded with \ref gldi_object_reload.
36 *
37 * You can listen for notifications on an object with \ref gldi_object_register_notification and stop listening with \ref gldi_object_remove_notification.
38 * To listen for notifications on any object of a given type, simply register yourself on its ObjectManager.
39 */
40 
41 /// Definition of an Object.
42 struct _GldiObject {
43 	gint ref;
44 	GPtrArray *pNotificationsTab;
45 	GldiObjectManager *mgr;
46 	GList *mgrs;  // sorted in reverse order
47 };
48 
49 /// Definition of an ObjectManager.
50 struct _GldiObjectManager {
51 	GldiObject object;
52 	const gchar *cName;
53 	gint iObjectSize;
54 	void (*init_object) (GldiObject *pObject, gpointer attr);
55 	void (*reset_object) (GldiObject *pObject);
56 	gboolean (*delete_object) (GldiObject *pObject);
57 	GKeyFile* (*reload_object) (GldiObject *pObject, gboolean bReloadConf, GKeyFile *pKeyFile);
58 };
59 
60 
61 /// signals (any object has at least these ones)
62 typedef enum {
63 	/// notification called when an object has been created. data : the object
64 	NOTIFICATION_NEW,
65 	/// notification called when the object is going to be destroyed. data : the object
66 	NOTIFICATION_DESTROY,
67 	NB_NOTIFICATIONS_OBJECT
68 	} GldiObjectNotifications;
69 
70 #define GLDI_OBJECT(p) ((GldiObject*)(p))
71 
72 
73 void gldi_object_init (GldiObject *obj, GldiObjectManager *pMgr, gpointer attr);
74 
75 /** Create a new object.
76  * @param pMgr the ObjectManager
77  * @param attr the attributes of the object
78  * @return the new object, with a reference of 1; use \ref gldi_object_unref to destroy it
79  */
80 GldiObject *gldi_object_new (GldiObjectManager *pMgr, gpointer attr);
81 
82 /** Take a reference on an object.
83  * @param pObject the Object
84  */
85 void gldi_object_ref (GldiObject *pObject);
86 
87 /** Drop your reference on an object. If it's the last reference, the object is destroyed, otherwise nothing happens.
88  * @param pObject the Object
89  */
90 void gldi_object_unref (GldiObject *pObject);
91 
92 /** Delete an object from the current theme. The object is unref'd, and won't be created again on next startup.
93  * @param pObject the Object
94  */
95 void gldi_object_delete (GldiObject *pObject);
96 
97 /** Reload an object.
98  * @param pObject the Object
99  * @param bReloadConfig TRUE to read its config file again (if the object has one)
100  */
101 void gldi_object_reload (GldiObject *pObject, gboolean bReloadConfig);
102 
103 /* Sets the ObjectManager of an object. It is only useful to make an ObjectManager derive from another one. For any other object, it is done automatically.
104  */
105 void gldi_object_set_manager (GldiObject *pObject, GldiObjectManager *pMgr);
106 
107 gboolean gldi_object_is_manager_child (GldiObject *pObject, GldiObjectManager *pMgr);
108 
109 #define gldi_object_get_type(obj) (GLDI_OBJECT(obj)->mgr ? GLDI_OBJECT(obj)->mgr->cName : "ObjectManager")
110 
111 
112 /// Generic prototype of a notification callback.
113 typedef gboolean (* GldiNotificationFunc) (gpointer pUserData, ...);
114 
115 typedef struct {
116 	GldiNotificationFunc pFunction;
117 	gpointer pUserData;
118 	} GldiNotificationRecord;
119 
120 typedef guint GldiNotificationType;
121 
122 /// Use this in \ref gldi_object_register_notification to be called before the core.
123 #define GLDI_RUN_FIRST TRUE
124 /// Use this in \ref gldi_object_register_notification to be called after the core.
125 #define GLDI_RUN_AFTER FALSE
126 
127 /// Return this in your callback to prevent the other callbacks from being called after you.
128 #define GLDI_NOTIFICATION_INTERCEPT TRUE
129 /// Return this in your callback to let pass the notification to the other callbacks after you.
130 #define GLDI_NOTIFICATION_LET_PASS FALSE
131 
132 
133 #define gldi_object_install_notifications(pObject, iNbNotifs) do {\
134 	GPtrArray *pNotificationsTab = (GLDI_OBJECT(pObject))->pNotificationsTab;\
135 	if (pNotificationsTab == NULL) {\
136 		pNotificationsTab = g_ptr_array_new ();\
137 		(GLDI_OBJECT(pObject))->pNotificationsTab = pNotificationsTab; }\
138 	if (pNotificationsTab->len < iNbNotifs)\
139 		g_ptr_array_set_size (pNotificationsTab, iNbNotifs); } while (0)
140 
141 /** Register an action to be called when a given notification is broadcasted from a given object.
142 *@param pObject the object (Icon, Container, Manager).
143 *@param iNotifType type of the notification.
144 *@param pFunction callback.
145 *@param bRunFirst GLDI_RUN_FIRST to be called before Cairo-Dock, GLDI_RUN_AFTER to be called after.
146 *@param pUserData data to be passed as the first parameter of the callback.
147 */
148 void gldi_object_register_notification (gpointer pObject, GldiNotificationType iNotifType, GldiNotificationFunc pFunction, gboolean bRunFirst, gpointer pUserData);
149 
150 /** Remove a callback from the list of callbacks of a given object for a given notification and a given data.
151 Note: it is safe to remove the callback when it is called, but not another one.
152 *@param pObject the object (Icon, Container, Manager) for which the action has been registered.
153 *@param iNotifType type of the notification.
154 *@param pFunction callback.
155 *@param pUserData data that was registerd with the callback.
156 */
157 void gldi_object_remove_notification (gpointer pObject, GldiNotificationType iNotifType, GldiNotificationFunc pFunction, gpointer pUserData);
158 
159 
160 #define __notify(pNotificationRecordList, bStop, ...) do {\
161 	GldiNotificationRecord *pNotificationRecord;\
162 	GSList *pElement = pNotificationRecordList, *pNextElement;\
163 	while (pElement != NULL && ! bStop) {\
164 		pNotificationRecord = pElement->data;\
165 		pNextElement = pElement->next;\
166 		bStop = pNotificationRecord->pFunction (pNotificationRecord->pUserData, ##__VA_ARGS__);\
167 		pElement = pNextElement; }\
168 	} while (0)
169 
170 #define __notify_on_object(pObject, iNotifType, ...) \
171 	__extension__ ({\
172 	gboolean _stop = FALSE;\
173 	GPtrArray *pNotificationsTab = (pObject)->pNotificationsTab;\
174 	if (pNotificationsTab && iNotifType < pNotificationsTab->len) {\
175 		GSList *pNotificationRecordList = g_ptr_array_index (pNotificationsTab, iNotifType);\
176 		__notify (pNotificationRecordList, _stop, ##__VA_ARGS__);} \
177 	else {_stop = TRUE;}\
178 	_stop; })
179 
180 /** Broadcast a notification on a given object, and on all its managers.
181 *@param pObject the object (Icon, Container, Manager, ...).
182 *@param iNotifType type of the notification.
183 *@param ... parameters to be passed to the callbacks that have registered to this notification.
184 */
185 #define gldi_object_notify(pObject, iNotifType, ...) \
186 	__extension__ ({\
187 	gboolean _bStop = FALSE;\
188 	GldiObject *_obj = GLDI_OBJECT (pObject);\
189 	while (_obj && !_bStop) {\
190 		_bStop = __notify_on_object (_obj, iNotifType, ##__VA_ARGS__);\
191 		_obj = GLDI_OBJECT (_obj->mgr); }\
192 	})
193 
194 
195 
196 #define	GLDI_STR_HELPER(x) #x
197 #define	GLDI_STR(x) GLDI_STR_HELPER(x)
198 
199 #define GLDI_MGR_NAME(name) my##name##ObjectMgr
200 #define GLDI_OBJECT_NAME(name) Gldi##name
201 
202 #define GLDI_OBJECT_MANAGER_REGISTER(name) gldi_##name##_object_manager_register()
203 
204 #define GLDI_OBJECT_MANAGER_DEFINE_H(name) void GLDI_OBJECT_MANAGER_REGISTER(name)
205 
206 //name=Dock, NAME=DOCK
207 #define GLDI_OBJECT_MANAGER_DEFINE_BEGIN(name, NAME) \
208 GLDI_OBJECT_MANAGER_DEFINE_H(name) \
209 { \
210 	GldiObjectManager *mgr = &GLDI_MGR_NAME(name); \
211 	memset (mgr, 0, sizeof (GldiObjectManager)); \
212 	mgr->cName         = GLDI_STR(name); \
213 	mgr->iObjectSize   = sizeof (GLDI_OBJECT_NAME(name)); \
214 	gldi_object_install_notifications (mgr, NB_NOTIFICATIONS_##NAME);
215 
216 #define GLDI_OBJECT_MANAGER_HAS_INIT   mgr->init_object     = init_object;
217 #define GLDI_OBJECT_MANAGER_HAS_RESET  mgr->reset_object    = reset_object;
218 #define GLDI_OBJECT_MANAGER_HAS_DELETE mgr->delete_object   = delete_object;
219 #define GLDI_OBJECT_MANAGER_HAS_RELOAD mgr->reload_object   = reload_object;
220 
221 #define GLDI_OBJECT_MANAGER_DERIVES_FROM(mgr2) gldi_object_set_manager (GLDI_OBJECT (mgr), mgr2)
222 
223 #define GLDI_OBJECT_MANAGER_DEFINE_END }
224 
225 
226 G_END_DECLS
227 #endif
228