static void _detach_icon (GldiContainer *pContainer, Icon *pIcon)
{
	CairoDesklet *pDesklet = CAIRO_DESKLET (pContainer);
	// remove icon
	pDesklet->icons = g_list_remove (pDesklet->icons, pIcon);
	
	// calculate icons
	_update_desklet_icons (pDesklet);
}
static gboolean _cairo_dock_for_one_desklet (gchar *cModuleName, CairoDockModule *pModule, gpointer *data)
{
	if (CAIRO_DOCK_IS_DESKLET (pModule->pContainer))
	{
		CairoDesklet *pDesklet = CAIRO_DESKLET (pModule->pContainer);
		CairoDockForeachDeskletFunc pCallback = data[0];
		gpointer user_data = data[1];
		
		return pCallback (pDesklet, pModule, user_data);
	}
	return FALSE;
}
static void _insert_icon (GldiContainer *pContainer, Icon *pIcon, G_GNUC_UNUSED gboolean bAnimateIcon)
{
	CairoDesklet *pDesklet = CAIRO_DESKLET (pContainer);
	// insert icon
	pDesklet->icons = g_list_insert_sorted (pDesklet->icons,
		pIcon,
		(GCompareFunc)cairo_dock_compare_icons_order);
	cairo_dock_set_icon_container (pIcon, pDesklet);
	
	// calculate icons
	_update_desklet_icons (pDesklet);
}
void cairo_dock_deactivate_module (CairoDockModule *module)
{
	if (module != NULL && module->bActive)
	{
		if (module->stopModule != NULL)
		{
			module->stopModule ();
		}
		module->bActive = FALSE;

		if (CAIRO_DOCK_IS_DESKLET (module->pContainer))
			cairo_dock_free_desklet (CAIRO_DESKLET (module->pContainer));
	}
}
static gboolean _cairo_desklet_animation_loop (GldiContainer *pContainer)
{
	CairoDesklet *pDesklet = CAIRO_DESKLET (pContainer);
	gboolean bContinue = FALSE;
	gboolean bUpdateSlowAnimation = FALSE;
	pContainer->iAnimationStep ++;
	if (pContainer->iAnimationStep * pContainer->iAnimationDeltaT >= CAIRO_DOCK_MIN_SLOW_DELTA_T)
	{
		bUpdateSlowAnimation = TRUE;
		pContainer->iAnimationStep = 0;
		pContainer->bKeepSlowAnimation = FALSE;
	}
	
	if (pDesklet->pIcon != NULL)
	{
		gboolean bIconIsAnimating = FALSE;
		
		if (bUpdateSlowAnimation)
		{
			gldi_object_notify (pDesklet->pIcon, NOTIFICATION_UPDATE_ICON_SLOW, pDesklet->pIcon, pDesklet, &bIconIsAnimating);
			pDesklet->container.bKeepSlowAnimation |= bIconIsAnimating;
		}
		
		gldi_object_notify (pDesklet->pIcon, NOTIFICATION_UPDATE_ICON, pDesklet->pIcon, pDesklet, &bIconIsAnimating);
		if (! bIconIsAnimating)
			pDesklet->pIcon->iAnimationState = CAIRO_DOCK_STATE_REST;
		else
			bContinue = TRUE;
	}
	
	if (bUpdateSlowAnimation)
	{
		gldi_object_notify (pDesklet, NOTIFICATION_UPDATE_SLOW, pDesklet, &pContainer->bKeepSlowAnimation);
	}
	
	gldi_object_notify (pDesklet, NOTIFICATION_UPDATE, pDesklet, &bContinue);
	
	if (! bContinue && ! pContainer->bKeepSlowAnimation)
	{
		pContainer->iSidGLAnimation = 0;
		return FALSE;
	}
	else
		return TRUE;
}
Icon *cairo_dock_find_icon_from_module (CairoDockModule *module, CairoContainer *pContainer)
{
	if (! module->bActive || pContainer == NULL)
		return NULL;

	if (CAIRO_DOCK_IS_DOCK (pContainer))
	{
		CairoDock *pDock = CAIRO_DOCK (pContainer);
		Icon *icon;
		GList *ic;
		for (ic = pDock->icons; ic != NULL; ic = ic->next)
		{
			icon = ic->data;
			if (icon->pModule == module)
				return icon;
		}
	}
	else if (CAIRO_DOCK_IS_DESKLET (pContainer))
	{
		CairoDesklet *pDesklet = CAIRO_DESKLET (pContainer);
		return pDesklet->pIcon;
	}
	return NULL;
}
void cairo_dock_reload_module (CairoDockModule *module, gboolean bReloadAppletConf)
{
	GError *erreur = NULL;
	g_return_if_fail (module != NULL);
	CairoContainer *pActualContainer = module->pContainer;
	gboolean bContainerTypeChanged = FALSE;
	module->pContainer = NULL;
	cd_message ("%s (%s, %d)", __func__, module->pVisitCard->cModuleName, bReloadAppletConf);

	//\______________ On tente de recharger le module.
	gboolean bModuleReloaded = FALSE;
	if (module->bActive && module->reloadModule != NULL)
	{
		Icon *pIcon = cairo_dock_find_icon_from_module (module, pActualContainer);

		GKeyFile *pKeyFile = NULL;
		CairoDockMinimalAppletConfig *pMinimalConfig = NULL;
		gboolean bToBeInserted = FALSE;
		gboolean bNeedFreeDesklet = FALSE;
		CairoContainer *pNewContainer = NULL;
		if (bReloadAppletConf && module->cConfFilePath != NULL)
		{
			pMinimalConfig = g_new0 (CairoDockMinimalAppletConfig, 1);
			pKeyFile = cairo_dock_pre_read_module_config (module, pMinimalConfig);

			if (pMinimalConfig->iDesiredIconWidth > -1)  // c'est une applet.
			{
				if (pIcon != NULL)
				{
					g_free (pIcon->acName);
					pIcon->acName = pMinimalConfig->cLabel;
					pMinimalConfig->cLabel = NULL;  // astuce.
					g_free (pIcon->acFileName);
					pIcon->acFileName = pMinimalConfig->cIconFileName;
					pMinimalConfig->cIconFileName = NULL;
				}

				if (pMinimalConfig->bIsDetached)  // l'applet est maintenant dans un desklet.
				{
					CairoDesklet *pDesklet;
					if (CAIRO_DOCK_IS_DOCK (pActualContainer))  // elle etait dans un dock.
					{
						cd_message ("le container a change (%s -> desklet)", pIcon->cParentDockName);
						gchar *cOldDockName = g_strdup (pIcon->cParentDockName);
						cairo_dock_detach_icon_from_dock (pIcon, CAIRO_DOCK (pActualContainer), g_bUseSeparator);
						if (CAIRO_DOCK (pActualContainer)->icons == NULL)
							cairo_dock_destroy_dock (CAIRO_DOCK (pActualContainer), cOldDockName, NULL, NULL);
						else
							cairo_dock_update_dock_size (CAIRO_DOCK (pActualContainer));
						g_free (cOldDockName);
						pDesklet = cairo_dock_create_desklet (pIcon, NULL, pMinimalConfig->bOnWidgetLayer);
						bContainerTypeChanged = TRUE;
					}
					else
					{
						pDesklet = CAIRO_DESKLET (pActualContainer);
					}
					pNewContainer = CAIRO_CONTAINER (pDesklet);
					cairo_dock_place_desklet (pDesklet, pMinimalConfig);
				}
				else  // l'applet est maintenant dans un dock.
				{
					gchar *cDockName = (pMinimalConfig->cDockName != NULL ? pMinimalConfig->cDockName : CAIRO_DOCK_MAIN_DOCK_NAME);
					CairoDock *pDock = cairo_dock_search_dock_from_name (cDockName);
					if (pDock == NULL)  // c'est un nouveau dock.
					{
						pDock = cairo_dock_create_new_dock (g_iWmHint, cDockName, NULL);
						cairo_dock_place_root_dock (pDock);
					}
					
					if (CAIRO_DOCK_IS_DESKLET (pActualContainer))  // elle etait dans un desklet.
					{
						bNeedFreeDesklet = TRUE;  // le desklet sera detruit apres le reload.
						cairo_dock_steal_interactive_widget_from_desklet (CAIRO_DESKLET (pActualContainer));
						///cairo_dock_free_desklet (CAIRO_DESKLET (pActualContainer));
						///pActualContainer = NULL;
						bToBeInserted = TRUE;  // l'icone sera inseree dans le dock avant le reload.
						bContainerTypeChanged = TRUE;
					}
					else  // elle etait deja dans un dock.
					{
						if (pActualContainer != CAIRO_CONTAINER (pDock))  // le dock a change.
						{
							cd_message ("le dock a change (%s -> %s)", pIcon->cParentDockName, cDockName);
							gchar *cOldDockName = g_strdup (pIcon->cParentDockName);
							cairo_dock_detach_icon_from_dock (pIcon, CAIRO_DOCK (pActualContainer), g_bUseSeparator);
							if (CAIRO_DOCK (pActualContainer)->icons == NULL)
								cairo_dock_destroy_dock (CAIRO_DOCK (pActualContainer), cOldDockName, NULL, NULL);
							else
								cairo_dock_update_dock_size (CAIRO_DOCK (pActualContainer));
							g_free (cOldDockName);
							bToBeInserted = TRUE;  // l'icone sera inseree dans le dock avant le reload.
						}
					}
					pNewContainer = CAIRO_CONTAINER (pDock);
				}
			}
		}
		else
			pNewContainer = pActualContainer;

		module->pContainer = pNewContainer;
		if (CAIRO_DOCK_IS_DOCK (pNewContainer) && pIcon != NULL)
		{
			if (pMinimalConfig != NULL)
			{
				pIcon->fWidth = pMinimalConfig->iDesiredIconWidth;
				pIcon->fHeight = pMinimalConfig->iDesiredIconHeight;
			}
			cairo_dock_load_one_icon_from_scratch (pIcon, pNewContainer);

			if (bToBeInserted)
			{
				CairoDock *pDock = CAIRO_DOCK (pNewContainer);
				cairo_dock_insert_icon_in_dock (pIcon, pDock, CAIRO_DOCK_UPDATE_DOCK_SIZE, CAIRO_DOCK_ANIMATE_ICON, CAIRO_DOCK_APPLY_RATIO, g_bUseSeparator);
				pIcon->cParentDockName = g_strdup (pMinimalConfig->cDockName);
				cairo_dock_start_animation (pIcon, pDock);
			}
			else
			{
				pIcon->fWidth *= CAIRO_DOCK (pActualContainer)->fRatio;
				pIcon->fHeight *= CAIRO_DOCK (pActualContainer)->fRatio;
				
				if (bReloadAppletConf)
					cairo_dock_update_dock_size (CAIRO_DOCK (pNewContainer));
			}
		}
		
		bModuleReloaded = module->reloadModule (pKeyFile, module->cConfFilePath, pNewContainer);
		
		if (pNewContainer != pActualContainer && CAIRO_DOCK_IS_DOCK (pNewContainer) && CAIRO_DOCK_IS_DOCK (pActualContainer) && pIcon != NULL)
		{
			cairo_dock_synchronize_one_sub_dock_position (pIcon, CAIRO_DOCK (pNewContainer), TRUE);
		}
		
		cairo_dock_free_minimal_config (pMinimalConfig);
		if (pKeyFile != NULL)
			g_key_file_free (pKeyFile);
		
		if (bNeedFreeDesklet)
			cairo_dock_free_desklet (CAIRO_DESKLET (pActualContainer));
	}
}
Icon * cairo_dock_activate_module (CairoDockModule *module, CairoDock *pDock, GError **erreur)
{
	cd_message ("%s (%s)", __func__, module->pVisitCard->cModuleName);
	if (module == NULL)
	{
		g_set_error (erreur, 1, 1, "%s () : empty module !", __func__);
		return NULL;
	}

	if (module->bActive)
	{
		g_set_error (erreur, 1, 1, "%s () : module %s is already active !", __func__, module->pVisitCard->cModuleName);
		return NULL;
	}

	GError *tmp_erreur = NULL;
	if (module->pModule == NULL)  // normalement impossible.
	{
		cairo_dock_open_module (module, &tmp_erreur);
		if (tmp_erreur != NULL)
		{
			g_propagate_error (erreur, tmp_erreur);
			return NULL;
		}
	}
	
	if (pDock == NULL)
	{
		module->bActive = TRUE;
		return NULL;
	}
	
	//\____________________ On cree le container de l'applet, ainsi que son icone.
	CairoContainer *pContainer = NULL;
	Icon *pIcon = NULL;
	GKeyFile *pKeyFile = NULL;
	CairoDockMinimalAppletConfig *pMinimalConfig = NULL;
	g_free (module->cConfFilePath);
	module->cConfFilePath = cairo_dock_check_conf_file_exists (module->pVisitCard->cUserDataDir, module->pVisitCard->cShareDataDir, module->pVisitCard->cConfFileName);
	if (module->cConfFilePath != NULL)
	{
		pMinimalConfig = g_new0 (CairoDockMinimalAppletConfig, 1);
		pKeyFile = cairo_dock_pre_read_module_config (module, pMinimalConfig);
		
		if (pMinimalConfig->iDesiredIconWidth > 0)  // le module a une icone, c'est donc une applet.
		{
			module->bCanDetach = pMinimalConfig->iDeskletWidth > 0;
			gchar *cDockName = (pMinimalConfig->cDockName != NULL ? pMinimalConfig->cDockName : CAIRO_DOCK_MAIN_DOCK_NAME);
			
			if (module->bCanDetach && pMinimalConfig->bIsDetached)
			{
				CairoDesklet *pDesklet = cairo_dock_create_desklet (NULL, NULL, pMinimalConfig->bOnWidgetLayer);
				pContainer = CAIRO_CONTAINER (pDesklet);
				cairo_dock_place_desklet (pDesklet, pMinimalConfig);
				while (gtk_events_pending ())
					gtk_main_iteration ();
			}
			else
			{
				CairoDock *pDock = cairo_dock_search_dock_from_name (cDockName);
				if (pDock == NULL)
				{
					pDock = cairo_dock_create_new_dock (g_iWmHint, cDockName, NULL);
					cairo_dock_place_root_dock (pDock);
				}
				pContainer = CAIRO_CONTAINER (pDock);
			}
			module->pContainer = pContainer;
			
			int iIconWidth, iIconHeight;
			if (CAIRO_DOCK_IS_DOCK (pContainer))
			{
				iIconWidth = pMinimalConfig->iDesiredIconWidth;
				iIconHeight = pMinimalConfig->iDesiredIconHeight;
			}
			else  // l'applet creera la surface elle-meme, car on ne sait ni la taille qu'elle voudra lui donner, ni meme si elle l'utilisera !
			{
				iIconWidth = -1;
				iIconHeight = -1;
			}
			pIcon = cairo_dock_create_icon_for_applet (pContainer,
				iIconWidth,
				iIconHeight,
				pMinimalConfig->cLabel,
				pMinimalConfig->cIconFileName,
				module);
			pIcon->fOrder = pMinimalConfig->fOrder;
			pIcon->cParentDockName = g_strdup (cDockName);
			if (CAIRO_DOCK_IS_DESKLET (pContainer))
			{
				CairoDesklet *pDesklet = CAIRO_DESKLET (pContainer);
				pDesklet->pIcon = pIcon;
				///gtk_widget_queue_draw (pContainer->pWidget);
			}
			cairo_dock_free_minimal_config (pMinimalConfig);
		}
	}

	//\____________________ On initialise le module.
	if (CAIRO_DOCK_IS_DOCK (pContainer))
	{
		pIcon->fWidth *= CAIRO_DOCK (pContainer)->fRatio;
		pIcon->fHeight *= CAIRO_DOCK (pContainer)->fRatio;
	}
	module->initModule (pKeyFile, pIcon, pContainer, module->cConfFilePath, &tmp_erreur);
	if (CAIRO_DOCK_IS_DOCK (pContainer))
	{
		pIcon->fWidth /= CAIRO_DOCK (pContainer)->fRatio;
		pIcon->fHeight /= CAIRO_DOCK (pContainer)->fRatio;
	}
	if (pKeyFile != NULL)
		g_key_file_free (pKeyFile);
	if (tmp_erreur != NULL)
	{
		g_propagate_error (erreur, tmp_erreur);
		return NULL;
	}

	module->bActive = TRUE;
	return pIcon;
}
CairoDesklet *cairo_dock_get_desklet_by_Xid (Window Xid)
{
	CairoDockModule *pModule = cairo_dock_foreach_desklet ((CairoDockForeachDeskletFunc) _cairo_dock_test_one_desklet_Xid, &Xid);
	return (pModule != NULL ? CAIRO_DESKLET (pModule->pContainer) : NULL);;
}