static void _get_theme (void)
{
    // get the user images first, as they overwrite the theme.
    if (myConfig.cEmptyUserImage != NULL)
    {
        gchar *cPath = cairo_dock_search_icon_s_path (myConfig.cEmptyUserImage, CAIRO_DOCK_DEFAULT_ICON_SIZE);
        if (! g_file_test (cPath, G_FILE_TEST_EXISTS))
        {
            g_free (myConfig.cEmptyUserImage);
            myConfig.cEmptyUserImage = NULL;
        }
        g_free (cPath);
    }
    if (myConfig.cFullUserImage != NULL)
    {
        gchar *cPath = cairo_dock_search_icon_s_path (myConfig.cFullUserImage, CAIRO_DOCK_DEFAULT_ICON_SIZE);
        if (! g_file_test (cPath, G_FILE_TEST_EXISTS))
        {
            g_free (myConfig.cFullUserImage);
            myConfig.cFullUserImage = NULL;
        }
        g_free (cPath);
    }
    // if a theme is defined, and user images are not defined, use the theme.
    if (myConfig.cThemePath != NULL)
    {
        if (myConfig.cEmptyUserImage == NULL)
        {
            myConfig.cEmptyUserImage = g_strdup_printf ("%s/%s", myConfig.cThemePath, "trashcan_empty.svg");
            if (! g_file_test (myConfig.cEmptyUserImage, G_FILE_TEST_EXISTS))
            {
                g_free (myConfig.cEmptyUserImage);
                myConfig.cEmptyUserImage = g_strdup_printf ("%s/%s", myConfig.cThemePath, "trashcan_empty.png");
                if (! g_file_test (myConfig.cEmptyUserImage, G_FILE_TEST_EXISTS))  // no svg nor png, use the default theme.
                {
                    g_free (myConfig.cEmptyUserImage);
                    myConfig.cEmptyUserImage = g_strdup (MY_APPLET_SHARE_DATA_DIR"/themes/default/trashcan_empty.svg");
                    cd_warning ("using the default theme for Dustbin, as neither the user image (%s) nor the theme (%s) are valid", myConfig.cEmptyUserImage, myConfig.cThemePath);
                }
            }
        }
        if (myConfig.cFullUserImage == NULL)
        {
            myConfig.cFullUserImage = g_strdup_printf ("%s/%s", myConfig.cThemePath, "trashcan_full.svg");
            if (! g_file_test (myConfig.cFullUserImage, G_FILE_TEST_EXISTS))
            {
                g_free (myConfig.cFullUserImage);
                myConfig.cFullUserImage = g_strdup_printf ("%s/%s", myConfig.cThemePath, "trashcan_full.png");
                if (! g_file_test (myConfig.cFullUserImage, G_FILE_TEST_EXISTS))
                {
                    g_free (myConfig.cFullUserImage);
                    myConfig.cFullUserImage = g_strdup (MY_APPLET_SHARE_DATA_DIR"/themes/default/trashcan_full.svg");
                    cd_warning ("using the default theme for Dustbin, as neither the user image (%s) nor the theme (%s) are valid", myConfig.cFullUserImage, myConfig.cThemePath);
                }
            }
        }
    }
}
static void _cd_switcher_add_window_on_viewport (Icon *pIcon, int iNumDesktop, int iNumViewportX, int iNumViewportY, GtkWidget *pMenu)
{
	//g_print (" + %s\n", pIcon->cName);
	
	// on cree une copie de la surface de l'icone a la taille du menu.
	GdkPixbuf *pixbuf = cairo_dock_icon_buffer_to_pixbuf (pIcon);
	if (pixbuf == NULL)  // icon not loaded (because not in a dock, because inhibited)
	{
		const gchar *cIcon = cairo_dock_get_class_icon (pIcon->cClass);
		gint iDesiredIconSize = cairo_dock_search_icon_size (GTK_ICON_SIZE_LARGE_TOOLBAR); // 24px
		gchar *cIconPath = cairo_dock_search_icon_s_path (cIcon, iDesiredIconSize);
		if (cIconPath)
		{
			pixbuf = gdk_pixbuf_new_from_file_at_size (cIconPath,
				iDesiredIconSize,
				iDesiredIconSize,
				NULL);
		}
	}
	
	// on ajoute une entree au menu avec le pixbuf.
	gchar *cLabel = cairo_dock_cut_string (pIcon->cName, 50);
	GtkWidget *pMenuItem = gldi_menu_add_item (pMenu, cLabel, "", G_CALLBACK (_show_window), pIcon);
	g_free (cLabel);
	
	if (pixbuf)
	{
		GtkWidget *image = gtk_image_new_from_pixbuf (pixbuf);
		gldi_menu_item_set_image (pMenuItem, image);
		g_object_unref (pixbuf);
	}
}
void cd_indicator_set_icon (CDAppletIndicator *pIndicator, const gchar *cStatusIcon)
{
    GldiModuleInstance *myApplet = pIndicator->pApplet;
    if (cStatusIcon != pIndicator->cStatusIcon)
    {
        g_free (pIndicator->cStatusIcon);
        pIndicator->cStatusIcon = g_strdup (cStatusIcon);
    }
    if (cStatusIcon == NULL)
        return;

    int iWidth, iHeight;
    cairo_dock_get_icon_extent (myIcon, &iWidth, &iHeight);
    const gchar *cIconName = cStatusIcon;
    gchar *tmp_icon_name = NULL;
    gchar *cIconPath = cairo_dock_search_icon_s_path (cIconName, MAX (iWidth, iHeight));  // on regarde si l'icone sera trouvee.
    gchar *cIconPathFallback = NULL;
    if (cIconPath == NULL)  // l'icone ne sera pas trouvee, on regarde si ce n'est pas une icone en carton d'Ubuntu.
    {
        gchar *str = g_strstr_len (cIconName, -1, "-panel");
        if (str)
        {
            tmp_icon_name = g_strndup (cIconName, str - cIconName);
            cIconName = tmp_icon_name;
            cIconPath = cairo_dock_search_icon_s_path (cIconName, MAX (iWidth, iHeight));
        }
    }
    if (cIconPath == NULL)  // l'icone ne sera pas trouvee, on met une icone par defaut.
    {
        gboolean bAddSuffix = (!g_str_has_suffix (cIconName, ".png") && !g_str_has_suffix (cIconName, ".svg"));
        cIconPathFallback = g_strdup_printf ("%s/%s%s", myApplet->pModule->pVisitCard->cShareDataDir, cIconName, bAddSuffix ? ".svg" : "");
    }

    cd_debug ("set %s", cIconPathFallback ? cIconPathFallback : cIconName);
    //CD_APPLET_SET_IMAGE_ON_MY_ICON (cIconPathFallback ? cIconPathFallback : cIconName);
    cairo_dock_set_image_on_icon_with_default (myDrawContext,
            cIconPathFallback ? cIconPathFallback : cIconName,
            myIcon,
            myContainer,
            myApplet->pModule->pVisitCard->cIconFilePath);

    g_free (tmp_icon_name);
    g_free (cIconPath);
    g_free (cIconPathFallback);
}
/* Applique la surface correspondant a un etat sur l'icone.
 */
void cd_musicplayer_apply_status_surface (MyPlayerStatus iStatus)
{
	cd_debug ("%s (%d)", __func__, iStatus);
	g_return_if_fail (iStatus < PLAYER_NB_STATUS);
	gboolean bUse3DTheme = (CD_APPLET_MY_CONTAINER_IS_OPENGL && myConfig.bOpenglThemes);
	cairo_surface_t *pSurface = myData.pSurfaces[iStatus];
	
	// load the surface if not already in cache
	if (pSurface == NULL)
	{
		gchar *cUserIcon = myConfig.cUserImage[iStatus];
		if (cUserIcon != NULL)  // l'utilisateur a defini une icone perso pour ce statut => on essaye de la charger.
		{
			gchar *cUserImagePath = cairo_dock_search_icon_s_path (cUserIcon, MAX (myIcon->image.iWidth, myIcon->image.iHeight));
			myData.pSurfaces[iStatus] = CD_APPLET_LOAD_SURFACE_FOR_MY_APPLET (cUserImagePath ? cUserImagePath : cUserIcon);  // si on a trouve une icone, on la prend, sinon on considere le fichier comme une image.
			g_free (cUserImagePath);
		}
		if (myData.pSurfaces[iStatus] == NULL)  // pas d'icone perso pour ce statut, ou l'icone specifiee n'a pas ete trouvee ou pas ete chargee => on prend l'icone par defaut.
		{
			const gchar **cIconName = (bUse3DTheme ? s_cDefaultIconName3D : s_cDefaultIconName);
			gchar *cImagePath = g_strdup_printf (MY_APPLET_SHARE_DATA_DIR"/%s", cIconName[iStatus]);
			myData.pSurfaces[iStatus] = CD_APPLET_LOAD_SURFACE_FOR_MY_APPLET (cImagePath);
			g_free (cImagePath);
		}
		pSurface = myData.pSurfaces[iStatus];
		g_return_if_fail (pSurface != NULL);
	}
	
	// apply the surface
	if (bUse3DTheme)  // 3D theme -> make a transition
	{
		if (myData.iPrevTextureCover != 0)
			_cairo_dock_delete_texture (myData.iPrevTextureCover);
		myData.iPrevTextureCover = myData.TextureCover;
		myData.TextureCover = cairo_dock_create_texture_from_surface (pSurface);
		if (myData.iPrevTextureCover != 0)
		{
			myData.iCoverTransition = NB_TRANSITION_STEP;
			cairo_dock_launch_animation (myContainer);
		}
		else
		{
			cd_opengl_render_to_texture (myApplet);
			CD_APPLET_REDRAW_MY_ICON;
		}
	}
	else  // just apply the surface (we could make a transition too ...)
	{
		CD_APPLET_SET_SURFACE_ON_MY_ICON (pSurface);
	}
}
/**
 * Look for an icon for GUI
 */
gchar * cairo_dock_get_icon_for_gui (const gchar *cGroupName, const gchar *cIcon, const gchar *cShareDataDir, gint iSize, gboolean bFastLoad)
{
	gchar *cIconPath = NULL;

	if (cIcon)
	{
		if (*cIcon == '/')  // on ecrase les chemins des icons d'applets.
		{
			if (bFastLoad)
				return g_strdup (cIcon);

			cIconPath = g_strdup_printf ("%s/config-panel/%s.png", g_cCairoDockDataDir, cGroupName);
			if (!g_file_test (cIconPath, G_FILE_TEST_EXISTS))
			{
				g_free (cIconPath);
				cIconPath = g_strdup (cIcon);
			}
		}
		else  // categorie ou module interne.
		{
			if (! bFastLoad)
			{
				cIconPath = g_strconcat (g_cCairoDockDataDir, "/config-panel/", cIcon, NULL);
				if (!g_file_test (cIconPath, G_FILE_TEST_EXISTS))
				{
					g_free (cIconPath);
					cIconPath = g_strconcat (CAIRO_DOCK_SHARE_DATA_DIR"/icons/", cIcon, NULL);
					if (!g_file_test (cIconPath, G_FILE_TEST_EXISTS)) // if we just have the name of an application
					{
						g_free (cIconPath);
						cIconPath = NULL;
					}
				}
			}
			if (cIconPath == NULL)
			{
				cIconPath = cairo_dock_search_icon_s_path (cIcon, iSize);
				if (cIconPath == NULL) // maybe we don't have any icon with this name
					cIconPath = cShareDataDir ? g_strdup_printf ("%s/icon", cShareDataDir) : g_strdup (cIcon);
			}
		}
	}
	else if (cShareDataDir)
		cIconPath = g_strdup_printf ("%s/icon", cShareDataDir);

	return cIconPath;
}
void _init_disk_usage (Icon *pIcon, GldiModuleInstance *myApplet)
{
    // ensure the applet has a valid icon, in case the VFS didn't give us one.
    if (pIcon->cFileName == NULL)
        pIcon->cFileName = cairo_dock_search_icon_s_path (CD_SHORTCUT_DEFAULT_DRIVE_ICON_FILENAME, CAIRO_DOCK_DEFAULT_ICON_SIZE);

    if (pIcon->cCommand)
    {
        // set our private data for disk usage
        CDDiskUsage *pDiskUsage = g_new0 (CDDiskUsage, 1);
        pDiskUsage->iPrevAvail = -1;  // data not yet retrieved (0 bytes is a valid value for non writable disks).
        CD_APPLET_SET_MY_ICON_DATA (pIcon, pDiskUsage);

        // get the current disk usage
        cd_shortcuts_get_fs_stat (pIcon->cCommand, pDiskUsage);
    }
}
cairo_surface_t *cairo_dock_create_surface_from_class (gchar *cClass, cairo_t *pSourceContext, double fMaxScale, double *fWidth, double *fHeight)
{
	cd_debug ("%s (%s)", __func__, cClass);
	CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
	if (pClassAppli != NULL)
	{
		cd_debug ("bUseXIcon:%d", pClassAppli->bUseXIcon);
		if (pClassAppli->bUseXIcon)
			return NULL;
		
		GList *pElement;
		Icon *pInhibatorIcon;
		for (pElement = pClassAppli->pIconsOfClass; pElement != NULL; pElement = pElement->next)
		{
			pInhibatorIcon = pElement->data;
			cd_debug ("  %s", pInhibatorIcon->acName);
			if (! CAIRO_DOCK_IS_APPLET (pInhibatorIcon))
			{
				cd_message ("%s va fournir genereusement sa surface", pInhibatorIcon->acName);
				return cairo_dock_duplicate_inhibator_surface_for_appli (pSourceContext, pInhibatorIcon, fMaxScale, fWidth, fHeight);
			}
		}
	}
	
	gchar *cIconFilePath = cairo_dock_search_icon_s_path (cClass);
	if (cIconFilePath != NULL)
	{
		cd_debug ("on remplace l'icone X par %s", cIconFilePath);
		cairo_surface_t *pSurface = cairo_dock_create_surface_from_image (cIconFilePath,
			pSourceContext,
			1 + g_fAmplitude,
			g_tIconAuthorizedWidth[CAIRO_DOCK_APPLI],
			g_tIconAuthorizedHeight[CAIRO_DOCK_APPLI],
			CAIRO_DOCK_FILL_SPACE,
			fWidth, fHeight,
			NULL, NULL);
		g_free (cIconFilePath);
		return pSurface;
	}
	
	cd_debug ("classe %s prend l'icone X", cClass);
	
	return NULL;
}
static void _load_emblem (Icon *pIcon)
{
	const gchar *cImage = NULL;
	if (GLDI_OBJECT_IS_APPLET_ICON (pIcon))
	{
		cImage = GLDI_ICON_NAME_JUMP_TO;
	}
	else
	{
		cImage = GLDI_ICON_NAME_DELETE;
	}
	
	int iWidth, iHeight;
	cairo_dock_get_icon_extent (pIcon, &iWidth, &iHeight);
	gchar *cIcon = cairo_dock_search_icon_s_path (cImage, MAX (iWidth/2, iHeight/2));
	cairo_dock_free_image_buffer (s_pEmblem);
	s_pEmblem = cairo_dock_create_image_buffer (cIcon, iWidth/2, iHeight/2, 0);
	g_free (cIcon);
}
static void _load_image (Icon *icon)
{
	int iWidth = cairo_dock_icon_get_allocated_width (icon);
	int iHeight = cairo_dock_icon_get_allocated_height (icon);
	cairo_surface_t *pSurface = NULL;
	
	if (icon->pSubDock != NULL && icon->iSubdockViewType != 0)  // a stack rendering is specified, we'll draw it when the sub-icons will be loaded
	{
		pSurface = cairo_dock_create_blank_surface (iWidth, iHeight);
		cairo_dock_trigger_redraw_subdock_content_on_icon (icon);  // now that the icon has a surface/texture, we can draw the sub-dock content on it.
	}
	else if (icon->cFileName)  // else simply draw the image
	{
		gchar *cIconPath = cairo_dock_search_icon_s_path (icon->cFileName, MAX (iWidth, iHeight));
		if (cIconPath != NULL && *cIconPath != '\0')
			pSurface = cairo_dock_create_surface_from_image_simple (cIconPath,
				iWidth,
				iHeight);
		g_free (cIconPath);
	}
	cairo_dock_load_image_buffer_from_surface (&icon->image, pSurface, iWidth, iHeight);
}
static gchar *_cd_get_icon_path (GIcon *pIcon)
{
	gchar *cIconPath = NULL;
	if (G_IS_THEMED_ICON (pIcon))
	{
		const gchar * const *cFileNames = g_themed_icon_get_names (G_THEMED_ICON (pIcon));
		//cd_message ("icones possibles : %s\n", g_strjoinv (":", (gchar **) cFileNames));
		int i;
		for (i = 0; cFileNames[i] != NULL && cIconPath == NULL; i ++)
		{
			//cd_message (" une icone possible est : %s\n", cFileNames[i]);
			cIconPath = cairo_dock_search_icon_s_path (cFileNames[i]);
			//cd_message ("  chemin trouve : %s\n", cIconPath);
		}
	}
	else if (G_IS_FILE_ICON (pIcon))
	{
		GFile *pFile = g_file_icon_get_file (G_FILE_ICON (pIcon));
		cIconPath = g_file_get_basename (pFile);
		//cd_message (" file_icon => %s\n", cIconPath);
	}
	return cIconPath;
}
static gboolean _on_click_item (GtkWidget *pWidget, GdkEventButton* pButton, CDQuickBrowserItem *pItem)
{
	g_return_val_if_fail (pItem != NULL, FALSE);
	GldiModuleInstance *myApplet = pItem->pApplet;
	CD_APPLET_ENTER;

	if (pButton->button == 3) // right click
	{
		gchar *cUri = g_filename_to_uri (pItem->cPath, NULL, NULL);
		g_return_val_if_fail (cUri != NULL, FALSE);

		GtkWidget *pMenu = gldi_menu_new (NULL);
		
		GList *pApps = cairo_dock_fm_list_apps_for_file (cUri);
		if (pApps != NULL)
		{
			GtkWidget *pSubMenu = CD_APPLET_ADD_SUB_MENU_WITH_IMAGE (D_("Open with"), pMenu, GLDI_ICON_NAME_OPEN);

			cd_quick_browser_free_apps_list (myApplet);

			GList *a;
			gchar **pAppInfo;
			gchar *cIconPath;
			for (a = pApps; a != NULL; a = a->next)
			{
				pAppInfo = a->data;

				if (pAppInfo[2] != NULL)
					cIconPath = cairo_dock_search_icon_s_path (pAppInfo[2], cairo_dock_search_icon_size (GTK_ICON_SIZE_MENU));
				else
					cIconPath = NULL;

				gpointer *data = g_new (gpointer, 2);
				data[0] = pItem;
				data[1] = pAppInfo[1];
				myData.pAppList = g_list_prepend (myData.pAppList, data); // to save the exec command

				CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (pAppInfo[0], cIconPath, _cd_launch_with, pSubMenu, data);

				g_free (cIconPath);
				g_free (pAppInfo[0]);
				g_free (pAppInfo[2]);
				g_free (pAppInfo);
			}
			g_list_free (pApps);
		}
		CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (D_("Open parent folder"), GLDI_ICON_NAME_DIRECTORY, _cd_open_parent, pMenu, pItem);
		
		CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (D_("Copy the location"), GLDI_ICON_NAME_COPY, _cd_copy_location, pMenu, pItem);
		
		gtk_widget_show_all (pMenu);
		gtk_menu_popup (GTK_MENU (pMenu),
			NULL,
			NULL,
			NULL,  // popup on mouse.
			NULL,
			1,
			gtk_get_current_event_time ());
		g_free (cUri);
		CD_APPLET_LEAVE (TRUE); // do not remove quick_browser menu now
	}

	CD_APPLET_LEAVE (FALSE);
}
static void _fill_submenu_with_items (CDQuickBrowserItem *pRootItem, int iNbSubItemsAtOnce)
{
	GldiModuleInstance *myApplet = pRootItem->pApplet;
	GtkWidget *pMenu = pRootItem->pSubMenu;
	GList *pFirstItem = pRootItem->pCurrentItem;

	// static GtkTargetEntry s_pMenuItemTargets[] = { {(gchar*) "text/uri-list", 0, 0} }; // for drag and drop support

	CDQuickBrowserItem *pItem;
	gchar *cFileName;
	GtkWidget *pMenuItem;
	gchar *cName = NULL, *cURI = NULL, *cIconName = NULL;
	gboolean bIsDirectory;
	int iVolumeID;
	double fOrder;
	GList *l;
	int i;
	for (l = pFirstItem, i = 0; l != NULL && i < iNbSubItemsAtOnce; l = l->next, i ++)
	{
		pItem = l->data;
		
		//\______________ On cree l'entree avec son icone si necessaire.
		if (myConfig.bHasIcons)
		{
			cairo_dock_fm_get_file_info (pItem->cPath, &cName, &cURI, &cIconName, &bIsDirectory, &iVolumeID, &fOrder, 0);
			g_free (cName);
			cName = NULL;
			g_free (cURI);
			cURI = NULL;
		}

		cFileName = strrchr (pItem->cPath, '/');
		if (cFileName)
			cFileName ++;
		
		if (cIconName != NULL)
		{
			gchar *cPath = cairo_dock_search_icon_s_path (cIconName, cairo_dock_search_icon_size (GTK_ICON_SIZE_MENU));
			pMenuItem = gldi_menu_item_new (cFileName, cPath);
			g_free (cPath);
			g_free (cIconName);
			cIconName = NULL;
		}
		else
		{
			pMenuItem = gldi_menu_item_new (cFileName, "");
		}

		//\______________ On l'insere dans le menu.
		gtk_menu_shell_append  (GTK_MENU_SHELL (pMenu), pMenuItem);
		
		if (pItem->pSubMenu != NULL)
		{
			gtk_menu_item_set_submenu (GTK_MENU_ITEM (pMenuItem), pItem->pSubMenu);
		}
		else
		{
			//\______________ Add drag and drop support for files only
			gtk_drag_source_set (pMenuItem, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
				NULL, 0,
				GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
			
			gtk_drag_source_add_text_targets (pMenuItem);
			gtk_drag_source_add_uri_targets (pMenuItem);
			
			g_signal_connect (G_OBJECT (pMenuItem), "button-release-event", G_CALLBACK(_on_click_item), pItem); // left and right click
			g_signal_connect (G_OBJECT (pMenuItem), "drag-begin", G_CALLBACK (_drag_begin), pMenuItem); // to create pixbuf
			g_signal_connect (G_OBJECT (pMenuItem), "drag-data-get", G_CALLBACK (_drag_data_get), pItem); // when the item is dropped
		}
		g_signal_connect (G_OBJECT (pMenuItem), "activate", G_CALLBACK(_on_activate_item), pItem); // select or over (submenu)
	}
	pRootItem->pCurrentItem = l;
}
static void _take_screenshot (CDScreenshotOptions *pOptions)
{
    g_free (myData.cCurrentUri);
    myData.cCurrentUri = _make_screenshot (pOptions ? pOptions->bActiveWindow : FALSE,
                                           pOptions ? pOptions->cFolder : NULL,
                                           pOptions ? pOptions->cName   : NULL);

    if (myData.cCurrentUri)
    {
        // demands the attention; it helps localizing the menu and it shows the icon if the dock is hidden.
        if (myData.bFromShortkey)
        {
            CD_APPLET_DEMANDS_ATTENTION ("pulse", 1000);
        }

        // pop up the menu
        GtkWidget *pMenu = gldi_menu_new (myIcon);

        CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (D_("Copy the location"), GLDI_ICON_NAME_COPY, _cd_copy_location, pMenu, NULL);

        CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (D_("Open"), GLDI_ICON_NAME_FILE, _cd_open, pMenu, NULL);

        if (myData.pAppList == NULL)
        {
            /* It's always a .png file always made by Cairo
             *  ==> no need to recreate the list, to search for icons, etc.
             * But we have to use the right icon and then reverse the list
             */
            myData.pAppList = cairo_dock_fm_list_apps_for_file (myData.cCurrentUri);
            GList *a;
            gchar **pAppInfo; // name, icon, cmd
            gchar *cIconPath;
            for (a = myData.pAppList; a != NULL; a = a->next)
            {
                pAppInfo = a->data;
                if (pAppInfo[2] != NULL)
                {
                    cIconPath = cairo_dock_search_icon_s_path (pAppInfo[2],
                                cairo_dock_search_icon_size (GTK_ICON_SIZE_MENU));
                    g_free (pAppInfo[2]);
                    pAppInfo[2] = cIconPath;
                }
            }
            myData.pAppList = g_list_reverse (myData.pAppList); // it's normal, we received a reversed list
        }
        if (myData.pAppList)
        {
            GtkWidget *pSubMenu = CD_APPLET_ADD_SUB_MENU_WITH_IMAGE (D_("Open with"), pMenu, GLDI_ICON_NAME_OPEN);
            GList *pItem;
            gchar **pAppInfo;
            for (pItem = myData.pAppList; pItem != NULL; pItem = g_list_next (pItem))
            {
                pAppInfo = pItem->data;
                CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (pAppInfo[0], pAppInfo[2], _cd_launch_with, pSubMenu, pAppInfo[1]);
            }
        }
        CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (D_("Open parent folder"), GLDI_ICON_NAME_DIRECTORY, _cd_open_parent, pMenu, NULL);

        CD_APPLET_POPUP_MENU_ON_MY_ICON (pMenu);

        gtk_menu_shell_select_first (GTK_MENU_SHELL (pMenu), FALSE);  // must be done here, after the menu has been realized.

        // when the menu disappear, set the icon back to normal.
        g_signal_connect (G_OBJECT (pMenu),
                          "deactivate",
                          G_CALLBACK (_on_menu_deactivated),
                          NULL);
    }
    else  // show an error message
    {
        gldi_dialog_show_temporary_with_icon (D_("Unable to take a screenshot"), myIcon, myContainer, 7000, MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
    }
}
void cd_xkbd_update_icon (const gchar *cGroupName, const gchar *cShortGroupName, gboolean bRedrawSurface)
{
	//g_print ("%s (%s;%s;%d)\n", __func__, cGroupName, cShortGroupName, bRedrawSurface);
	
	if (bRedrawSurface)  // group has changed -> update the icon and label
	{
		if (! cShortGroupName)
		{
			cShortGroupName = myData.cShortGroupName;
		}
		else
		{
			g_free (myData.cShortGroupName);
			myData.cShortGroupName = g_strdup (cShortGroupName);
		}
		if (! cGroupName)
		{
			cGroupName = myData.cGroupName;
		}
		else
		{
			g_free (myData.cGroupName);
			myData.cGroupName = g_strdup (cGroupName);
		}
		
		//\__________________ On sauvegarde l'ancienne surface/texture.
		cairo_dock_free_image_buffer (myData.pOldImage);
		myData.pOldImage = myData.pCurrentImage;
		myData.pCurrentImage = NULL;
		
		//\__________________ On cree la nouvelle surface (la taille du texte peut avoir change).
		int iWidth, iHeight;
		CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
		if (iWidth <= 1 && iHeight <= 1)  // peut arriver au lancement en mode desklet.
		{
			return;
		}
		int w, h;
		cairo_surface_t *pSurface = cairo_dock_create_surface_from_text_full (cShortGroupName,
			&myConfig.textDescription,
			1.,
			0,  /// iWidth
			&w, &h);
		myData.pCurrentImage = g_new0 (CairoDockImageBuffer, 1);
		cairo_dock_load_image_buffer_from_surface (myData.pCurrentImage, pSurface, w, h);
		
		//\__________________ On lance une transition entre ancienne et nouvelle surface/texture, ou on dessine direct.
		if (myConfig.iTransitionDuration != 0 && myData.pOldImage != NULL)
		{
			CD_APPLET_SET_TRANSITION_ON_MY_ICON (cd_xkbd_render_step_cairo,
				cd_xkbd_render_step_opengl,
				g_bUseOpenGL,  // bFastPace : vite si opengl, lent si cairo.
				myConfig.iTransitionDuration,
				TRUE);  // bRemoveWhenFinished
		}
		else
		{
			if (CD_APPLET_MY_CONTAINER_IS_OPENGL)
			{
				CD_APPLET_START_DRAWING_MY_ICON_OR_RETURN ();
				cd_xkbd_render_step_opengl (myIcon, myApplet);	
				CD_APPLET_FINISH_DRAWING_MY_ICON;
			}
			else
			{
				cd_xkbd_render_step_cairo (myIcon, myApplet);
			}
			CD_APPLET_REDRAW_MY_ICON;
		}
		
		//\__________________ update the label.
		CD_APPLET_SET_NAME_FOR_MY_ICON (cGroupName);
	}
	else  // only the indicators have changed -> trigger a redraw event only (overlay update).
	{
		CD_APPLET_REDRAW_MY_ICON;
	}
	
	//\__________________ lock indicators
	if (myConfig.bShowKbdIndicator)
	{
		cd_debug ("XKBD: caps-lock: %d; num-lock: %d", myData.iCurrentIndic & 1, myData.iCurrentIndic & 2);
		if (myData.iCurrentIndic & 1)  // caps-lock
		{
			if (! (myData.iPreviousIndic & 1)) // TODO: cairo_dock_search_icon_s_path in init? or here the first time (save to data) and reset in reload?
			{
				if (myConfig.cEmblemCapsLock && (myData.cEmblemCapsLock ||
					(myData.cEmblemCapsLock = cairo_dock_search_icon_s_path (myConfig.cEmblemCapsLock, // search for an icon only the first time
						MAX (myIcon->image.iWidth/2, myIcon->image.iHeight/2)))))
					CD_APPLET_ADD_OVERLAY_ON_MY_ICON (myData.cEmblemCapsLock, CAIRO_OVERLAY_UPPER_RIGHT);
				else
					CD_APPLET_ADD_OVERLAY_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/caps-lock.png", CAIRO_OVERLAY_UPPER_RIGHT);
			}
		}
		else
		{
			if (myData.iPreviousIndic & 1)
				CD_APPLET_REMOVE_OVERLAY_ON_MY_ICON (CAIRO_OVERLAY_UPPER_RIGHT);
		}

		if (myData.iCurrentIndic & 2)  // num-lock
		{
			if (! (myData.iPreviousIndic & 2))
			{
				if (myConfig.cEmblemNumLock &&(myData.cEmblemNumLock ||
					(myData.cEmblemNumLock = cairo_dock_search_icon_s_path (myConfig.cEmblemNumLock,
						MAX (myIcon->image.iWidth/2, myIcon->image.iHeight/2)))))
					CD_APPLET_ADD_OVERLAY_ON_MY_ICON (myData.cEmblemNumLock, CAIRO_OVERLAY_UPPER_LEFT);
				else
					CD_APPLET_ADD_OVERLAY_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/num-lock.png", CAIRO_OVERLAY_UPPER_LEFT);
			}
		}
		else
		{
			if (myData.iPreviousIndic & 2)
				CD_APPLET_REMOVE_OVERLAY_ON_MY_ICON (CAIRO_OVERLAY_UPPER_LEFT);
		}
		myData.iPreviousIndic = myData.iCurrentIndic;
	}
}
static Icon * _cd_shortcuts_get_icon (gchar *cFileName, const gchar *cUserName, double fCurrentOrder)
{
	cd_debug ("New icon: %s, %s, %f", cFileName, cUserName, fCurrentOrder);

	/* Nautilus adds custom prefixes which are not supported by gvfs...
	 * gvfs-integration plugin can read x-nautilus-desktop but not others, e.g.:
	 * x-nautilus-search://0/ => specific to Nautilus: open these URI with it.
	 * Note that all these URI have a user-name
	 */
	if (g_str_has_prefix (cFileName, "x-nautilus-")
	    && ! g_str_has_prefix (cFileName, "x-nautilus-desktop://"))
	{
		Icon *pNewIcon = cairo_dock_create_dummy_launcher (
			cUserName ? g_strdup (cUserName) : g_strdup (cFileName),
			cairo_dock_search_icon_s_path (
				CD_SHORTCUT_DEFAULT_DIRECTORY_ICON_FILENAME,
				CAIRO_DOCK_DEFAULT_ICON_SIZE),
			g_strdup_printf ("nautilus %s", cFileName),
			NULL,
			fCurrentOrder);
		pNewIcon->iGroup = CD_BOOKMARK_GROUP;
		pNewIcon->cBaseURI = cFileName;
		pNewIcon->iVolumeID = CD_VOLUME_ID_BOOKMARK_CMD;
		return pNewIcon;
	}

	gchar *cName, *cRealURI, *cIconName;
	gboolean bIsDirectory;
	gint iVolumeID;
	gdouble fOrder;
	if (! cairo_dock_fm_get_file_info (cFileName, &cName, &cRealURI, &cIconName,
		&bIsDirectory, &iVolumeID, &fOrder, CAIRO_DOCK_FM_SORT_BY_NAME))
		return NULL;
	if (cUserName != NULL)
	{
		g_free (cName);
		if (cName == NULL)  // a bookmark on a unmounted system or a folder that doesn't exist any more
			cName = g_strdup_printf ("%s\n[%s]", cUserName, D_("Unmounted"));
		else
			cName = g_strdup (cUserName);
	}
	else if (cName == NULL)  // a bookmark on a unmounted system
	{
		gchar *cGuessedName = g_path_get_basename (cFileName);
		cairo_dock_remove_html_spaces (cGuessedName); // or: g_uri_unescape_string
		cName = g_strdup_printf ("%s\n[%s]", cGuessedName, D_("Unmounted"));
		g_free (cGuessedName);
	}
	if (cRealURI == NULL)
		cRealURI = g_strdup (cFileName);
	if (cIconName == NULL)
		cIconName = cairo_dock_search_icon_s_path (
			CD_SHORTCUT_DEFAULT_DIRECTORY_ICON_FILENAME,
			CAIRO_DOCK_DEFAULT_ICON_SIZE); // should be the default icon

	Icon *pNewIcon = cairo_dock_create_dummy_launcher (cName,
		cIconName,
		cRealURI,
		NULL,
		fCurrentOrder);
	pNewIcon->iGroup = CD_BOOKMARK_GROUP;
	pNewIcon->cBaseURI = cFileName;
	pNewIcon->iVolumeID = iVolumeID;
	return pNewIcon;
}
void gldi_dialog_init_internals (CairoDialog *pDialog, CairoDialogAttr *pAttribute)
{
	pDialog->container.iface.animation_loop = _animation_loop;
	
	//\________________ set up the window
	GtkWidget *pWindow = pDialog->container.pWidget;
	gtk_window_set_title (GTK_WINDOW (pWindow), "cairo-dock-dialog");
	if (! pAttribute->pInteractiveWidget && ! pAttribute->pActionFunc)  // not an interactive dialog
		gtk_window_set_type_hint (GTK_WINDOW (pDialog->container.pWidget), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);  // pour ne pas prendre le focus.
	
	gtk_widget_add_events (pWindow, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
	gtk_window_resize (GTK_WINDOW (pWindow), CAIRO_DIALOG_MIN_SIZE, CAIRO_DIALOG_MIN_SIZE);
	gtk_window_set_keep_above (GTK_WINDOW (pWindow), TRUE);
	
	pDialog->pIcon = pAttribute->pIcon;
	if (pAttribute->bForceAbove)  // try to force it above other windows (with most WM, it will still stay below fullscreen windows).
	{
		gtk_window_set_keep_above (GTK_WINDOW (pDialog->container.pWidget), TRUE);
		gtk_window_set_type_hint (GTK_WINDOW (pDialog->container.pWidget), GDK_WINDOW_TYPE_HINT_DOCK);  // should be called before the window becomes visible
	}
	
	//\________________ load the message
	if (pAttribute->cText != NULL)
	{
		pDialog->cText = g_strdup (pAttribute->cText);  // it may be a const string, so duplicate it
		pDialog->pTextBuffer = _cairo_dock_create_dialog_text_surface (pAttribute->cText,
			pAttribute->bUseMarkup,
			&pDialog->iTextWidth, &pDialog->iTextHeight);
		///pDialog->iTextTexture = cairo_dock_create_texture_from_surface (pDialog->pTextBuffer);
	}
	pDialog->bUseMarkup = pAttribute->bUseMarkup;  // remember this attribute, in case another text is set (with cairo_dock_set_dialog_message).

	//\________________ load the icon
	if (pAttribute->cImageFilePath != NULL)
	{
		pDialog->pIconBuffer = _cairo_dock_create_dialog_icon_surface (pAttribute->cImageFilePath, pAttribute->pIcon, pAttribute->iIconSize, &pDialog->iIconSize);
		///pDialog->iIconTexture = cairo_dock_create_texture_from_surface (pDialog->pIconBuffer);
	}

	//\________________ load the interactive widget
	if (pAttribute->pInteractiveWidget != NULL)
	{
		pDialog->pInteractiveWidget = pAttribute->pInteractiveWidget;
		
		GtkRequisition requisition;
		gtk_widget_get_preferred_size (pAttribute->pInteractiveWidget, &requisition, NULL);
		pDialog->iInteractiveWidth = requisition.width;
		pDialog->iInteractiveHeight = requisition.height;
	}
	
	//\________________ load the buttons
	pDialog->pUserData = pAttribute->pUserData;
	pDialog->pFreeUserDataFunc = pAttribute->pFreeDataFunc;
	if (pAttribute->cButtonsImage != NULL && pAttribute->pActionFunc != NULL)
	{
		int i;
		for (i = 0; pAttribute->cButtonsImage[i] != NULL; i++);
		
		pDialog->iNbButtons = i;
		pDialog->action_on_answer = pAttribute->pActionFunc;
		pDialog->pButtons = g_new0 (CairoDialogButton, pDialog->iNbButtons);
		const gchar *cButtonImage;
		for (i = 0; i < pDialog->iNbButtons; i++)
		{
			cButtonImage = pAttribute->cButtonsImage[i];
			if (strcmp (cButtonImage, "ok") == 0)
			{
				pDialog->pButtons[i].iDefaultType = 1;
			}
			else if (strcmp (cButtonImage, "cancel") == 0)
			{
				pDialog->pButtons[i].iDefaultType = 0;
			}
			else
			{
				gchar *cButtonPath;
				if (*cButtonImage != '/')
					cButtonPath = cairo_dock_search_icon_s_path (cButtonImage,
						MAX (myDialogsParam.iDialogButtonWidth, myDialogsParam.iDialogButtonHeight));
				else
					cButtonPath = (gchar*)cButtonImage;
				pDialog->pButtons[i].pSurface = cairo_dock_create_surface_from_image_simple (cButtonPath,
					myDialogsParam.iDialogButtonWidth,
					myDialogsParam.iDialogButtonHeight);
				if (cButtonPath != cButtonImage)
					g_free (cButtonPath);
				///pDialog->pButtons[i].iTexture = cairo_dock_create_texture_from_surface (pDialog->pButtons[i].pSurface);
			}
		}
	}
	else
	{
		pDialog->bNoInput = pAttribute->bNoInput;
	}
	
	//\________________ set a decorator.
	cairo_dock_set_dialog_decorator_by_name (pDialog, (pAttribute->cDecoratorName ? pAttribute->cDecoratorName : myDialogsParam.cDecoratorName));
	if (pDialog->pDecorator != NULL)
		pDialog->pDecorator->set_size (pDialog);
	
	//\________________ Maintenant qu'on connait tout, on calcule les tailles des divers elements.
	_compute_dialog_sizes (pDialog);
	pDialog->container.iWidth = pDialog->iBubbleWidth + pDialog->iLeftMargin + pDialog->iRightMargin;
	pDialog->container.iHeight = pDialog->iBubbleHeight + pDialog->iTopMargin + pDialog->iBottomMargin + pDialog->iMinBottomGap;
	
	//\________________ On reserve l'espace pour les decorations.
	GtkWidget *pMainHBox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
	gtk_container_add (GTK_CONTAINER (pDialog->container.pWidget), pMainHBox);
	pDialog->pLeftPaddingBox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
	g_object_set (pDialog->pLeftPaddingBox, "width-request", pDialog->iLeftMargin, NULL);
	gtk_box_pack_start (GTK_BOX (pMainHBox),
		pDialog->pLeftPaddingBox,
		FALSE,
		FALSE,
		0);

	pDialog->pWidgetLayout = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
	gtk_box_pack_start (GTK_BOX (pMainHBox),
		pDialog->pWidgetLayout,
		FALSE,
		FALSE,
		0);

	pDialog->pRightPaddingBox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
	g_object_set (pDialog->pRightPaddingBox, "width-request", pDialog->iRightMargin, NULL);
	gtk_box_pack_start (GTK_BOX (pMainHBox),
		pDialog->pRightPaddingBox,
		FALSE,
		FALSE,
		0);
	
	//\________________ On reserve l'espace pour les elements.
	if (pDialog->container.bDirectionUp)
		pDialog->pTopWidget = _cairo_dock_add_dialog_internal_box (pDialog, 0, pDialog->iTopMargin, FALSE);
	else
		pDialog->pTipWidget = _cairo_dock_add_dialog_internal_box (pDialog, 0, pDialog->iMinBottomGap + pDialog->iBottomMargin, TRUE);
	if (pDialog->iMessageWidth != 0 && pDialog->iMessageHeight != 0)
	{
		pDialog->pMessageWidget = _cairo_dock_add_dialog_internal_box (pDialog, pDialog->iMessageWidth, pDialog->iMessageHeight, FALSE);
	}
	if (pDialog->pInteractiveWidget != NULL)
	{
		gtk_box_pack_start (GTK_BOX (pDialog->pWidgetLayout),
			pDialog->pInteractiveWidget,
			FALSE,
			FALSE,
			0);
		gtk_window_present (GTK_WINDOW (pDialog->container.pWidget));
		gtk_widget_grab_focus (pDialog->pInteractiveWidget);
		
		// set a MenuItem style to the dialog, so that the interactive widget can use the style defined for menu-items (either from the GTK theme, or from our own .css), and therefore be well integrated into the dialog, as if it was inside a menu.
		GtkStyleContext *ctx = gtk_widget_get_style_context (pDialog->pWidgetLayout);
		gtk_style_context_add_class (ctx, myDialogsParam.bUseDefaultColors && myStyleParam.bUseSystemColors ? GTK_STYLE_CLASS_MENUITEM : "gldimenuitem");
	}
	if (pDialog->pButtons != NULL)
	{
		pDialog->pButtonsWidget = _cairo_dock_add_dialog_internal_box (pDialog, pDialog->iButtonsWidth, pDialog->iButtonsHeight, FALSE);
	}
	if (pDialog->container.bDirectionUp)
		pDialog->pTipWidget = _cairo_dock_add_dialog_internal_box (pDialog, 0, pDialog->iMinBottomGap + pDialog->iBottomMargin, TRUE);
	else
		pDialog->pTopWidget = _cairo_dock_add_dialog_internal_box (pDialog, 0, pDialog->iTopMargin, TRUE);
	
	gtk_widget_show_all (pDialog->container.pWidget);
	
	//\________________ load the input shape.
	if (pDialog->bNoInput)
	{
		_cairo_dock_set_dialog_input_shape (pDialog);
	}
	
	//\________________ connect the signals to the window
	g_signal_connect (G_OBJECT (pDialog->container.pWidget),
		"draw",
		G_CALLBACK (on_expose_dialog),
		pDialog);
	g_signal_connect_after (G_OBJECT (pDialog->container.pWidget),
		"draw",
		G_CALLBACK (on_expose_dialog_after),
		pDialog);
	g_signal_connect (G_OBJECT (pDialog->container.pWidget),
		"configure-event",
		G_CALLBACK (on_configure_dialog),
		pDialog);
	g_signal_connect (G_OBJECT (pDialog->container.pWidget),
		"unmap-event",
		G_CALLBACK (on_unmap_dialog),
		pDialog);  // prevent dialogs from being hidden (for instance by a 'show-desktop' event), because they might be modal
	g_signal_connect (G_OBJECT (pDialog->container.pWidget),
		"map-event",
		G_CALLBACK (on_map_dialog),
		pDialog);  // some WM (like GS) prevent the focus to be taken, so we have to force it whenever the dialog is shown (creation or unhide).
	if (pDialog->pInteractiveWidget != NULL && pDialog->pButtons == NULL)  // the dialog has no button to be closed, so it can be closed by clicking on it. But some widget (like the GTK calendar) let pass the click to their parent (= the dialog), which then close it. To prevent this, we memorize the last click on the widget.
		g_signal_connect (G_OBJECT (pDialog->pInteractiveWidget),
			"button-press-event",
			G_CALLBACK (on_button_press_widget),
			pDialog);
	
	cairo_dock_launch_animation (CAIRO_CONTAINER (pDialog));
}
static void _on_got_events (ZeitgeistResultSet *pEvents, GtkListStore *pModel)
{
	int i, n;
	ZeitgeistEvent *event;
	ZeitgeistSubject *subject;
	gint64 iTimeStamp;
	const gchar *cEventURI;
	guint id;
	gchar *cName = NULL, *cURI = NULL, *cIconName = NULL, *cIconPath, *cPath = NULL;
	double fOrder;
	int iVolumeID;
	gboolean bIsDirectory;
	GdkPixbuf *pixbuf;
	GtkTreeIter iter;
	GHashTable *pHashTable = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);  // used to prevent doubles
	
	//\_____________ parse all the events.
	while (zeitgeist_result_set_has_next (pEvents))
	{
		#ifdef ZEITGEIST_1_0
		event = zeitgeist_result_set_next (pEvents);
		#else
		event = zeitgeist_result_set_next_value (pEvents);
		#endif
		iTimeStamp = zeitgeist_event_get_timestamp (event) / 1e3;
		id = zeitgeist_event_get_id (event);
		n = zeitgeist_event_num_subjects (event);
		if (n > 1)
			cd_debug (" +++ %s, %s, %d", zeitgeist_event_get_interpretation (event), zeitgeist_event_get_manifestation (event), n);
		for (i = 0; i < n; i++)
		{
			subject = zeitgeist_event_get_subject (event, i);
			
			//\_____________ prevent doubles.
			cEventURI = zeitgeist_subject_get_uri (subject);
			if (g_hash_table_lookup_extended  (pHashTable, cEventURI, NULL, NULL))
				continue;
			//g_print ("  %s:\n    %s, %s\n", cEventURI, zeitgeist_subject_get_interpretation (subject), zeitgeist_subject_get_manifestation (subject));
			
			//\_____________ ignore files that have been deleted
			cPath = g_filename_from_uri (cEventURI, NULL, NULL);  // NULL for anything else than file://*
			if (strncmp (cEventURI, "file://", 7) == 0 && ! g_file_test (cPath, G_FILE_TEST_EXISTS))
			{
				g_hash_table_insert (pHashTable, (gchar*)cEventURI, NULL);  // since we've checked it, insert it, even if we don't display it.
				g_free (cPath);
				continue;
			}
			//\_____________ get the text to display.
			const gchar *cText = zeitgeist_subject_get_text (subject);
			if (cText == NULL)  // skip empty texts (they are most of the times web page that redirect to another page, which is probably in the next event anyway).
				continue;
			
			//\_____________ find the icon.
			if (strncmp (cEventURI, "http", 4) == 0)  // gvfs is deadly slow to get info on distant URI...
			{
				cIconName = cairo_dock_search_icon_s_path ("text-html", myData.iDesiredIconSize);
			}
			else if (strncmp (cEventURI, "application://", 14) == 0)  // application URL
			{
				gchar *cClass = cairo_dock_register_class (cEventURI+14);
				cIconName = g_strdup (cairo_dock_get_class_icon (cClass));
				cText = cairo_dock_get_class_name (cClass);  // use the translated name
				g_free (cClass);
			}
			else
			{
				cairo_dock_fm_get_file_info (cEventURI, &cName, &cURI, &cIconName, &bIsDirectory, &iVolumeID, &fOrder, CAIRO_DOCK_FM_SORT_BY_DATE);
			}
			if (cIconName != NULL)
			{
				cIconPath = cairo_dock_search_icon_s_path (cIconName, myData.iDesiredIconSize);
				pixbuf = gdk_pixbuf_new_from_file_at_size (cIconPath, myData.iDesiredIconSize, myData.iDesiredIconSize, NULL);
				g_free (cIconPath);
			}
			else
				pixbuf = NULL;
			
			//\_____________ build the path to display.
			const gchar *cDisplayedPath = (cPath ? cPath : cEventURI);

			// need to escape the '&' (and ', etc.) because gtk-tooltips use markups by default.
			gchar *cEscapedPath = g_markup_escape_text (cDisplayedPath, -1);
			
			//\_____________ store in the model.
			memset (&iter, 0, sizeof (GtkTreeIter));
			gtk_list_store_append (GTK_LIST_STORE (pModel), &iter);
			gtk_list_store_set (GTK_LIST_STORE (pModel), &iter,
				CD_MODEL_NAME, cText,
				CD_MODEL_URI, cEventURI,
				CD_MODEL_PATH, cEscapedPath,
				CD_MODEL_ICON, pixbuf,
				CD_MODEL_DATE, iTimeStamp,
				CD_MODEL_ID, id, -1);
			
			g_free (cIconName);
			cIconName = NULL;
			g_free (cName);
			cName = NULL;
			g_free (cURI);
			cURI = NULL;
			if (pixbuf)
				g_object_unref (pixbuf);
			g_free (cPath);
			g_free (cEscapedPath);
			
			g_hash_table_insert (pHashTable, (gchar*)cEventURI, NULL);  // cEventURI stays valid in this function.
		}
	}
	g_hash_table_destroy (pHashTable);
}
static gboolean _on_click_module_tree_view (GtkTreeView *pTreeView, GdkEventButton* pButton, gpointer data)
{
	//g_print ("%s ()\n", __func__);
	if ((pButton->button == 3 && pButton->type == GDK_BUTTON_RELEASE)  // right-click
	|| (pButton->button == 1 && pButton->type == GDK_2BUTTON_PRESS))  // double-click
	{
		cd_debug ("%s ()", __func__);
		// get the current selected line.
		GtkTreeSelection *pSelection = gtk_tree_view_get_selection (pTreeView);
		GtkTreeModel *pModel;
		GtkTreeIter iter;
		if (! gtk_tree_selection_get_selected (pSelection, &pModel, &iter))
			return FALSE;
		
		gchar *cName = NULL, *cUri = NULL;
		guint id = 0;
		gtk_tree_model_get (pModel, &iter,
			CD_MODEL_NAME, &cName,
			CD_MODEL_URI, &cUri,
			CD_MODEL_ID, &id, -1);
		
		//launch or build the menu.
		gboolean bIsAppli = (strncmp (cUri, "application://", 14) == 0);
		if (pButton->button == 1)  // double-click
		{
			if (bIsAppli)  // an appli -> run it
			{
				gchar *tmp = strrchr (cUri, '.');  // remove the '.desktop'
				if (tmp)
					*tmp = '\0';
				cairo_dock_launch_command (cUri+14);
			}
			else  // a file -> open it
			{
				cairo_dock_fm_launch_uri (cUri);
			}
			g_free (cUri);
		}
		else  // right-click
		{
			GtkWidget *pMenu = gldi_menu_new (NULL);
			g_free (myData.cCurrentUri);
			myData.cCurrentUri = cUri;
			
			if (!bIsAppli)
			{
				GList *pApps = cairo_dock_fm_list_apps_for_file (cUri);
				if (pApps != NULL)
				{
					GtkWidget *pSubMenu = CD_APPLET_ADD_SUB_MENU_WITH_IMAGE (D_("Open with"), pMenu, GLDI_ICON_NAME_OPEN);
					
					cd_folders_free_apps_list (myApplet);
					
					GList *a;
					gchar **pAppInfo;
					gchar *cIconPath;
					for (a = pApps; a != NULL; a = a->next)
					{
						pAppInfo = a->data;
						myData.pAppList = g_list_prepend (myData.pAppList, pAppInfo[1]);
						
						if (pAppInfo[2] != NULL)
							cIconPath = cairo_dock_search_icon_s_path (pAppInfo[2], cairo_dock_search_icon_size (GTK_ICON_SIZE_MENU));
						else
							cIconPath = NULL;
						CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (pAppInfo[0], cIconPath, _cd_launch_with, pSubMenu, pAppInfo[1]);
						g_free (cIconPath);
						g_free (pAppInfo[0]);
						g_free (pAppInfo[2]);
						g_free (pAppInfo);
					}
					g_list_free (pApps);
				}
				CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (D_("Open parent folder"), GLDI_ICON_NAME_DIRECTORY, _cd_open_parent, pMenu, NULL);
				
				CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (D_("Copy the location"), GLDI_ICON_NAME_COPY, _cd_copy_location, pMenu, NULL);
			}
			
			CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (D_("Delete this event"), GLDI_ICON_NAME_REMOVE, _cd_delete_event, pMenu, GUINT_TO_POINTER (id));
			
			gtk_widget_show_all (pMenu);
			gtk_menu_popup (GTK_MENU (pMenu),
				NULL,
				NULL,
				NULL,  // popup on mouse.
				NULL,
				1,
				gtk_get_current_event_time ());
		}
	}
	return FALSE;
}