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 project,
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
**********************************************************************************/
30
#include <sys/types.h>
33
#include <glib/gstdio.h>
35
#include "cairo-dock.h"
37
#include "applet-draw.h"
38
#include "applet-struct.h"
39
#include "applet-trashes-manager.h"
41
extern int lstat (const char *path, struct stat *buf);
43
static GStaticRWLock s_mTasksMutex = G_STATIC_RW_LOCK_INIT;
44
static GList *s_pTasksList = NULL;
45
static int s_iThreadIsRunning = 0;
46
static int s_iSidTimerRedraw = 0;
47
static int s_iSidDelayMeasure = 0;
49
gpointer cd_dustbin_threaded_calculation (gpointer data)
54
//\________________________ On quitte si plus de message.
55
g_static_rw_lock_writer_lock (&s_mTasksMutex);
56
if (s_pTasksList == NULL) // aucun message dans la file d'attente, on quitte.
58
cd_message ("*** plus de message, on quitte le thread.");
59
g_atomic_int_set (&s_iThreadIsRunning, 0);
60
g_static_rw_lock_writer_unlock (&s_mTasksMutex);
64
//\________________________ On recupere le message de tete.
65
GList *pFirstElement = s_pTasksList;
66
CdDustbinMessage *pMessage = pFirstElement->data;
67
CdDustbin *pDustbin = pMessage->pDustbin;
68
gchar *cURI = pMessage->cURI;
69
cd_message ("*** recuperation du message : %s", cURI);
71
//\________________________ On l'enleve de la liste.
72
s_pTasksList = g_list_remove (s_pTasksList, pMessage);
75
g_static_rw_lock_writer_unlock (&s_mTasksMutex);
77
//\________________________ On traite le message.
78
if (pDustbin == NULL) // recalcul complet.
80
cd_dustbin_task_all_dustbins (&myData.iNbFiles, &myData.iSize);
82
else if (cURI == NULL)
84
g_atomic_int_add (&myData.iNbFiles, - pDustbin->iNbFiles);
85
g_atomic_int_add (&myData.iSize, - pDustbin->iSize);
86
cd_dustbin_task_directory (pDustbin->cPath, myConfig.iQuickInfoType, pDustbin, &pDustbin->iNbFiles, &pDustbin->iSize);
87
g_atomic_int_add (&myData.iNbFiles, pDustbin->iNbFiles);
88
g_atomic_int_add (&myData.iSize, pDustbin->iSize);
90
else // calcul d'un fichier supplementaire.
92
cd_dustbin_task_one_file (cURI, myConfig.iQuickInfoType, pDustbin, &iNbFiles, &iSize);
93
pDustbin->iNbFiles += iNbFiles;
94
pDustbin->iSize += iSize;
95
g_atomic_int_add (&myData.iNbFiles, iNbFiles);
96
g_atomic_int_add (&myData.iSize, iSize);
102
cd_message ("*** fin du thread -> %dfichiers , %db", myData.iNbFiles, myData.iSize);
108
void cd_dustbin_free_message (CdDustbinMessage *pMessage)
110
if (pMessage == NULL)
112
g_free (pMessage->cURI);
116
void cd_dustbin_remove_all_messages (void)
118
g_list_foreach (s_pTasksList, (GFunc) cd_dustbin_free_message, NULL);
119
g_list_free (s_pTasksList);
123
void cd_dustbin_remove_messages (CdDustbin *pDustbin)
125
CdDustbinMessage *pMessage;
126
GList *pElement = s_pTasksList, *pNextElement;
127
while (pElement != NULL)
129
pMessage = pElement->data;
130
pNextElement = pElement->next;
132
if (pMessage->pDustbin == pDustbin) // on l'enleve de la liste et on l'efface.
134
s_pTasksList = g_list_remove (s_pTasksList, pMessage);
135
cd_dustbin_free_message (pMessage);
137
pElement = pNextElement;
142
gboolean cd_dustbin_is_calculating (void)
144
int iThreadIsRunning = g_atomic_int_get (&s_iThreadIsRunning);
145
return (iThreadIsRunning != 0 || s_iSidDelayMeasure != 0);
148
static gboolean _cd_dustbin_check_for_redraw (gpointer data)
150
int iThreadIsRunning = g_atomic_int_get (&s_iThreadIsRunning);
151
cd_message ("%s (%d)", __func__, iThreadIsRunning);
152
if (! iThreadIsRunning)
154
s_iSidTimerRedraw = 0;
155
cd_message (" redessin (%d,%d)\n", myData.iNbFiles, myData.iSize);
156
if (myConfig.iQuickInfoType == CD_DUSTBIN_INFO_NB_FILES || myConfig.iQuickInfoType == CD_DUSTBIN_INFO_WEIGHT)
157
cd_dustbin_draw_quick_info (TRUE);
158
cd_dustbin_signal_full_dustbin ();
163
static void _cd_dustbin_launch_task (void)
166
if (g_atomic_int_compare_and_exchange (&s_iThreadIsRunning, 0, 1)) // il etait egal a 0, on lui met 1 et on lance le thread.
168
cd_message (" ==> lancement du thread de calcul\n");
169
if (s_iSidTimerRedraw == 0)
170
s_iSidTimerRedraw = g_timeout_add (150, (GSourceFunc) _cd_dustbin_check_for_redraw, (gpointer) NULL);
172
GError *erreur = NULL;
173
GThread* pThread = g_thread_create ((GThreadFunc) cd_dustbin_threaded_calculation,
179
cd_message ("Attention : %s\n", erreur->message);
180
g_error_free (erreur);
184
static gboolean _cd_dustbin_launch_task_delayed (gpointer *data)
186
_cd_dustbin_launch_task ();
187
s_iSidDelayMeasure = 0;
190
void cd_dustbin_add_message (gchar *cURI, CdDustbin *pDustbin)
192
cd_message ("%s (%s)", __func__, cURI);
193
g_static_rw_lock_writer_lock (&s_mTasksMutex);
195
CdDustbinMessage *pNewMessage = g_new (CdDustbinMessage, 1);
196
pNewMessage->cURI = cURI;
197
pNewMessage->pDustbin = pDustbin;
199
if (pDustbin == NULL)
201
cd_dustbin_remove_all_messages ();
202
s_pTasksList = g_list_prepend (s_pTasksList, pNewMessage);
203
g_atomic_int_set (&myData.iNbFiles, -1); // en cours.
204
g_atomic_int_set (&myData.iSize, -1); // en cours.
206
else if (cURI == NULL)
208
cd_dustbin_remove_messages (pDustbin);
209
s_pTasksList = g_list_prepend (s_pTasksList, pNewMessage);
213
s_pTasksList = g_list_append (s_pTasksList, pNewMessage);
215
g_static_rw_lock_writer_unlock (&s_mTasksMutex);
217
if (! g_atomic_int_get (&s_iThreadIsRunning))
219
if (s_iSidDelayMeasure != 0)
221
cd_message (" lancement calcul retarde");
222
g_source_remove (s_iSidDelayMeasure);
223
s_iSidDelayMeasure = 0;
225
s_iSidDelayMeasure = g_timeout_add (400, (GSourceFunc) _cd_dustbin_launch_task_delayed, NULL); // on retarde le calcul, car il y'a probablement d'autres fichiers qui vont arriver.
227
if (pDustbin == NULL)
228
cd_dustbin_draw_quick_info (TRUE);
233
int cd_dustbin_count_trashes (gchar *cDirectory)
235
//g_print ("%s (%s)\n", __func__, cDirectory);
236
GError *erreur = NULL;
237
GDir *dir = g_dir_open (cDirectory, 0, &erreur);
240
cd_warning ("Attention : %s", erreur->message);
241
g_error_free (erreur);
246
while (g_dir_read_name (dir) != NULL)
255
void cd_dustbin_task_directory (gchar *cDirectory, CdDustbinInfotype iInfoType, CdDustbin *pDustbin, int *iNbFiles, int *iSize)
257
cd_debug ("%s (%s)", __func__, cDirectory);
258
g_atomic_int_set (iNbFiles, 0);
259
g_atomic_int_set (iSize, 0);
261
GError *erreur = NULL;
262
GDir *dir = g_dir_open (cDirectory, 0, &erreur);
265
cd_warning ("Attention : %s", erreur->message);
266
g_error_free (erreur);
270
int iNbFilesSubDir, iSizeSubDir;
272
const gchar *cFileName;
273
CdDustbinMessage *pMessage;
274
GString *sFilePath = g_string_new ("");
275
while ((cFileName = g_dir_read_name (dir)) != NULL)
277
g_static_rw_lock_reader_lock (&s_mTasksMutex);
278
if (s_pTasksList != NULL)
280
pMessage = s_pTasksList->data;
281
if (pMessage->pDustbin == NULL || pMessage->pDustbin == pDustbin) // une demande de recalcul complet a ete faite sur cette poubelle, on interromp le calcul.
283
g_static_rw_lock_reader_unlock (&s_mTasksMutex);
287
g_static_rw_lock_reader_unlock (&s_mTasksMutex);
289
g_string_printf (sFilePath, "%s/%s", cDirectory, cFileName);
290
if (lstat (sFilePath->str, &buf) != -1)
292
if (S_ISDIR (buf.st_mode))
294
cd_debug (" %s est un repertoire", sFilePath->str);
297
cd_dustbin_task_directory (sFilePath->str, iInfoType, pDustbin, &iNbFilesSubDir, &iSizeSubDir);
298
g_atomic_int_add (iNbFiles, iNbFilesSubDir);
299
g_atomic_int_add (iSize, iSizeSubDir);
300
cd_debug (" + %d fichiers dans ce sous-repertoire", iNbFilesSubDir );
304
g_atomic_int_add (iNbFiles, 1);
305
g_atomic_int_add (iSize, buf.st_size);
310
g_string_free (sFilePath, TRUE);
314
void cd_dustbin_task_one_file (gchar *cURI, CdDustbinInfotype iInfoType, CdDustbin *pDustbin, int *iNbFiles, int *iSize)
316
cd_debug ("%s (%s)", __func__, cURI);
318
GError *erreur = NULL;
319
gchar *cFilePath = g_filename_from_uri (cURI, NULL, &erreur);
322
cd_warning ("Attention : %s", erreur->message);
323
g_error_free (erreur);
324
g_atomic_int_set (iNbFiles, 0);
325
g_atomic_int_set (iSize, 0);
330
if (lstat (cFilePath, &buf) != -1)
332
if (S_ISDIR (buf.st_mode))
334
cd_dustbin_task_directory (cFilePath, iInfoType, pDustbin, iNbFiles, iSize);
338
g_atomic_int_set (iNbFiles, 1);
339
g_atomic_int_set (iSize, buf.st_size);
344
g_atomic_int_set (iNbFiles, 0);
345
g_atomic_int_set (iSize, 0);
350
void cd_dustbin_task_all_dustbins (int *iNbFiles, int *iSize)
353
g_atomic_int_set (iNbFiles, 0);
354
g_atomic_int_set (iSize, 0);
356
int iNbFilesHere, iSizeHere;
359
for (pElement = myData.pDustbinsList; pElement != NULL; pElement = pElement->next)
361
pDustbin = pElement->data;
363
cd_dustbin_task_directory (pDustbin->cPath, myConfig.iQuickInfoType, pDustbin, &pDustbin->iNbFiles, &pDustbin->iSize);
365
g_atomic_int_add (iNbFiles, pDustbin->iNbFiles);
366
g_atomic_int_add (iSize, pDustbin->iSize);
370
static void _cd_dustbin_empty_dir (const gchar *cDirectory)
372
g_return_if_fail (cDirectory != NULL && *cDirectory != '\0' && strcmp (cDirectory, g_getenv ("HOME")) != 0);
373
gchar *cCommand = g_strdup_printf ("find '%s' -maxdepth 1 -mindepth 1 -exec rm -rf '{}' \\;", cDirectory); // un rm -rf * n'efface pas les fichiers caches.
374
cd_message (cCommand);
375
g_print ("***\n***%s\n***\n", cCommand);
376
///int r = system (cCommand);
377
cairo_dock_launch_command (cCommand); // est-ce que ca ne va pas saturer le file-monitor ?
381
void cd_dustbin_delete_trash (GtkMenuItem *menu_item, gchar *cDirectory)
384
if (cDirectory != NULL)
385
cQuestion = g_strdup_printf (D_("You're about to delete all files in %s. Sure ?"), cDirectory);
386
else if (myData.pDustbinsList != NULL)
387
cQuestion = g_strdup_printf (D_("You're about to delete all files in all dustbins. Sure ?"));
390
int answer = cairo_dock_ask_question_and_wait (cQuestion, myIcon, myContainer);
392
if (answer == GTK_RESPONSE_YES)
394
GString *sCommand = g_string_new ("");
395
if (cDirectory != NULL)
397
g_string_printf (sCommand, "rm -rf '%s'/* '%s'/.*", cDirectory, cDirectory);
398
_cd_dustbin_empty_dir (cDirectory);
404
for (pElement = myData.pDustbinsList; pElement != NULL; pElement = pElement->next)
406
pDustbin = pElement->data;
407
///g_string_append_printf (sCommand, "\"%s\"/* \"%s\"/.* ", pDustbin->cPath, pDustbin->cPath);
408
_cd_dustbin_empty_dir (pDustbin->cPath);
411
///cd_message (">>> %s", sCommand->str);
412
///system (sCommand->str); // g_spawn_command_line_async() ne marche pas pour celle-la.
414
gchar *cFileInfoPath= NULL;
415
gchar *cDefaultTrash = cairo_dock_fm_get_trash_path (g_getenv ("HOME"), &cFileInfoPath);
416
if (cDefaultTrash != NULL && cFileInfoPath != NULL) // il faut aussi effacer les infos.
418
if (cDirectory == NULL || strcmp (cDirectory, cDefaultTrash) == 0)
420
///g_string_printf (sCommand, "rm -rf \"%s\"/*info \"%s\"/.*info", cFileInfoPath, cFileInfoPath);
421
_cd_dustbin_empty_dir (cFileInfoPath);
422
///cd_message (">>> %s", sCommand->str);
423
///system (sCommand->str);
426
g_free (cDefaultTrash);
427
g_free (cFileInfoPath);
428
///g_string_free (sCommand, TRUE);
432
void cd_dustbin_show_trash (GtkMenuItem *menu_item, gchar *cDirectory)
434
if (myConfig.cDefaultBrowser != NULL)
436
GString *sCommand = g_string_new (myConfig.cDefaultBrowser);
437
if (cDirectory != NULL)
439
g_string_append_printf (sCommand, " %s", cDirectory);
441
else if (myData.pDustbinsList != NULL)
445
for (pElement = myData.pDustbinsList; pElement != NULL; pElement = pElement->next)
447
pDustbin = pElement->data;
448
g_string_append_printf (sCommand, " %s", pDustbin->cPath);
453
cd_message ("dustbin : %s", sCommand->str);
454
GError *erreur = NULL;
455
g_spawn_command_line_async (sCommand->str, &erreur);
458
cd_warning ("Dustbin : when trying to execute '%s' : %s", sCommand->str, erreur->message);
459
g_error_free (erreur);
460
cairo_dock_show_temporary_dialog (D_("A problem occured\nIf '%s' is not your usual file browser,\nyou can change it in the conf panel of this module"), myIcon, myContainer, 5000, myConfig.cDefaultBrowser);
462
g_string_free (sCommand, TRUE);
466
cairo_dock_fm_launch_uri (cDirectory != NULL ? cDirectory : "trash:/");
470
void cd_dustbin_sum_all_tasks (int *iNbFiles, int *iSize)
472
int iTotalMeasure = 0;
475
for (pElement = myData.pDustbinsList; pElement != NULL; pElement = pElement->next)
477
pDustbin = pElement->data;
478
g_atomic_int_add (iNbFiles, pDustbin->iNbFiles);
479
g_atomic_int_add (iSize, pDustbin->iSize);
485
gboolean cd_dustbin_is_monitored (gchar *cDustbinPath)
487
g_return_val_if_fail (cDustbinPath != NULL, FALSE);
490
for (pElement = myData.pDustbinsList; pElement != NULL; pElement = pElement->next)
492
pDustbin = pElement->data;
493
if (pDustbin->cPath != NULL && strcmp (pDustbin->cPath, cDustbinPath) == 0)
499
gboolean cd_dustbin_add_one_dustbin (gchar *cDustbinPath, int iAuthorizedWeight)
501
g_return_val_if_fail (cDustbinPath != NULL, FALSE);
502
cd_message ("%s (%s)", __func__, cDustbinPath);
504
CdDustbin *pDustbin = g_new0 (CdDustbin, 1);
505
pDustbin->cPath = cDustbinPath;
506
pDustbin->iAuthorizedWeight = iAuthorizedWeight;
507
myData.pDustbinsList = g_list_prepend (myData.pDustbinsList, pDustbin);
509
if (cairo_dock_fm_add_monitor_full (cDustbinPath, TRUE, NULL, (CairoDockFMMonitorCallback) cd_dustbin_on_file_event, pDustbin))
511
pDustbin->iNbTrashes = cd_dustbin_count_trashes (cDustbinPath);
512
g_atomic_int_add (&myData.iNbTrashes, pDustbin->iNbTrashes);
513
cd_message (" myConfig.iNbTrashes <- %d", myData.iNbTrashes);
520
void cd_dustbin_free_dustbin (CdDustbin *pDustbin)
522
g_free (pDustbin->cPath);
526
void cd_dustbin_remove_all_dustbins (void)
528
g_static_rw_lock_writer_lock (&s_mTasksMutex);
529
cd_dustbin_remove_all_messages ();
530
g_static_rw_lock_writer_unlock (&s_mTasksMutex); // un g_thread_join() serait peut-etre necessaire.
534
for (pElement = myData.pDustbinsList; pElement != NULL; pElement = pElement->next)
536
pDustbin = pElement->data;
537
cairo_dock_fm_remove_monitor_full (pDustbin->cPath, FALSE, NULL);
538
cd_dustbin_free_dustbin (pDustbin);
540
g_list_free (myData.pDustbinsList);
541
myData.pDustbinsList = NULL;
542
myData.iNbTrashes = 0;