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 #include <glib/gi18n.h>
23
24 #include "applet-struct.h"
25 #include "applet-load-icons.h"
26 #include "applet-drives.h"
27 #include "applet-bookmarks.h"
28
29 #define CD_SHORTCUT_DEFAULT_DIRECTORY_ICON_FILENAME "inode-directory"
30
_get_custom_name_and_uri(gchar * cOneBookmark,gchar ** cURI)31 static const gchar * _get_custom_name_and_uri (gchar *cOneBookmark, gchar **cURI)
32 {
33 const gchar *cUserName = NULL;
34 // should not happen if we add bookmarks via the dock or Nautilus
35 if (*cOneBookmark == '/')
36 {
37 // for 'gvfs_launch_uri':
38 *cURI = g_strconcat ("file://", cOneBookmark, NULL);
39 g_free (cOneBookmark);
40 }
41 else // it's a valid URI but does it have a custom name?
42 {
43 *cURI = cOneBookmark;
44 // a custom name is separated with a whitespace (no whitespace in the URI)
45 gchar *str = strchr (cOneBookmark, ' ');
46 if (str != NULL)
47 {
48 cUserName = str + 1;
49 *str = '\0';
50 }
51 }
52 return cUserName;
53 }
54
_cd_shortcuts_get_icon(gchar * cFileName,const gchar * cUserName,double fCurrentOrder)55 static Icon * _cd_shortcuts_get_icon (gchar *cFileName, const gchar *cUserName, double fCurrentOrder)
56 {
57 cd_debug ("New icon: %s, %s, %f", cFileName, cUserName, fCurrentOrder);
58
59 /* Nautilus adds custom prefixes which are not supported by gvfs...
60 * gvfs-integration plugin can read x-nautilus-desktop but not others, e.g.:
61 * x-nautilus-search://0/ => specific to Nautilus: open these URI with it.
62 * Note that all these URI have a user-name
63 */
64 if (g_str_has_prefix (cFileName, "x-nautilus-")
65 && ! g_str_has_prefix (cFileName, "x-nautilus-desktop://"))
66 {
67 Icon *pNewIcon = cairo_dock_create_dummy_launcher (
68 cUserName ? g_strdup (cUserName) : g_strdup (cFileName),
69 cairo_dock_search_icon_s_path (
70 CD_SHORTCUT_DEFAULT_DIRECTORY_ICON_FILENAME,
71 CAIRO_DOCK_DEFAULT_ICON_SIZE),
72 g_strdup_printf ("nautilus %s", cFileName),
73 NULL,
74 fCurrentOrder);
75 pNewIcon->iGroup = CD_BOOKMARK_GROUP;
76 pNewIcon->cBaseURI = cFileName;
77 pNewIcon->iVolumeID = CD_VOLUME_ID_BOOKMARK_CMD;
78 return pNewIcon;
79 }
80
81 gchar *cName, *cRealURI, *cIconName;
82 gboolean bIsDirectory;
83 gint iVolumeID;
84 gdouble fOrder;
85 if (! cairo_dock_fm_get_file_info (cFileName, &cName, &cRealURI, &cIconName,
86 &bIsDirectory, &iVolumeID, &fOrder, CAIRO_DOCK_FM_SORT_BY_NAME))
87 return NULL;
88 if (cUserName != NULL)
89 {
90 g_free (cName);
91 if (cName == NULL) // a bookmark on a unmounted system or a folder that doesn't exist any more
92 cName = g_strdup_printf ("%s\n[%s]", cUserName, D_("Unmounted"));
93 else
94 cName = g_strdup (cUserName);
95 }
96 else if (cName == NULL) // a bookmark on a unmounted system
97 {
98 gchar *cGuessedName = g_path_get_basename (cFileName);
99 cairo_dock_remove_html_spaces (cGuessedName); // or: g_uri_unescape_string
100 cName = g_strdup_printf ("%s\n[%s]", cGuessedName, D_("Unmounted"));
101 g_free (cGuessedName);
102 }
103 if (cRealURI == NULL)
104 cRealURI = g_strdup (cFileName);
105 if (cIconName == NULL)
106 cIconName = cairo_dock_search_icon_s_path (
107 CD_SHORTCUT_DEFAULT_DIRECTORY_ICON_FILENAME,
108 CAIRO_DOCK_DEFAULT_ICON_SIZE); // should be the default icon
109
110 Icon *pNewIcon = cairo_dock_create_dummy_launcher (cName,
111 cIconName,
112 cRealURI,
113 NULL,
114 fCurrentOrder);
115 pNewIcon->iGroup = CD_BOOKMARK_GROUP;
116 pNewIcon->cBaseURI = cFileName;
117 pNewIcon->iVolumeID = iVolumeID;
118 return pNewIcon;
119 }
120
_get_item_with_base_uri_icon(GList * pIconList,const gchar * cBaseURI)121 static GList * _get_item_with_base_uri_icon (GList *pIconList, const gchar *cBaseURI)
122 {
123 GList* ic;
124 Icon *pIcon;
125 for (ic = pIconList; ic != NULL; ic = ic->next)
126 {
127 pIcon = ic->data;
128 if (pIcon->cBaseURI != NULL && strcmp (pIcon->cBaseURI, cBaseURI) == 0)
129 return ic;
130 }
131 return NULL;
132 }
133
_remove_old_icons_and_free_list(GList * pOldBookmarkList)134 static void _remove_old_icons_and_free_list (GList *pOldBookmarkList)
135 {
136 GList* ic;
137 Icon *pIcon;
138 for (ic = pOldBookmarkList; ic != NULL; ic = ic->next)
139 {
140 pIcon = ic->data;
141 CD_APPLET_REMOVE_ICON_FROM_MY_ICONS_LIST (pIcon);
142 }
143 g_list_free (pOldBookmarkList);
144 }
145
cd_shortcuts_on_bookmarks_event(CairoDockFMEventType iEventType,const gchar * cURI,GldiModuleInstance * myApplet)146 void cd_shortcuts_on_bookmarks_event (CairoDockFMEventType iEventType, const gchar *cURI, GldiModuleInstance *myApplet)
147 {
148 static int iTime = 0;
149 iTime ++;
150 CD_APPLET_ENTER;
151 //g_print ("%s (%d)\n", __func__, iEventType);
152 GList *pIconsList = CD_APPLET_MY_ICONS_LIST;
153 GList *pOldBookmarkList;
154 Icon *icon;
155 GList *ic;
156 // optimization: skip the disks and networks, and point on the first bookmark.
157 for (ic = pIconsList; ic != NULL; ic = ic->next)
158 {
159 icon = ic->data;
160 if (icon->iGroup == (CairoDockIconGroup) CD_BOOKMARK_GROUP)
161 break;
162 }
163 /* Note that since the first bookmark is always the Home Folder,
164 * 'pIconsList' will never change when inserting/removing a bookmark.
165 */
166 pIconsList = ic;
167 GldiContainer *pContainer = CD_APPLET_MY_ICONS_LIST_CONTAINER;
168 CD_APPLET_LEAVE_IF_FAIL (pContainer != NULL);
169
170 // split the list: items can have been removed
171 pOldBookmarkList = pIconsList->next;
172 pIconsList->next = NULL;
173 pOldBookmarkList->prev = NULL;
174
175 // Bookmarks file has been modified
176 if (iEventType == CAIRO_DOCK_FILE_CREATED || iEventType == CAIRO_DOCK_FILE_MODIFIED)
177 {
178 cd_message ("The bookmarks list has changed");
179
180 //\____________________ Read bookmarks file
181 gchar *cContent = NULL;
182 gsize length=0;
183 GError *erreur = NULL;
184 g_file_get_contents (myData.cBookmarksURI, &cContent, &length, &erreur);
185 if (erreur != NULL)
186 {
187 cd_warning ("when trying to get the bookmarks : %s", erreur->message);
188 g_error_free (erreur);
189 }
190 else
191 {
192 gchar **cBookmarksList = g_strsplit (cContent, "\n", -1);
193 g_free (cContent);
194
195 //\____________________ Read the content.
196 /* Bookmarks are listed in the order of the file; we need to
197 * reorder each icon in case a bookmark has changed its place, or
198 * if a new one appeared (the first one is always the Home Folder).
199 */
200 double fCurrentOrder = 1.;
201 gchar *cOneBookmark;
202 Icon *pNewIcon, *pExistingIcon;
203 GList *pExistingIconNode;
204 const gchar *cUserName;
205 int i;
206 for (i = 0; cBookmarksList[i] != NULL; i ++)
207 {
208 cOneBookmark = cBookmarksList[i];
209 if (*cOneBookmark == '\0' || *cOneBookmark == '#')
210 {
211 g_free (cOneBookmark);
212 continue;
213 }
214
215 // Grab the custom name if any
216 cUserName = _get_custom_name_and_uri (cBookmarksList[i], &cOneBookmark);
217
218 // Check if the icon already exists and has changed
219 pExistingIconNode = _get_item_with_base_uri_icon (pOldBookmarkList, cOneBookmark);
220 if (pExistingIconNode != NULL)
221 {
222 pExistingIcon = pExistingIconNode->data;
223 // move this node to the subdock icons list
224 pOldBookmarkList = g_list_delete_link (pOldBookmarkList, pExistingIconNode);
225 pIconsList = g_list_insert (pIconsList, pExistingIcon, 1); // after the home, will be sorted later
226 if (cUserName && g_strcmp0 (pExistingIcon->cName, cUserName) != 0)
227 {
228 CD_APPLET_REMOVE_ICON_FROM_MY_ICONS_LIST (pExistingIcon); // will destroy it
229 pExistingIcon = NULL;
230 }
231 else
232 {
233 fCurrentOrder++;
234 g_free (cOneBookmark);
235 }
236 }
237 else
238 pExistingIcon = NULL;
239
240 if (pExistingIcon == NULL)
241 {
242 pNewIcon = _cd_shortcuts_get_icon (cOneBookmark,
243 cUserName, fCurrentOrder);
244 if (pNewIcon)
245 {
246 CD_APPLET_ADD_ICON_IN_MY_ICONS_LIST (pNewIcon);
247 fCurrentOrder++;
248 }
249 else
250 {
251 cd_warning ("couldn't get info on bookmark '%s'", cOneBookmark);
252 g_free (cOneBookmark);
253 }
254 }
255 }
256 g_free (cBookmarksList);
257
258 _remove_old_icons_and_free_list (pOldBookmarkList);
259
260 /* Again, since 'Home Folder' is always the first bookmark,
261 * the head of the list won't change even if there are only bookmarks
262 * (so we don't need to re-assigne it to the container).
263 */
264 cairo_dock_sort_icons_by_order (pIconsList);
265 }
266 }
267 CD_APPLET_LEAVE();
268 }
269
cd_shortcuts_remove_one_bookmark(const gchar * cURI,GldiModuleInstance * myApplet)270 void cd_shortcuts_remove_one_bookmark (const gchar *cURI, GldiModuleInstance *myApplet)
271 {
272 g_return_if_fail (cURI != NULL);
273 cd_message ("%s (%s)", __func__, cURI);
274
275 gchar *cContent = NULL;
276 gsize length=0;
277 GError *erreur = NULL;
278 g_file_get_contents (myData.cBookmarksURI, &cContent, &length, &erreur);
279 if (erreur != NULL)
280 {
281 cd_warning ("while trying to read bookmarks file : %s", erreur->message);
282 g_error_free (erreur);
283 }
284 else
285 {
286 gchar **cBookmarksList = g_strsplit (cContent, "\n", -1);
287 g_free (cContent);
288 gchar *cOneBookmark, *str;
289 gboolean bFound = FALSE;
290 int i = 0;
291 for (i = 0; cBookmarksList[i] != NULL; i ++)
292 {
293 cOneBookmark = cBookmarksList[i];
294 if (*cOneBookmark == '\0' || *cOneBookmark == '#')
295 continue;
296
297 str = strchr (cOneBookmark, ' ');
298 if ((str && strncmp (cOneBookmark, cURI, str - cOneBookmark) == 0)
299 || (!str && strcmp (cOneBookmark, cURI) == 0))
300 {
301 // remove this element from the array
302 int j;
303 for (j = i; cBookmarksList[j] != NULL; j ++)
304 {
305 cBookmarksList[j] = cBookmarksList[j+1];
306 }
307 // free the removed element.
308 g_free (cOneBookmark);
309 // quit the loop
310 bFound = TRUE;
311 break;
312 }
313 }
314
315 if (! bFound)
316 {
317 cd_warning ("bookmark '%s' not found", cURI);
318 }
319 else
320 {
321 cContent = g_strjoinv ("\n", cBookmarksList);
322 g_file_set_contents (myData.cBookmarksURI, cContent, -1, &erreur);
323 if (erreur != NULL)
324 {
325 cd_warning ("while trying to write bookmarks file : %s", erreur->message);
326 g_error_free (erreur);
327 }
328 g_free (cContent);
329 }
330 g_strfreev (cBookmarksList);
331 }
332 }
333
cd_shortcuts_rename_one_bookmark(const gchar * cURI,const gchar * cName,GldiModuleInstance * myApplet)334 void cd_shortcuts_rename_one_bookmark (const gchar *cURI, const gchar *cName, GldiModuleInstance *myApplet)
335 {
336 g_return_if_fail (cURI != NULL);
337 cd_message ("%s (%s, %s)", __func__, cURI, cName);
338
339 gchar *cContent = NULL;
340 gsize length=0;
341 GError *erreur = NULL;
342 g_file_get_contents (myData.cBookmarksURI, &cContent, &length, &erreur);
343 if (erreur != NULL)
344 {
345 cd_warning ("while trying to read bookmarks file : %s", erreur->message);
346 g_error_free (erreur);
347 }
348 else
349 {
350 gchar **cBookmarksList = g_strsplit (cContent, "\n", -1);
351 g_free (cContent);
352 gchar *cOneBookmark, *str;
353 int i = 0;
354 for (i = 0; cBookmarksList[i] != NULL; i ++)
355 {
356 cOneBookmark = cBookmarksList[i];
357 if (*cOneBookmark == '\0' || *cOneBookmark == '#')
358 continue;
359
360 str = strchr (cOneBookmark, ' ');
361 if ((str && strncmp (cOneBookmark, cURI, str - cOneBookmark) == 0) || (!str && strcmp (cOneBookmark, cURI) == 0))
362 {
363 cBookmarksList[i] = g_strdup_printf ("%s %s", cURI, cName);
364 g_free (cOneBookmark);
365 break;
366 }
367 }
368
369 if (cBookmarksList[i] == NULL)
370 {
371 cd_warning ("bookmark '%s' not found", cURI);
372 }
373 else
374 {
375 cContent = g_strjoinv ("\n", cBookmarksList);
376 g_file_set_contents (myData.cBookmarksURI, cContent, -1, &erreur);
377 if (erreur != NULL)
378 {
379 cd_warning ("while trying to write bookmarks file : %s", erreur->message);
380 g_error_free (erreur);
381 }
382 g_free (cContent);
383 }
384 g_strfreev (cBookmarksList);
385 }
386 }
387
cd_shortcuts_add_one_bookmark(const gchar * cURI,GldiModuleInstance * myApplet)388 void cd_shortcuts_add_one_bookmark (const gchar *cURI, GldiModuleInstance *myApplet)
389 {
390 g_return_if_fail (cURI != NULL);
391 cd_message ("%s (%s)", __func__, cURI);
392
393 // see if we need to add a new line before the new URI.
394 gchar *cContent = NULL;
395 gsize length = 0;
396 g_file_get_contents (myData.cBookmarksURI,
397 &cContent,
398 &length,
399 NULL);
400 gboolean bAddNewLine = (cContent && length > 0 && cContent[length-1] != '\n');
401 g_free (cContent);
402
403 // append the new URI to the file.
404 FILE *f = fopen (myData.cBookmarksURI, "a");
405 if (f != NULL)
406 {
407 gchar *cNewLine = g_strdup_printf ("%s%s\n", bAddNewLine ? "\n" : "", cURI);
408 fputs(cNewLine, f);
409 g_free (cNewLine);
410 fclose (f);
411 }
412 }
413
cd_shortcuts_list_bookmarks(gchar * cBookmarkFilePath,GldiModuleInstance * myApplet)414 GList *cd_shortcuts_list_bookmarks (gchar *cBookmarkFilePath, GldiModuleInstance *myApplet)
415 {
416 GList *pBookmarkIconList = NULL;
417 Icon *pNewIcon;
418 double fCurrentOrder = 0.;
419
420 // Home
421 gchar *cHome = g_strdup_printf ("file://%s", g_getenv ("HOME"));
422 pNewIcon = _cd_shortcuts_get_icon (cHome, D_("Home Folder"), fCurrentOrder++);
423 if (pNewIcon != NULL)
424 {
425 _init_disk_usage (pNewIcon, myApplet);
426 CDDiskUsage *pDiskUsage = CD_APPLET_GET_MY_ICON_DATA (pNewIcon);
427 if (pDiskUsage) // so that this bookmark will never be considered old, and therefore removed.
428 pDiskUsage->iLastCheckTime = 1e9;
429 pBookmarkIconList = g_list_append (pBookmarkIconList, pNewIcon);
430 }
431 else
432 g_free (cHome);
433
434 gchar *cContent = NULL;
435 gsize length = 0;
436 GError *erreur = NULL;
437 g_file_get_contents (cBookmarkFilePath, &cContent, &length, &erreur);
438 if (erreur != NULL)
439 {
440 cd_warning ("Attention: %s\n no bookmark will be available", erreur->message);
441 g_error_free (erreur);
442 }
443 else
444 {
445 gchar **cBookmarksList = g_strsplit (cContent, "\n", -1);
446 g_free (cContent);
447
448 gchar *cOneBookmark;
449 const gchar *cUserName;
450 int i = 0;
451 for (i = 0; cBookmarksList[i] != NULL; i ++)
452 {
453 cUserName = _get_custom_name_and_uri (cBookmarksList[i], &cOneBookmark);
454 if (*cOneBookmark != '\0' && *cOneBookmark != '#')
455 {
456 cd_message (" + 1 bookmark : %s", cOneBookmark);
457 pNewIcon = _cd_shortcuts_get_icon (cOneBookmark, cUserName, fCurrentOrder++);
458 if (pNewIcon)
459 pBookmarkIconList = g_list_append (pBookmarkIconList, pNewIcon);
460 else
461 g_free (cOneBookmark);
462 }
463 else
464 {
465 g_free (cOneBookmark);
466 }
467 }
468 g_free (cBookmarksList);
469 }
470 return pBookmarkIconList;
471 }
472