2
* This file is a part of the Cairo-Dock project
4
* Copyright : (C) see the 'copyright' file.
5
* E-mail : see the 'copyright' file.
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.
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/>.
20
/******************************************************************************
22
This file is a part of the cairo-dock program,
23
released under the terms of the GNU General Public License.
25
Written by Fabrice Rey (for any bug report, please mail me to fabounet@users.berlios.de)
27
******************************************************************************/
31
#include "applet-struct.h"
32
#include "applet-menu.h"
34
static GList *s_pItemList = NULL;
36
static void _on_activate_item (GtkWidget *pMenuItem, CDQuickBrowserItem *pItem);
38
static int _sort_item (CDQuickBrowserItem *pItem1, CDQuickBrowserItem *pItem2)
44
CairoDockModuleInstance *myApplet = pItem2->pApplet;
45
if (myConfig.bFoldersFirst)
47
if (pItem1->pSubMenu && ! pItem2->pSubMenu)
49
if (! pItem1->pSubMenu && pItem2->pSubMenu)
52
if (myConfig.bCaseUnsensitive)
53
return g_ascii_strcasecmp (pItem1->cTmpFileName, pItem2->cTmpFileName);
55
return strcmp (pItem1->cTmpFileName, pItem2->cTmpFileName);
57
static GList *_list_dir (const gchar *cDirPath, CairoDockModuleInstance *myApplet)
59
//\______________ On ouvre le repertoire en lecture.
60
GError *erreur = NULL;
61
GDir *dir = g_dir_open (cDirPath, 0, &erreur);
64
cd_warning (erreur->message);
65
g_error_free (erreur);
69
//\______________ On recupere chaque item, qu'on classe dans une liste temporaire.
70
CDQuickBrowserItem *pItem;
71
const gchar *cFileName;
72
GList *pLocalItemList = NULL;
75
cFileName = g_dir_read_name (dir);
76
if (cFileName == NULL)
78
if (! myConfig.bShowHiddenFiles && *cFileName == '.')
80
pItem = g_new0 (CDQuickBrowserItem, 1);
81
pItem->cPath = g_strdup_printf ("%s/%s", cDirPath, cFileName);
82
pItem->cTmpFileName = cFileName; // valable uniquement dans cette boucle, ca tombe bien le classement se fait ici.
83
pItem->pApplet = myApplet;
84
if (g_file_test (pItem->cPath, G_FILE_TEST_IS_DIR))
85
pItem->pSubMenu = gtk_menu_new ();
87
pLocalItemList = g_list_insert_sorted (pLocalItemList,
89
(GCompareFunc)_sort_item);
94
return pLocalItemList;
96
static void _init_fill_menu_from_dir (CDQuickBrowserItem *pItem)
98
const gchar *cDirPath = pItem->cPath;
99
GtkWidget *pMenu = pItem->pSubMenu;
100
CairoDockModuleInstance *myApplet = pItem->pApplet;
102
//\______________ On recupere les items du repertoire.
103
GList *pLocalItemList = _list_dir (cDirPath, myApplet);
105
//\______________ On rajoute en premier une entree pour ouvrir le repertoire.
106
CDQuickBrowserItem *pOpenDirItem = g_new0 (CDQuickBrowserItem, 1);
107
pOpenDirItem->cPath = g_strdup (cDirPath);
108
pOpenDirItem->pApplet = myApplet;
109
pItem->pLocalItemList = g_list_prepend (pLocalItemList, pOpenDirItem);
110
pItem->pCurrentItem = pItem->pLocalItemList->next; // on la rajoute au menu ici, pas en meme temps que les autres.
112
//\______________ On ajoute cette entree dans le menu des maintenant.
113
GtkWidget *pMenuItem;
114
if (myConfig.bHasIcons)
116
pMenuItem = gtk_image_menu_item_new_with_label (D_("Open this folder"));
117
GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
118
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (pMenuItem), image);
122
pMenuItem = gtk_menu_item_new_with_label (D_("Open this folder"));
124
gtk_menu_shell_append (GTK_MENU_SHELL (pMenu), pMenuItem);
125
g_signal_connect (G_OBJECT (pMenuItem), "activate", G_CALLBACK(_on_activate_item), pOpenDirItem);
127
static void _fill_submenu_with_items (CDQuickBrowserItem *pRootItem, int iNbSubItemsAtOnce)
129
CairoDockModuleInstance *myApplet = pRootItem->pApplet;
130
GtkWidget *pMenu = pRootItem->pSubMenu;
131
GList *pFirstItem = pRootItem->pCurrentItem;
133
CDQuickBrowserItem *pItem;
135
GtkWidget *pMenuItem;
137
gchar *cName = NULL, *cURI = NULL, *cIconName = NULL;
138
gboolean bIsDirectory;
143
for (l = pFirstItem, i = 0; l != NULL && i < iNbSubItemsAtOnce; l = l->next, i ++)
147
//\______________ On cree l'entree avec son icone si necessaire.
149
if (myConfig.bHasIcons)
151
cairo_dock_fm_get_file_info (pItem->cPath, &cName, &cURI, &cIconName, &bIsDirectory, &iVolumeID, &fOrder, 0);
157
cFileName = strrchr (pItem->cPath, '/');
160
if (cIconName != NULL)
162
pMenuItem = gtk_image_menu_item_new_with_label (cFileName);
163
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size (cIconName, 32, 32, NULL);
164
GtkWidget *image = gtk_image_new_from_pixbuf (pixbuf);
165
g_object_unref (pixbuf);
166
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (pMenuItem), image);
172
pMenuItem = gtk_menu_item_new_with_label (cFileName);
175
//\______________ On l'insere dans le menu.
176
gtk_menu_shell_append (GTK_MENU_SHELL (pMenu), pMenuItem);
177
g_signal_connect (G_OBJECT (pMenuItem), "activate", G_CALLBACK(_on_activate_item), pItem);
179
if (pItem->pSubMenu != NULL)
181
gtk_menu_item_set_submenu (GTK_MENU_ITEM (pMenuItem), pItem->pSubMenu);
184
pRootItem->pCurrentItem = l;
186
static gboolean _fill_submenu_idle (CDQuickBrowserItem *pItem)
188
CairoDockModuleInstance *myApplet = pItem->pApplet;
189
if (pItem->pLocalItemList == NULL)
191
_init_fill_menu_from_dir (pItem);
192
if (pItem->pLocalItemList == NULL) // cas particulier d'un repertoire vide, inutile de revenir ici pour rien faire.
193
pItem->bMenuBuilt = TRUE;
197
_fill_submenu_with_items (pItem, myConfig.iNbSubItemsAtOnce);
198
if (pItem->pCurrentItem == NULL)
199
pItem->bMenuBuilt = TRUE;
202
if (pItem->bMenuBuilt)
204
CairoDockModuleInstance *myApplet = pItem->pApplet;
205
myData.iSidFillDirIdle = 0;
206
gtk_widget_show_all (pItem->pSubMenu);
211
static void _on_activate_item (GtkWidget *pMenuItem, CDQuickBrowserItem *pItem)
213
//g_print ("%s (%s, %x)\n", __func__, pItem->cPath, pItem->pSubMenu);
214
CairoDockModuleInstance *myApplet = pItem->pApplet;
215
if (pItem->pSubMenu != NULL)
217
if (! pItem->bMenuBuilt)
219
//g_print (" c'est un repertoire (tache courante : %d)\n", myData.iSidFillDirIdle);
220
if (myData.iSidFillDirIdle != 0)
221
g_source_remove (myData.iSidFillDirIdle);
222
myData.iSidFillDirIdle = g_idle_add ((GSourceFunc) _fill_submenu_idle, pItem);
227
cairo_dock_fm_launch_uri (pItem->cPath);
228
cd_quick_browser_destroy_menu (myApplet);
233
CDQuickBrowserItem *cd_quick_browser_make_menu_from_dir (const gchar *cDirPath, CairoDockModuleInstance *myApplet)
235
CDQuickBrowserItem *pRootItem = g_new0 (CDQuickBrowserItem, 1);
236
pRootItem->cPath = g_strdup (cDirPath);
237
pRootItem->pApplet = myApplet;
238
pRootItem->pSubMenu = gtk_menu_new ();
240
_init_fill_menu_from_dir (pRootItem);
241
_fill_submenu_with_items (pRootItem, 1e6);
242
pRootItem->bMenuBuilt = TRUE;
243
gtk_widget_show_all (pRootItem->pSubMenu);
248
static void _free_item (CDQuickBrowserItem *pItem)
250
g_free (pItem->cPath);
251
if (pItem->pLocalItemList != NULL)
253
g_list_foreach (pItem->pLocalItemList, (GFunc) _free_item, NULL);
254
g_list_free (pItem->pLocalItemList);
258
void cd_quick_browser_destroy_menu (CairoDockModuleInstance *myApplet)
260
if (myData.iSidFillDirIdle != 0)
261
g_source_remove (myData.iSidFillDirIdle);
262
myData.iSidFillDirIdle = 0;
264
if (myData.pRootItem != NULL)
266
gtk_widget_destroy (myData.pRootItem->pSubMenu); // detruit tous les pSubMenu en cascade.
267
_free_item (myData.pRootItem);
268
myData.pRootItem = NULL;
272
void cd_quick_browser_show_menu (CairoDockModuleInstance *myApplet)
274
cd_quick_browser_destroy_menu (myApplet);
276
myData.pRootItem = cd_quick_browser_make_menu_from_dir (myConfig.cDirPath, myApplet);
277
g_return_if_fail (myData.pRootItem != NULL && myData.pRootItem->pSubMenu != NULL);
279
g_signal_connect (G_OBJECT (myData.pRootItem->pSubMenu),
281
G_CALLBACK (cairo_dock_delete_menu),
285
myDock->bMenuVisible = TRUE;
286
gtk_menu_popup (GTK_MENU (myData.pRootItem->pSubMenu),
292
gtk_get_current_event_time ());