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 #include <string.h>
21 #include <stdlib.h>
22 #include <glib/gstdio.h>
23 #include <dlfcn.h>
24 
25 #include "gldi-config.h"
26 #include "gldi-module-config.h"
27 #include "cairo-dock-dock-manager.h"
28 #include "cairo-dock-themes-manager.h"  // cairo_dock_add_conf_file
29 #include "cairo-dock-file-manager.h"  // cairo_dock_copy_file
30 #include "cairo-dock-log.h"
31 #include "cairo-dock-applet-manager.h"
32 #include "cairo-dock-desktop-manager.h"  // gldi_desktop_get_width
33 #include "cairo-dock-desklet-manager.h"
34 #include "cairo-dock-animations.h"
35 #include "cairo-dock-config.h"
36 #include "cairo-dock-module-instance-manager.h"
37 #define _MANAGER_DEF_
38 #include "cairo-dock-module-manager.h"
39 
40 // public (manager, config, data)
41 GldiModulesParam myModulesParam;
42 GldiManager myModulesMgr;
43 GldiObjectManager myModuleObjectMgr;
44 
45 GldiModuleInstance *g_pCurrentModule = NULL;  // only used to trace a possible crash in one of the modules.
46 
47 // dependancies
48 extern gchar *g_cConfFile;
49 extern gchar *g_cCurrentThemePath;
50 extern int g_iMajorVersion, g_iMinorVersion, g_iMicroVersion;
51 extern gboolean g_bEasterEggs;
52 
53 // private
54 static GHashTable *s_hModuleTable = NULL;
55 static GList *s_AutoLoadedModules = NULL;
56 static guint s_iSidWriteModules = 0;
57 
58 
59   ///////////////
60  /// MANAGER ///
61 ///////////////
62 
gldi_module_get(const gchar * cModuleName)63 GldiModule *gldi_module_get (const gchar *cModuleName)
64 {
65 	g_return_val_if_fail (cModuleName != NULL, NULL);
66 	return g_hash_table_lookup (s_hModuleTable, cModuleName);
67 }
68 
gldi_module_foreach(GHRFunc pCallback,gpointer user_data)69 GldiModule *gldi_module_foreach (GHRFunc pCallback, gpointer user_data)
70 {
71 	return g_hash_table_find (s_hModuleTable, (GHRFunc) pCallback, user_data);
72 }
73 
_sort_module_by_alphabetical_order(GldiModule * m1,GldiModule * m2)74 static int _sort_module_by_alphabetical_order (GldiModule *m1, GldiModule *m2)
75 {
76 	if (!m1 || !m1->pVisitCard || !m1->pVisitCard->cTitle)
77 		return 1;
78 	if (!m2 || !m2->pVisitCard || !m2->pVisitCard->cTitle)
79 		return -1;
80 	return g_ascii_strncasecmp (m1->pVisitCard->cTitle, m2->pVisitCard->cTitle, -1);
81 }
gldi_module_foreach_in_alphabetical_order(GCompareFunc pCallback,gpointer user_data)82 GldiModule *gldi_module_foreach_in_alphabetical_order (GCompareFunc pCallback, gpointer user_data)
83 {
84 	GList *pModuleList = g_hash_table_get_values (s_hModuleTable);
85 	pModuleList = g_list_sort (pModuleList, (GCompareFunc) _sort_module_by_alphabetical_order);
86 
87 	GldiModule *pModule = (GldiModule *)g_list_find_custom (pModuleList, user_data, pCallback);
88 
89 	g_list_free (pModuleList);
90 	return pModule;
91 }
92 
gldi_module_get_nb(void)93 int gldi_module_get_nb (void)
94 {
95 	return g_hash_table_size (s_hModuleTable);
96 }
97 
_write_one_module_name(const gchar * cModuleName,GldiModule * pModule,GString * pString)98 static void _write_one_module_name (const gchar *cModuleName, GldiModule *pModule, GString *pString)
99 {
100 	if (pModule->pInstancesList != NULL && ! gldi_module_is_auto_loaded (pModule))
101 	{
102 		g_string_append_printf (pString, "%s;", cModuleName);
103 	}
104 }
_gldi_module_list_active(void)105 static gchar *_gldi_module_list_active (void)
106 {
107 	GString *pString = g_string_new ("");
108 
109 	g_hash_table_foreach (s_hModuleTable, (GHFunc) _write_one_module_name, pString);
110 
111 	if (pString->len > 0)
112 		pString->str[pString->len-1] = '\0';
113 
114 	gchar *cModuleNames = pString->str;
115 	g_string_free (pString, FALSE);
116 	return cModuleNames;
117 }
118 
_write_modules_idle(G_GNUC_UNUSED gpointer data)119 static gboolean _write_modules_idle (G_GNUC_UNUSED gpointer data)
120 {
121 	gchar *cModuleNames = _gldi_module_list_active ();
122 	cd_debug ("%s", cModuleNames);
123 	cairo_dock_update_conf_file (g_cConfFile,
124 		G_TYPE_STRING, "System", "modules", cModuleNames,
125 		G_TYPE_INVALID);
126 	g_free (cModuleNames);
127 	s_iSidWriteModules = 0;
128 	return FALSE;
129 }
gldi_modules_write_active(void)130 void gldi_modules_write_active (void)
131 {
132 	if (s_iSidWriteModules == 0)
133 		s_iSidWriteModules = g_idle_add (_write_modules_idle, NULL);
134 }
135 
136 
137   /////////////////////
138  /// MODULE LOADER ///
139 /////////////////////
140 
gldi_module_new(GldiVisitCard * pVisitCard,GldiModuleInterface * pInterface)141 GldiModule *gldi_module_new (GldiVisitCard *pVisitCard, GldiModuleInterface *pInterface)
142 {
143 	g_return_val_if_fail (pVisitCard != NULL && pVisitCard->cModuleName != NULL, NULL);
144 
145 	GldiModuleAttr attr = {pVisitCard, pInterface};
146 	return (GldiModule*)gldi_object_new (&myModuleObjectMgr, &attr);
147 }
148 
gldi_module_new_from_so_file(const gchar * cSoFilePath)149 GldiModule *gldi_module_new_from_so_file (const gchar *cSoFilePath)
150 {
151 	g_return_val_if_fail (cSoFilePath != NULL, NULL);
152 	GldiVisitCard *pVisitCard = NULL;
153 	GldiModuleInterface *pInterface = NULL;
154 
155 	// open the .so file
156 	///GModule *module = g_module_open (pGldiModule->cSoFilePath, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
157 	gpointer handle = dlopen (cSoFilePath, RTLD_LAZY | RTLD_LOCAL);
158 	if (! handle)
159 	{
160 		cd_warning ("while opening module '%s' : (%s)", cSoFilePath, dlerror());
161 		return NULL;
162 	}
163 
164 	// find the pre-init entry point
165 	GldiModulePreInit function_pre_init = NULL;
166 	/**bSymbolFound = g_module_symbol (module, "pre_init", (gpointer) &function_pre_init);
167 	if (bSymbolFound && function_pre_init != NULL)*/
168 	function_pre_init = dlsym (handle, "pre_init");
169 	if (function_pre_init == NULL)
170 	{
171 		cd_warning ("this module ('%s') does not have the common entry point 'pre_init', it may be broken or icompatible with cairo-dock", cSoFilePath);
172 		goto discard;
173 	}
174 
175 	// run the pre-init entry point to get the necessary info about the module
176 	pVisitCard = g_new0 (GldiVisitCard, 1);
177 	pInterface = g_new0 (GldiModuleInterface, 1);
178 	gboolean bModuleLoaded = function_pre_init (pVisitCard, pInterface);
179 	if (! bModuleLoaded)
180 	{
181 		cd_debug ("module '%s' has not been loaded", cSoFilePath);  // can happen to xxx-integration or icon-effect for instance.
182 		goto discard;
183 	}
184 
185 	// check module compatibility
186 	if (! g_bEasterEggs &&
187 		(pVisitCard->iMajorVersionNeeded > g_iMajorVersion
188 		|| (pVisitCard->iMajorVersionNeeded == g_iMajorVersion && pVisitCard->iMinorVersionNeeded > g_iMinorVersion)
189 		|| (pVisitCard->iMajorVersionNeeded == g_iMajorVersion && pVisitCard->iMinorVersionNeeded == g_iMinorVersion && pVisitCard->iMicroVersionNeeded > g_iMicroVersion)))
190 	{
191 		cd_warning ("this module ('%s') needs at least Cairo-Dock v%d.%d.%d, but Cairo-Dock is in v%d.%d.%d (%s)\n  It will be ignored", cSoFilePath, pVisitCard->iMajorVersionNeeded, pVisitCard->iMinorVersionNeeded, pVisitCard->iMicroVersionNeeded, g_iMajorVersion, g_iMinorVersion, g_iMicroVersion, GLDI_VERSION);
192 		goto discard;
193 	}
194 	if (! g_bEasterEggs
195 	&& pVisitCard->cDockVersionOnCompilation != NULL && strcmp (pVisitCard->cDockVersionOnCompilation, GLDI_VERSION) != 0)  // separation des versions en easter egg.
196 	{
197 		cd_warning ("this module ('%s') was compiled with Cairo-Dock v%s, but Cairo-Dock is in v%s\n  It will be ignored", cSoFilePath, pVisitCard->cDockVersionOnCompilation, GLDI_VERSION);
198 		goto discard;
199 	}
200 
201 	// create a new module with these info
202 	GldiModule *pModule = gldi_module_new (pVisitCard, pInterface);  // takes ownership of pVisitCard and pInterface
203 	if (pModule)
204 		pModule->handle = handle;
205 	return pModule;
206 
207 discard:
208 	///g_module_close (pModule);
209 	dlclose (handle);
210 	cairo_dock_free_visit_card (pVisitCard);
211 	g_free (pInterface);
212 	return NULL;
213 }
214 
gldi_modules_new_from_directory(const gchar * cModuleDirPath,GError ** erreur)215 void gldi_modules_new_from_directory (const gchar *cModuleDirPath, GError **erreur)
216 {
217 	if (cModuleDirPath == NULL)
218 		cModuleDirPath = GLDI_MODULES_DIR;
219 	cd_message ("%s (%s)", __func__, cModuleDirPath);
220 
221 	GError *tmp_erreur = NULL;
222 	GDir *dir = g_dir_open (cModuleDirPath, 0, &tmp_erreur);
223 	if (tmp_erreur != NULL)
224 	{
225 		g_propagate_error (erreur, tmp_erreur);
226 		return ;
227 	}
228 
229 	const gchar *cFileName;
230 	GString *sFilePath = g_string_new ("");
231 	do
232 	{
233 		cFileName = g_dir_read_name (dir);
234 		if (cFileName == NULL)
235 			break ;
236 
237 		if (g_str_has_suffix (cFileName, ".so"))
238 		{
239 			g_string_printf (sFilePath, "%s/%s", cModuleDirPath, cFileName);
240 			(void)gldi_module_new_from_so_file (sFilePath->str);
241 		}
242 	}
243 	while (1);
244 	g_string_free (sFilePath, TRUE);
245 	g_dir_close (dir);
246 }
247 
gldi_module_get_config_dir(GldiModule * pModule)248 gchar *gldi_module_get_config_dir (GldiModule *pModule)
249 {
250 	GldiVisitCard *pVisitCard = pModule->pVisitCard;
251 	if (pVisitCard->cConfFileName == NULL)
252 		return NULL;
253 
254 	gchar *cUserDataDirPath = g_strdup_printf ("%s/plug-ins/%s", g_cCurrentThemePath, pVisitCard->cUserDataDir);
255 	if (! g_file_test (cUserDataDirPath, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
256 	{
257 		cd_message ("directory %s doesn't exist, it will be added.", cUserDataDirPath);
258 
259 		gchar *command = g_strdup_printf ("mkdir -p \"%s\"", cUserDataDirPath);
260 		int r = system (command);
261 		g_free (command);
262 
263 		if (r != 0)
264 		{
265 			cd_warning ("couldn't create a directory for applet '%s' in '%s/plug-ins'\n check writing permissions", pVisitCard->cModuleName, g_cCurrentThemePath);
266 			g_free (cUserDataDirPath);
267 			g_free (pModule->cConfFilePath);
268 			pModule->cConfFilePath = NULL;
269 			return NULL;
270 		}
271 	}
272 
273 	return cUserDataDirPath;
274 }
275 
cairo_dock_free_visit_card(GldiVisitCard * pVisitCard)276 void cairo_dock_free_visit_card (GldiVisitCard *pVisitCard)
277 {
278 	g_free (pVisitCard);  // toutes les chaines sont statiques.
279 }
280 
281 
282   /////////////////////////
283  /// MODULES HIGH LEVEL///
284 /////////////////////////
285 
gldi_module_activate(GldiModule * module)286 void gldi_module_activate (GldiModule *module)
287 {
288 	g_return_if_fail (module != NULL && module->pVisitCard != NULL);
289 	cd_debug ("%s (%s)", __func__, module->pVisitCard->cModuleName);
290 
291 	if (module->pInstancesList != NULL)
292 	{
293 		cd_warning ("Module %s already active", module->pVisitCard->cModuleName);
294 		return ;
295 	}
296 
297 	if (module->pVisitCard->cConfFileName != NULL)  // the module has a conf file -> create an instance for each of them.
298 	{
299 		// check that the module's config dir exists or create it.
300 		gchar *cUserDataDirPath = gldi_module_get_config_dir (module);
301 		if (cUserDataDirPath == NULL)
302 		{
303 			cd_warning ("Unable to open the config folder of module %s\nCheck permissions", module->pVisitCard->cModuleName);
304 			return;
305 		}
306 
307 		// look for conf files inside this folder, and create an instance for each of them.
308 		int n = 0;
309 		if (module->pVisitCard->bMultiInstance)  // possibly several conf files.
310 		{
311 			// open it
312 			GError *tmp_erreur = NULL;
313 			GDir *dir = g_dir_open (cUserDataDirPath, 0, &tmp_erreur);
314 			if (tmp_erreur != NULL)
315 			{
316 				cd_warning ("couldn't open folder %s (%s)", cUserDataDirPath, tmp_erreur->message);
317 				g_error_free (tmp_erreur);
318 				g_free (cUserDataDirPath);
319 				return ;
320 			}
321 
322 			// for each conf file inside, instanciate the module with it.
323 			const gchar *cFileName;
324 			gchar *cInstanceFilePath;
325 
326 			while ((cFileName = g_dir_read_name (dir)) != NULL)
327 			{
328 				gchar *str = strstr (cFileName, ".conf");
329 				if (!str)
330 					continue;
331 				if (*(str+5) != '-' && *(str+5) != '\0')  // xxx.conf or xxx.conf-i
332 					continue;
333 				cInstanceFilePath = g_strdup_printf ("%s/%s", cUserDataDirPath, cFileName);
334 				gldi_module_instance_new (module, cInstanceFilePath);  // takes ownership of 'cInstanceFilePath'.
335 				n ++;
336 			}
337 			g_dir_close (dir);
338 		}
339 		else  // only 1 conf file possible.
340 		{
341 			gchar *cConfFilePath = g_strdup_printf ("%s/%s", cUserDataDirPath, module->pVisitCard->cConfFileName);
342 			if (g_file_test (cConfFilePath, G_FILE_TEST_EXISTS))
343 			{
344 				gldi_module_instance_new (module, cConfFilePath);
345 				n = 1;
346 			}
347 			else
348 			{
349 				g_free (cConfFilePath);
350 			}
351 		}
352 
353 		// if no conf file was present, copy the default one and instanciate the module with it.
354 		if (n == 0)  // no conf file was present.
355 		{
356 			gchar *cConfFilePath = g_strdup_printf ("%s/%s", cUserDataDirPath, module->pVisitCard->cConfFileName);
357 			gboolean r = cairo_dock_copy_file (module->cConfFilePath, cConfFilePath);
358 			if (! r)  // the copy failed.
359 			{
360 				cd_warning ("couldn't copy %s into %s; check permissions and file's existence", module->cConfFilePath, cUserDataDirPath);
361 				g_free (cConfFilePath);
362 				g_free (cUserDataDirPath);
363 				return;
364 			}
365 			else
366 			{
367 				gldi_module_instance_new (module, cConfFilePath);
368 			}
369 		}
370 
371 		g_free (cUserDataDirPath);
372 	}
373 	else  // the module has no conf file, just instanciate it once.
374 	{
375 		gldi_module_instance_new (module, NULL);
376 	}
377 }
378 
gldi_module_deactivate(GldiModule * module)379 void gldi_module_deactivate (GldiModule *module)  // stop all instances of a module
380 {
381 	g_return_if_fail (module != NULL);
382 	cd_debug ("%s (%s, %s)", __func__, module->pVisitCard->cModuleName, module->cConfFilePath);
383 	GList *pInstances = module->pInstancesList;
384 	module->pInstancesList = NULL;  // set to NULL already so that notifications don't get fooled. This can probably be avoided...
385 	g_list_foreach (pInstances, (GFunc)gldi_object_unref, NULL);
386 	g_list_free (pInstances);
387 	gldi_object_notify (module, NOTIFICATION_MODULE_ACTIVATED, module->pVisitCard->cModuleName, FALSE);  // throw it since the list was NULL when the instances were destroyed
388 	gldi_modules_write_active ();  // same
389 }
390 
391 
gldi_modules_activate_from_list(gchar ** cActiveModuleList)392 void gldi_modules_activate_from_list (gchar **cActiveModuleList)
393 {
394 	//\_______________ On active les modules auto-charges en premier.
395 	gchar *cModuleName;
396 	GldiModule *pModule;
397 	GList *m;
398 	for (m = s_AutoLoadedModules; m != NULL; m = m->next)
399 	{
400 		pModule = m->data;
401 		if (pModule->pInstancesList == NULL)  // not yet active
402 		{
403 			gldi_module_activate (pModule);
404 		}
405 	}
406 
407 	if (cActiveModuleList == NULL)
408 		return ;
409 
410 	//\_______________ On active tous les autres.
411 	int i;
412 	for (i = 0; cActiveModuleList[i] != NULL; i ++)
413 	{
414 		cModuleName = cActiveModuleList[i];
415 		pModule = g_hash_table_lookup (s_hModuleTable, cModuleName);
416 		if (pModule == NULL)
417 		{
418 			cd_debug ("No such module (%s)", cModuleName);
419 			continue ;
420 		}
421 
422 		if (pModule->pInstancesList == NULL)  // not yet active
423 		{
424 			gldi_module_activate (pModule);
425 		}
426 	}
427 
428 	// don't write down
429 	if (s_iSidWriteModules != 0)
430 	{
431 		g_source_remove (s_iSidWriteModules);
432 		s_iSidWriteModules = 0;
433 	}
434 }
435 
_deactivate_one_module(G_GNUC_UNUSED gchar * cModuleName,GldiModule * pModule,G_GNUC_UNUSED gpointer data)436 static void _deactivate_one_module (G_GNUC_UNUSED gchar *cModuleName, GldiModule *pModule, G_GNUC_UNUSED gpointer data)
437 {
438 	if (! gldi_module_is_auto_loaded (pModule))
439 		gldi_module_deactivate (pModule);
440 }
gldi_modules_deactivate_all(void)441 void gldi_modules_deactivate_all (void)
442 {
443 	// first deactivate applets
444 	g_hash_table_foreach (s_hModuleTable, (GHFunc)_deactivate_one_module, NULL);
445 
446 	// then deactivate auto-loaded modules (that have been loaded first)
447 	GldiModule *pModule;
448 	GList *m;
449 	for (m = s_AutoLoadedModules; m != NULL; m = m->next)
450 	{
451 		pModule = m->data;
452 		gldi_module_deactivate (pModule);
453 	}
454 
455 	// don't write down
456 	if (s_iSidWriteModules != 0)
457 	{
458 		g_source_remove (s_iSidWriteModules);
459 		s_iSidWriteModules = 0;
460 	}
461 }
462 
463 
gldi_module_add_conf_file(GldiModule * pModule)464 gchar *gldi_module_add_conf_file (GldiModule *pModule)
465 {
466 	gchar *cUserDataDirPath = gldi_module_get_config_dir (pModule);
467 	if (cUserDataDirPath == NULL)
468 		return NULL;
469 
470 	// find a name that doesn't exist yet in the config dir.
471 	gchar *cConfFilePath;
472 	int i = 0;
473 	do
474 	{
475 		if (i == 0)
476 			cConfFilePath = g_strdup_printf ("%s/%s", cUserDataDirPath, pModule->pVisitCard->cConfFileName);
477 		else
478 			cConfFilePath = g_strdup_printf ("%s/%s-%d", cUserDataDirPath, pModule->pVisitCard->cConfFileName, i);
479 		if (! g_file_test (cConfFilePath, G_FILE_TEST_EXISTS))
480 			break;
481 		g_free (cConfFilePath);
482 		i ++;
483 	} while (1);
484 
485 	// copy one of the instances conf file, or the default one.
486 	GldiModuleInstance *pFirstInstance = NULL;
487 	if (pModule->pInstancesList != NULL)
488 	{
489 		GList *last = g_list_last (pModule->pInstancesList);
490 		pFirstInstance = last->data;  // instances are prepended.
491 
492 		cairo_dock_add_conf_file (pFirstInstance->cConfFilePath, cConfFilePath);
493 
494 		if (pFirstInstance->pDesklet)  // prevent desklets from overlapping.
495 		{
496 			int iX2, iX = pFirstInstance->pContainer->iWindowPositionX;
497 			int iWidth = pFirstInstance->pContainer->iWidth;
498 			if (iX + iWidth/2 <= gldi_desktop_get_width()/2)  // desklet on the left, we place the new one on its right.
499 				iX2 = iX + iWidth;
500 			else  // desklet on the right, we place the new one on its left.
501 				iX2 = iX - iWidth;
502 
503 			int iRelativePositionX = (iX2 + iWidth/2 <= gldi_desktop_get_width()/2 ? iX2 : iX2 - gldi_desktop_get_width());
504 			cairo_dock_update_conf_file (cConfFilePath,
505 				G_TYPE_INT, "Desklet", "x position", iRelativePositionX,
506 				G_TYPE_BOOLEAN, "Desklet", "locked", FALSE,  // we'll probably want to move it
507 				G_TYPE_BOOLEAN, "Desklet", "no input", FALSE,
508 				G_TYPE_INVALID);
509 		}
510 	}
511 	else  // no instance yet, just copy the default conf file.
512 	{
513 		cairo_dock_add_conf_file (pModule->cConfFilePath, cConfFilePath);
514 	}
515 
516 	g_free (cUserDataDirPath);
517 
518 	return cConfFilePath;
519 }
520 
gldi_module_add_instance(GldiModule * pModule)521 void gldi_module_add_instance (GldiModule *pModule)
522 {
523 	// check that the module is already active
524 	if (pModule->pInstancesList == NULL)
525 	{
526 		cd_warning ("This module has not been instanciated yet");
527 		return ;
528 	}
529 
530 	// check that the module can be multi-instanciated
531 	if (! pModule->pVisitCard->bMultiInstance)
532 	{
533 		cd_warning ("This module can't be instanciated more than once");
534 		return ;
535 	}
536 
537 	// add a conf file
538 	gchar *cInstanceFilePath = gldi_module_add_conf_file (pModule);
539 
540 	// create an instance for it
541 	gldi_module_instance_new (pModule, cInstanceFilePath);  // takes ownership of 'cInstanceFilePath'.
542 }
543 
544 
545   //////////////////
546  /// GET CONFIG ///
547 //////////////////
548 
get_config(GKeyFile * pKeyFile,GldiModulesParam * pModules)549 static gboolean get_config (GKeyFile *pKeyFile, GldiModulesParam *pModules)
550 {
551 	gboolean bFlushConfFileNeeded = FALSE;
552 
553 	gsize length=0;
554 	pModules->cActiveModuleList = cairo_dock_get_string_list_key_value (pKeyFile, "System", "modules", &bFlushConfFileNeeded, &length, NULL, "Applets", "modules_0");
555 
556 	return bFlushConfFileNeeded;
557 }
558 
559   ////////////////////
560  /// RESET CONFIG ///
561 ////////////////////
562 
reset_config(GldiModulesParam * pModules)563 static void reset_config (GldiModulesParam *pModules)
564 {
565 	g_free (pModules->cActiveModuleList);
566 }
567 
568   ////////////
569  /// INIT ///
570 ////////////
571 
init(void)572 static void init (void)
573 {
574 	s_hModuleTable = g_hash_table_new_full (g_str_hash,
575 		g_str_equal,
576 		NULL,  // module name (points directly on the 'cModuleName' field of the module).
577 		NULL);  // module
578 }
579 
580   ///////////////
581  /// MANAGER ///
582 ///////////////
583 
init_object(GldiObject * obj,gpointer attr)584 static void init_object (GldiObject *obj, gpointer attr)
585 {
586 	GldiModule *pModule = (GldiModule*)obj;
587 	GldiModuleAttr *mattr = (GldiModuleAttr*)attr;
588 
589 	// check everything is ok
590 	g_return_if_fail (mattr != NULL && mattr->pVisitCard != NULL && mattr->pVisitCard->cModuleName);
591 
592 	if (g_hash_table_lookup (s_hModuleTable, mattr->pVisitCard->cModuleName) != NULL)
593 	{
594 		cd_warning ("a module with the name '%s' is already registered", mattr->pVisitCard->cModuleName);
595 		return;
596 	}
597 
598 	// set params
599 	pModule->pVisitCard = mattr->pVisitCard;
600 	mattr->pVisitCard = NULL;
601 	pModule->pInterface = mattr->pInterface;
602 	mattr->pInterface = NULL;
603 	if (pModule->cConfFilePath == NULL && pModule->pVisitCard->cConfFileName)
604 		pModule->cConfFilePath = g_strdup_printf ("%s/%s", pModule->pVisitCard->cShareDataDir, pModule->pVisitCard->cConfFileName);
605 
606 	// register the module
607 	g_hash_table_insert (s_hModuleTable, (gpointer)pModule->pVisitCard->cModuleName, pModule);
608 
609 	if (gldi_module_is_auto_loaded (pModule))  // a module that doesn't have an init/stop entry point, or that extends a manager; we'll activate it automatically (and before the others).
610 		s_AutoLoadedModules = g_list_prepend (s_AutoLoadedModules, pModule);
611 
612 	// notify everybody
613 	gldi_object_notify (&myModuleObjectMgr, NOTIFICATION_MODULE_REGISTERED, pModule->pVisitCard->cModuleName, TRUE);
614 }
615 
reset_object(GldiObject * obj)616 static void reset_object (GldiObject *obj)
617 {
618 	GldiModule *pModule = (GldiModule*)obj;
619 	if (pModule->pVisitCard == NULL)  // we didn't register it, pass
620 		return;
621 
622 	// deactivate the module, if it was active
623 	gldi_module_deactivate (pModule);
624 
625 	// unregister the module
626 	g_hash_table_remove (s_hModuleTable, pModule->pVisitCard->cModuleName);
627 
628 	// notify everybody
629 	gldi_object_notify (&myModuleObjectMgr, NOTIFICATION_MODULE_REGISTERED, pModule->pVisitCard->cModuleName, FALSE);
630 
631 	// free data
632 	if (pModule->handle)
633 		dlclose (pModule->handle);
634 	g_free (pModule->pInterface);
635 	cairo_dock_free_visit_card (pModule->pVisitCard);
636 }
637 
reload_object(GldiObject * obj,gboolean bReloadConf,G_GNUC_UNUSED GKeyFile * pKeyFile)638 static GKeyFile* reload_object (GldiObject *obj, gboolean bReloadConf, G_GNUC_UNUSED GKeyFile *pKeyFile)
639 {
640 	GldiModule *pModule = (GldiModule*)obj;
641 	GList *pElement;
642 	GldiModuleInstance *pInstance;
643 	for (pElement = pModule->pInstancesList; pElement != NULL; pElement = pElement->next)
644 	{
645 		pInstance = pElement->data;
646 		gldi_object_reload (GLDI_OBJECT(pInstance), bReloadConf);
647 	}
648 	return NULL;
649 }
650 
gldi_register_modules_manager(void)651 void gldi_register_modules_manager (void)
652 {
653 	// Manager
654 	memset (&myModulesMgr, 0, sizeof (GldiManager));
655 	gldi_object_init (GLDI_OBJECT(&myModulesMgr), &myManagerObjectMgr, NULL);
656 	myModulesMgr.cModuleName   = "Modules";
657 	// interface
658 	myModulesMgr.init          = init;
659 	myModulesMgr.load          = NULL;
660 	myModulesMgr.unload        = NULL;
661 	myModulesMgr.reload        = (GldiManagerReloadFunc)NULL;
662 	myModulesMgr.get_config    = (GldiManagerGetConfigFunc)get_config;
663 	myModulesMgr.reset_config  = (GldiManagerResetConfigFunc)reset_config;
664 	// Config
665 	memset (&myModulesParam, 0, sizeof (GldiModulesParam));
666 	myModulesMgr.pConfig = (GldiManagerConfigPtr)&myModulesParam;
667 	myModulesMgr.iSizeOfConfig = sizeof (GldiModulesParam);
668 	// data
669 	myModulesMgr.pData = (GldiManagerDataPtr)NULL;
670 	myModulesMgr.iSizeOfData = 0;
671 
672 	// Object Manager
673 	memset (&myModuleObjectMgr, 0, sizeof (GldiObjectManager));
674 	myModuleObjectMgr.cName         = "Module";
675 	myModuleObjectMgr.iObjectSize   = sizeof (GldiModule);
676 	// interface
677 	myModuleObjectMgr.init_object   = init_object;
678 	myModuleObjectMgr.reset_object  = reset_object;
679 	myModuleObjectMgr.reload_object = reload_object;
680 	// signals
681 	gldi_object_install_notifications (GLDI_OBJECT(&myModuleObjectMgr), NB_NOTIFICATIONS_MODULES);
682 }
683