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 <stdlib.h>
21 #include <string.h>
22
23 #include "applet-struct.h"
24 #include "applet-notifications.h"
25 #include "applet-load-icons.h"
26
27 static void _cd_folders_remove_all_icons (GldiModuleInstance *myApplet);
28
cd_shortcuts_set_icon_order(Icon * pNewIcon,GList * pIconsList,GCompareFunc comp)29 void cd_shortcuts_set_icon_order (Icon *pNewIcon, GList *pIconsList, GCompareFunc comp)
30 {
31 if (comp == NULL)
32 return;
33 cd_debug ("%s (%s)", __func__, pNewIcon->cName);
34 // on cherche la 1ere icone du meme type.
35 GList *ic;
36 Icon *pIcon;
37 for (ic = pIconsList; ic != NULL; ic = ic->next)
38 {
39 pIcon = ic->data;
40 if (pIcon->iGroup == pNewIcon->iGroup)
41 break;
42 }
43 GList *ic0 = ic;
44 if (! ic0) // si non trouve, on arrete la.
45 {
46 pNewIcon->fOrder = 0;
47 return;
48 }
49
50 pIcon = ic0->data;
51 if (comp (pNewIcon, pIcon) <= 0)
52 {
53 pNewIcon->fOrder = pIcon->fOrder - 1;
54 cd_debug ("name : %s <= %s -> %.2f", pNewIcon->cName, pIcon->cName, pNewIcon->fOrder);
55 return;
56 }
57
58 pNewIcon->fOrder = 0;
59 for (ic = ic0; ic != NULL; ic = ic->next)
60 {
61 pIcon = ic->data;
62 cd_debug (" compare with %s (%.2f)", pIcon->cName, pIcon->fOrder);
63 if (pIcon->iGroup != pNewIcon->iGroup)
64 {
65 cd_debug (" type differ, break");
66 break;
67 }
68 if (comp (pNewIcon, pIcon) < 0)
69 {
70 if (ic->prev == NULL)
71 pNewIcon->fOrder = pIcon->fOrder - 1;
72 else
73 {
74 Icon *pPrevIcon = ic->prev->data;
75 pNewIcon->fOrder = (pIcon->fOrder + pPrevIcon->fOrder) / 2;
76 }
77 cd_debug (" name : %s < %s -> %.2f", pNewIcon->cName, pIcon->cName, pNewIcon->fOrder);
78 break;
79 }
80 pNewIcon->fOrder = pIcon->fOrder + 1;
81 cd_debug (" fOrder <- %.2f", pNewIcon->fOrder);
82 }
83 }
84
85
_manage_event_on_file(CairoDockFMEventType iEventType,const gchar * cBaseURI,GList * pIconsList,GldiContainer * pContainer,GldiModuleInstance * myApplet)86 static void _manage_event_on_file (CairoDockFMEventType iEventType, const gchar *cBaseURI, GList *pIconsList, GldiContainer *pContainer, GldiModuleInstance *myApplet)
87 {
88 if (!cBaseURI)
89 return;
90 gchar *cURI = g_strdup (cBaseURI);
91 cairo_dock_remove_html_spaces (cURI);
92 cd_debug (" * event %d on '%s'", iEventType, cURI);
93
94 if (!myConfig.bShowHiddenFiles)
95 {
96 gchar *str = strrchr (cBaseURI, '/');
97 if (str && *(str+1) == '.')
98 return;
99 }
100
101 switch (iEventType)
102 {
103 case CAIRO_DOCK_FILE_DELETED : // un fichier a ete supprime (ce peut etre du a un renommage).
104 {
105 if (strcmp (myConfig.cDirPath, cBaseURI) == 0)
106 {
107 cd_debug ("our folder has been removed");
108 _cd_folders_remove_all_icons (myApplet);
109 return;
110 }
111
112 Icon *pConcernedIcon = cairo_dock_get_icon_with_base_uri (pIconsList, cURI);
113 if (pConcernedIcon == NULL) // on cherche par nom.
114 {
115 pConcernedIcon = cairo_dock_get_icon_with_name (pIconsList, cURI);
116 }
117 if (pConcernedIcon == NULL)
118 {
119 cd_warning (" an unknown file was removed");
120 return ;
121 }
122 cd_debug (" %s will be removed", pConcernedIcon->cName);
123
124 // on l'enleve du container.
125 CD_APPLET_REMOVE_ICON_FROM_MY_ICONS_LIST (pConcernedIcon); // detruit l'icone.
126 }
127 break ;
128
129 case CAIRO_DOCK_FILE_CREATED : // un point de montage a ete connecte.
130 {
131 if (strcmp (myConfig.cDirPath, cBaseURI) == 0)
132 {
133 cd_debug ("our folder has been re-created");
134 gldi_task_launch (myData.pTask);
135 return;
136 }
137
138 //\_______________________ on verifie qu'elle n'existe pas deja.
139 Icon *pSameIcon = cairo_dock_get_icon_with_base_uri (pIconsList, cURI);
140 if (pSameIcon != NULL)
141 {
142 cd_warning ("this file (%s) already exists", pSameIcon->cName);
143 return; // on decide de ne rien faire, c'est surement un signal inutile.
144 }
145
146 //\_______________________ on cree une icone pour cette nouvelle URI.
147 Icon *pNewIcon = cairo_dock_fm_create_icon_from_URI (cURI, pContainer, myConfig.iSortType);
148 if (pNewIcon == NULL)
149 {
150 cd_warning ("couldn't create an icon for this file");
151 return ;
152 }
153 pNewIcon->iGroup = (myConfig.bFoldersFirst && pNewIcon->iVolumeID == -1 ? 6 : 8);
154
155 //\_______________________ on la place au bon endroit suivant son nom.
156 cd_shortcuts_set_icon_order (pNewIcon, pIconsList, myData.comp);
157 cd_debug (" new file : %s, order = %.2f", pNewIcon->cName, pNewIcon->fOrder);
158
159 CD_APPLET_ADD_ICON_IN_MY_ICONS_LIST (pNewIcon);
160 }
161 break ;
162
163 case CAIRO_DOCK_FILE_MODIFIED : // un point de montage a ete (de)monte
164 {
165 Icon *pConcernedIcon = cairo_dock_get_icon_with_base_uri (pIconsList, cURI);
166 if (pConcernedIcon == NULL) // on cherche par nom.
167 {
168 pConcernedIcon = cairo_dock_get_icon_with_name (pIconsList, cURI);
169 }
170 if (pConcernedIcon == NULL)
171 {
172 cd_warning (" an unknown file was modified");
173 return ;
174 }
175 cd_debug (" %s is modified", pConcernedIcon->cName);
176
177 //\_______________________ on recupere les infos actuelles.
178 Icon *pNewIcon = cairo_dock_fm_create_icon_from_URI (cURI, pContainer, myConfig.iSortType);
179 if (pNewIcon == NULL)
180 {
181 cd_warning ("couldn't create an icon for this file");
182 return ;
183 }
184 pNewIcon->iGroup = (myConfig.bFoldersFirst && pNewIcon->iVolumeID == -1 ? 6 : 8);
185 double fCurrentOrder = pConcernedIcon->fOrder;
186 if (myConfig.iSortType == 1 || myConfig.iSortType == 2) // sort by date or size.
187 pConcernedIcon->fOrder = pNewIcon->fOrder;
188
189 //\_______________________ on gere le changement de nom.
190 if (cairo_dock_strings_differ (pConcernedIcon->cName, pNewIcon->cName)) // le nom a change.
191 {
192 cd_debug (" name changed : '%s' -> '%s'", pConcernedIcon->cName, pNewIcon->cName);
193 gldi_icon_set_name (pConcernedIcon, pNewIcon->cName);
194 cd_shortcuts_set_icon_order (pConcernedIcon, pIconsList, myData.comp);
195 }
196
197 //\_______________________ on gere le changement d'image.
198 if (cairo_dock_strings_differ (pConcernedIcon->cFileName, pNewIcon->cFileName))
199 {
200 cd_debug (" image changed : '%s' -> '%s'", pConcernedIcon->cFileName, pNewIcon->cFileName);
201 g_free (pConcernedIcon->cFileName);
202 pConcernedIcon->cFileName = g_strdup (pNewIcon->cFileName);
203
204 if (pConcernedIcon->image.pSurface != NULL)
205 cairo_dock_load_icon_image (pConcernedIcon, pContainer);
206 }
207
208 //\_______________________ on gere le changement d'ordre (du au changement de nom, d'extension, ou de taille, suivant le classement utilise).
209 if (pConcernedIcon->fOrder != fCurrentOrder)
210 {
211 cd_debug (" order changed : %.2f -> %.2f", fCurrentOrder, pConcernedIcon->fOrder);
212
213 // on la detache.
214 CD_APPLET_DETACH_ICON_FROM_MY_ICONS_LIST (pConcernedIcon);
215 pIconsList = CD_APPLET_MY_ICONS_LIST;
216
217 CD_APPLET_ADD_ICON_IN_MY_ICONS_LIST (pConcernedIcon);
218 }
219 gldi_object_unref (GLDI_OBJECT (pNewIcon));
220 }
221 break ;
222 case CAIRO_DOCK_NB_EVENT_ON_FILES :
223 break ;
224 }
225 g_free (cURI);
226 }
227
_cd_folders_on_file_event(CairoDockFMEventType iEventType,const gchar * cURI,GldiModuleInstance * myApplet)228 static void _cd_folders_on_file_event (CairoDockFMEventType iEventType, const gchar *cURI, GldiModuleInstance *myApplet)
229 {
230 g_return_if_fail (cURI != NULL);
231 CD_APPLET_ENTER;
232
233 //\________________ On gere l'evenement sur le fichier.
234 GList *pIconsList = CD_APPLET_MY_ICONS_LIST;
235 GldiContainer *pContainer = CD_APPLET_MY_ICONS_LIST_CONTAINER;
236 CD_APPLET_LEAVE_IF_FAIL (pContainer != NULL);
237
238 _manage_event_on_file (iEventType, cURI, pIconsList, pContainer, myApplet);
239
240 CD_APPLET_LEAVE();
241 }
242
243
_cd_folders_get_data(CDSharedMemory * pSharedMemory)244 static void _cd_folders_get_data (CDSharedMemory *pSharedMemory)
245 {
246 //\_______________________ On recupere les fichiers.
247 gchar *cCommand = NULL;
248 pSharedMemory->pIconList = cairo_dock_fm_list_directory (pSharedMemory->cDirPath, pSharedMemory->iSortType, 8, pSharedMemory->bShowHiddenFiles, 1e4, &cCommand);
249 g_free (cCommand);
250
251 //\_______________________ on classe les icones.
252 if (pSharedMemory->bFoldersFirst)
253 {
254 Icon *pIcon;
255 GList *ic;
256 for (ic = pSharedMemory->pIconList; ic != NULL; ic = ic->next)
257 {
258 pIcon = ic->data;
259 if (pIcon->iVolumeID != 0) // repertoire
260 pIcon->iGroup = 6;
261 }
262 }
263
264 if (pSharedMemory->iSortType == 0) // sort by name
265 {
266 pSharedMemory->pIconList = g_list_sort (pSharedMemory->pIconList, (GCompareFunc) cairo_dock_compare_icons_name);
267 }
268 else if (pSharedMemory->iSortType == 3) // sort by type
269 {
270 pSharedMemory->pIconList = g_list_sort (pSharedMemory->pIconList, (GCompareFunc) cairo_dock_compare_icons_extension);
271 }
272 else // sort by date or size
273 {
274 pSharedMemory->pIconList = g_list_sort (pSharedMemory->pIconList, (GCompareFunc) cairo_dock_compare_icons_order);
275 }
276
277 //g_print ("=== files to display: ===\n");
278 Icon *pIcon;
279 int iOrder = 0;
280 GList *ic;
281 for (ic = pSharedMemory->pIconList; ic != NULL; ic = ic->next)
282 {
283 pIcon = ic->data;
284 //g_print (" %s (%d)\n", pIcon->cName, pIcon->iVolumeID);
285 pIcon->fOrder = iOrder ++;
286 }
287 }
288
289
_cd_folders_load_icons_from_data(CDSharedMemory * pSharedMemory)290 static gboolean _cd_folders_load_icons_from_data (CDSharedMemory *pSharedMemory)
291 {
292 GldiModuleInstance *myApplet = pSharedMemory->pApplet;
293 g_return_val_if_fail (myIcon != NULL, FALSE); // paranoia
294 CD_APPLET_ENTER;
295
296 //\_______________________ On efface l'ancienne liste.
297 CD_APPLET_DELETE_MY_ICONS_LIST;
298
299 //\_______________________ On charge la nouvelle liste.
300 CD_APPLET_LOAD_MY_ICONS_LIST (pSharedMemory->pIconList, myConfig.cRenderer, "Viewport", NULL);
301 pSharedMemory->pIconList = NULL;
302
303 //\_______________________ On se place en ecoute.
304 cairo_dock_fm_add_monitor_full (pSharedMemory->cDirPath, TRUE, NULL, (CairoDockFMMonitorCallback) _cd_folders_on_file_event, myApplet);
305
306 gldi_task_discard (myData.pTask);
307 myData.pTask = NULL;
308 CD_APPLET_LEAVE (TRUE);
309 }
310
_free_shared_memory(CDSharedMemory * pSharedMemory)311 static void _free_shared_memory (CDSharedMemory *pSharedMemory)
312 {
313 g_free (pSharedMemory->cDirPath);
314 g_list_foreach (pSharedMemory->pIconList, (GFunc)g_free, NULL);
315 g_list_free (pSharedMemory->pIconList);
316 g_free (pSharedMemory);
317 }
318
cd_folders_start(GldiModuleInstance * myApplet)319 void cd_folders_start (GldiModuleInstance *myApplet)
320 {
321 if (myData.pTask != NULL)
322 {
323 gldi_task_discard (myData.pTask);
324 myData.pTask = NULL;
325 }
326
327 CDSharedMemory *pSharedMemory = g_new0 (CDSharedMemory, 1);
328 pSharedMemory->cDirPath = g_strdup (myConfig.cDirPath);
329 pSharedMemory->bShowFiles = myConfig.bShowFiles;
330 pSharedMemory->iSortType = myConfig.iSortType;
331 pSharedMemory->bFoldersFirst = myConfig.bFoldersFirst;
332 pSharedMemory->bShowHiddenFiles = myConfig.bShowHiddenFiles;
333 pSharedMemory->pApplet = myApplet;
334
335 myData.pTask = gldi_task_new_full (0,
336 (GldiGetDataAsyncFunc) _cd_folders_get_data,
337 (GldiUpdateSyncFunc) _cd_folders_load_icons_from_data,
338 (GFreeFunc) _free_shared_memory,
339 pSharedMemory);
340 gldi_task_launch_delayed (myData.pTask, 0); // le delai est la pour laisser le temps au backend gvfs de s'initialiser (sinon on a un "g_hash_table_lookup: assertion `hash_table != NULL' failed" lors du listing d'un repertoire, avec en consequence des icones non trouvees).
341 }
342
343
344
345
_cd_folders_remove_all_icons(GldiModuleInstance * myApplet)346 static void _cd_folders_remove_all_icons (GldiModuleInstance *myApplet)
347 {
348 //\_______________________ On stoppe la tache.
349 gldi_task_discard (myData.pTask);
350 myData.pTask = NULL;
351
352 //\_______________________ On detruit ensuite les icones chargees dans le container.
353 CD_APPLET_DELETE_MY_ICONS_LIST; // si le container a change entre-temps, le ModuleManager se chargera de nettoyer derriere nous.
354 }
cd_folders_free_all_data(GldiModuleInstance * myApplet)355 void cd_folders_free_all_data (GldiModuleInstance *myApplet)
356 {
357 //\_______________________ On arrete de surveiller le repertoire.
358 cairo_dock_fm_remove_monitor_full (myConfig.cDirPath, TRUE, NULL);
359
360 _cd_folders_remove_all_icons (myApplet);
361
362 cd_folders_free_apps_list (myApplet);
363 }
364
365
_get_order(Icon * pIcon,gpointer data)366 static void _get_order (Icon *pIcon, gpointer data)
367 {
368 CairoDockFMSortType iSortType = GPOINTER_TO_INT (data);
369 gchar *cName = NULL, *cURI = NULL, *cIconName = NULL;
370 gboolean bIsDirectory;
371 int iVolumeID;
372 double fOrder;
373 cairo_dock_fm_get_file_info (pIcon->cBaseURI, &cName, &cURI, &cIconName, &bIsDirectory, &iVolumeID, &fOrder, iSortType);
374 g_free (cName);
375 g_free (cURI);
376 g_free (cIconName);
377 pIcon->fOrder = fOrder;
378 }
379
cairo_dock_sort_icons_by_extension(GList * pIconList)380 GList *cairo_dock_sort_icons_by_extension (GList *pIconList)
381 {
382 GList *pSortedIconList = g_list_sort (pIconList, (GCompareFunc) cairo_dock_compare_icons_extension);
383
384 guint iCurrentGroup = -1;
385 double fCurrentOrder = 0.;
386 Icon *icon;
387 GList *ic;
388 for (ic = pIconList; ic != NULL; ic = ic->next)
389 {
390 icon = ic->data;
391 if (icon->iGroup != iCurrentGroup)
392 {
393 iCurrentGroup = icon->iGroup;
394 fCurrentOrder = 0.;
395 }
396 icon->fOrder = fCurrentOrder++;
397 }
398 return pSortedIconList;
399 }
400
cd_folders_sort_icons(GldiModuleInstance * myApplet,CairoDockFMSortType iSortType)401 void cd_folders_sort_icons (GldiModuleInstance *myApplet, CairoDockFMSortType iSortType)
402 {
403 GList *pIconsList = CD_APPLET_MY_ICONS_LIST;
404 GldiContainer *pContainer = CD_APPLET_MY_ICONS_LIST_CONTAINER;
405 if (!pIconsList || !pContainer) // nothing to do.
406 return;
407
408 switch (iSortType)
409 {
410 case CAIRO_DOCK_FM_SORT_BY_NAME:
411 pIconsList = cairo_dock_sort_icons_by_name (pIconsList);
412 break;
413 case CAIRO_DOCK_FM_SORT_BY_DATE:
414 g_list_foreach (pIconsList, (GFunc)_get_order, GINT_TO_POINTER (CAIRO_DOCK_FM_SORT_BY_DATE));
415 pIconsList = cairo_dock_sort_icons_by_order (pIconsList);
416 break;
417 case CAIRO_DOCK_FM_SORT_BY_SIZE:
418 g_list_foreach (pIconsList, (GFunc)_get_order, GINT_TO_POINTER (CAIRO_DOCK_FM_SORT_BY_SIZE));
419 pIconsList = cairo_dock_sort_icons_by_order (pIconsList);
420 break;
421 case CAIRO_DOCK_FM_SORT_BY_TYPE:
422 pIconsList = cairo_dock_sort_icons_by_extension (pIconsList);
423 break;
424 default:
425 break;
426 }
427
428 if (myDock)
429 {
430 CairoDock *pSubDock = CAIRO_DOCK (pContainer);
431 pSubDock->icons = pIconsList;
432 cairo_dock_calculate_dock_icons (pSubDock);
433 cairo_dock_update_dock_size (pSubDock);
434 }
435 else
436 {
437 myDesklet->icons = pIconsList;
438 if (myDesklet->pRenderer && myDesklet->pRenderer->calculate_icons != NULL)
439 myDesklet->pRenderer->calculate_icons (myDesklet); // don't use cairo_dock_update_desklet_icons(), since the number of icons didn't change.
440 }
441
442 // redraw
443 cairo_dock_redraw_container (pContainer);
444
445 myConfig.iSortType = iSortType; // we don't update the conf file, it's a temporary modification.
446 }
447