1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
2 
3    caja-desktop-link.c: Class that handles the links on the desktop
4 
5    Copyright (C) 2003 Red Hat, Inc.
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 as
9    published by the Free Software Foundation; either version 2 of the
10    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 GNU
15    General Public License for more details.
16 
17    You should have received a copy of the GNU General Public
18    License along with this program; if not, write to the
19    Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20    Boston, MA 02110-1301, USA.
21 
22    Author: Alexander Larsson <alexl@redhat.com>
23 */
24 
25 #include <config.h>
26 #include <glib/gi18n.h>
27 #include <gio/gio.h>
28 #include <string.h>
29 
30 #include "caja-desktop-link.h"
31 #include "caja-desktop-link-monitor.h"
32 #include "caja-desktop-icon-file.h"
33 #include "caja-directory-private.h"
34 #include "caja-desktop-directory.h"
35 #include "caja-icon-names.h"
36 #include "caja-file-utilities.h"
37 #include "caja-trash-monitor.h"
38 #include "caja-global-preferences.h"
39 
40 struct _CajaDesktopLinkPrivate
41 {
42     CajaDesktopLinkType type;
43     char *filename;
44     char *display_name;
45     GFile *activation_location;
46     GIcon *icon;
47 
48     CajaDesktopIconFile *icon_file;
49 
50     GObject *signal_handler_obj;
51     gulong signal_handler;
52 
53     /* Just for mount icons: */
54     GMount *mount;
55 };
56 
G_DEFINE_TYPE_WITH_PRIVATE(CajaDesktopLink,caja_desktop_link,G_TYPE_OBJECT)57 G_DEFINE_TYPE_WITH_PRIVATE (CajaDesktopLink, caja_desktop_link, G_TYPE_OBJECT)
58 
59 static void
60 create_icon_file (CajaDesktopLink *link)
61 {
62     link->details->icon_file = caja_desktop_icon_file_new (link);
63 }
64 
65 static void
caja_desktop_link_changed(CajaDesktopLink * link)66 caja_desktop_link_changed (CajaDesktopLink *link)
67 {
68     if (link->details->icon_file != NULL)
69     {
70         caja_desktop_icon_file_update (link->details->icon_file);
71     }
72 }
73 
74 static void
mount_changed_callback(GMount * mount,CajaDesktopLink * link)75 mount_changed_callback (GMount *mount, CajaDesktopLink *link)
76 {
77     g_free (link->details->display_name);
78     if (link->details->activation_location)
79     {
80         g_object_unref (link->details->activation_location);
81     }
82     if (link->details->icon)
83     {
84         g_object_unref (link->details->icon);
85     }
86 
87     link->details->display_name = g_mount_get_name (mount);
88     link->details->activation_location = g_mount_get_default_location (mount);
89     link->details->icon = g_mount_get_icon (mount);
90 
91     caja_desktop_link_changed (link);
92 }
93 
94 static void
caja_desktop_link_ensure_display_name(CajaDesktopLink * link)95 caja_desktop_link_ensure_display_name (CajaDesktopLink *link)
96 {
97     if (link->details->display_name[0] == 0) {
98         g_free (link->details->display_name);
99 
100         switch (link->details->type)
101         {
102         case CAJA_DESKTOP_LINK_HOME:
103             /* Translators: If it's hard to compose a good home
104              * icon name from the user name, you can use a string without
105              * an "%s" here, in which case the home icon name will not
106              * include the user's name, which should be fine. To avoid a
107              * warning, put "%.0s" somewhere in the string, which will
108              * match the user name string passed by the C code, but not
109              * put the user name in the final string.
110              */
111             link->details->display_name = g_strdup_printf (_("%s's Home"), g_get_user_name ());
112             break;
113         case CAJA_DESKTOP_LINK_COMPUTER:
114             link->details->display_name = g_strdup (_("Computer"));
115             break;
116         case CAJA_DESKTOP_LINK_NETWORK:
117             link->details->display_name = g_strdup (_("Network Servers"));
118             break;
119         case CAJA_DESKTOP_LINK_TRASH:
120             link->details->display_name = g_strdup (_("Trash"));
121             break;
122         default:
123         case CAJA_DESKTOP_LINK_MOUNT:
124             g_assert_not_reached();
125         }
126     }
127 }
128 
129 static void
trash_state_changed_callback(CajaTrashMonitor * trash_monitor,gboolean state,gpointer callback_data)130 trash_state_changed_callback (CajaTrashMonitor *trash_monitor,
131                               gboolean state,
132                               gpointer callback_data)
133 {
134     CajaDesktopLink *link;
135 
136     link = CAJA_DESKTOP_LINK (callback_data);
137     g_assert (link->details->type == CAJA_DESKTOP_LINK_TRASH);
138 
139     if (link->details->icon)
140     {
141         g_object_unref (link->details->icon);
142     }
143     link->details->icon = caja_trash_monitor_get_icon ();
144 
145     caja_desktop_link_changed (link);
146 }
147 
148 static void
home_name_changed(gpointer callback_data)149 home_name_changed (gpointer callback_data)
150 {
151     CajaDesktopLink *link;
152 
153     link = CAJA_DESKTOP_LINK (callback_data);
154     g_assert (link->details->type == CAJA_DESKTOP_LINK_HOME);
155 
156     g_free (link->details->display_name);
157 
158     link->details->display_name = g_settings_get_string (caja_desktop_preferences,
159                                                          CAJA_PREFERENCES_DESKTOP_HOME_NAME);
160 
161     caja_desktop_link_ensure_display_name (link);
162     caja_desktop_link_changed (link);
163 }
164 
165 static void
computer_name_changed(gpointer callback_data)166 computer_name_changed (gpointer callback_data)
167 {
168     CajaDesktopLink *link;
169 
170     link = CAJA_DESKTOP_LINK (callback_data);
171     g_assert (link->details->type == CAJA_DESKTOP_LINK_COMPUTER);
172 
173     g_free (link->details->display_name);
174     link->details->display_name = g_settings_get_string (caja_desktop_preferences, CAJA_PREFERENCES_DESKTOP_COMPUTER_NAME);
175 
176     caja_desktop_link_ensure_display_name (link);
177     caja_desktop_link_changed (link);
178 }
179 
180 static void
trash_name_changed(gpointer callback_data)181 trash_name_changed (gpointer callback_data)
182 {
183     CajaDesktopLink *link;
184 
185     link = CAJA_DESKTOP_LINK (callback_data);
186     g_assert (link->details->type == CAJA_DESKTOP_LINK_TRASH);
187 
188     g_free (link->details->display_name);
189     link->details->display_name = g_settings_get_string (caja_desktop_preferences, CAJA_PREFERENCES_DESKTOP_TRASH_NAME);
190 
191     caja_desktop_link_ensure_display_name (link);
192     caja_desktop_link_changed (link);
193 }
194 
195 static void
network_name_changed(gpointer callback_data)196 network_name_changed (gpointer callback_data)
197 {
198     CajaDesktopLink *link;
199 
200     link = CAJA_DESKTOP_LINK (callback_data);
201     g_assert (link->details->type == CAJA_DESKTOP_LINK_NETWORK);
202 
203     g_free (link->details->display_name);
204     link->details->display_name = g_settings_get_string (caja_desktop_preferences, CAJA_PREFERENCES_DESKTOP_NETWORK_NAME);
205 
206     caja_desktop_link_ensure_display_name (link);
207     caja_desktop_link_changed (link);
208 }
209 
210 CajaDesktopLink *
caja_desktop_link_new(CajaDesktopLinkType type)211 caja_desktop_link_new (CajaDesktopLinkType type)
212 {
213     CajaDesktopLink *link;
214 
215     link = CAJA_DESKTOP_LINK (g_object_new (CAJA_TYPE_DESKTOP_LINK, NULL));
216 
217     link->details->type = type;
218     switch (type)
219     {
220     case CAJA_DESKTOP_LINK_HOME:
221         link->details->filename = g_strdup ("home");
222         link->details->display_name = g_settings_get_string (caja_desktop_preferences, CAJA_PREFERENCES_DESKTOP_HOME_NAME);
223         link->details->activation_location = g_file_new_for_path (g_get_home_dir ());
224         link->details->icon = g_themed_icon_new (CAJA_ICON_HOME);
225 
226         g_signal_connect_swapped (caja_desktop_preferences,
227                                   "changed::" CAJA_PREFERENCES_DESKTOP_HOME_NAME,
228                                   G_CALLBACK (home_name_changed),
229                                   link);
230 
231         break;
232 
233     case CAJA_DESKTOP_LINK_COMPUTER:
234         link->details->filename = g_strdup ("computer");
235         link->details->display_name = g_settings_get_string (caja_desktop_preferences, CAJA_PREFERENCES_DESKTOP_COMPUTER_NAME);
236         link->details->activation_location = g_file_new_for_uri ("computer:///");
237         /* TODO: This might need a different icon: */
238         link->details->icon = g_themed_icon_new (CAJA_ICON_COMPUTER);
239 
240         g_signal_connect_swapped (caja_desktop_preferences,
241                                   "changed::" CAJA_PREFERENCES_DESKTOP_COMPUTER_NAME,
242                                   G_CALLBACK (computer_name_changed),
243                                   link);
244 
245         break;
246 
247     case CAJA_DESKTOP_LINK_TRASH:
248         link->details->filename = g_strdup ("trash");
249         link->details->display_name = g_settings_get_string (caja_desktop_preferences, CAJA_PREFERENCES_DESKTOP_TRASH_NAME);
250         link->details->activation_location = g_file_new_for_uri (EEL_TRASH_URI);
251         link->details->icon = caja_trash_monitor_get_icon ();
252 
253         g_signal_connect_swapped (caja_desktop_preferences,
254                                   "changed::" CAJA_PREFERENCES_DESKTOP_TRASH_NAME,
255                                   G_CALLBACK (trash_name_changed),
256                                   link);
257         link->details->signal_handler_obj = G_OBJECT (caja_trash_monitor_get ());
258         link->details->signal_handler =
259             g_signal_connect_object (caja_trash_monitor_get (), "trash_state_changed",
260                                      G_CALLBACK (trash_state_changed_callback), link, 0);
261         break;
262 
263     case CAJA_DESKTOP_LINK_NETWORK:
264         link->details->filename = g_strdup ("network");
265         link->details->display_name = g_settings_get_string (caja_desktop_preferences, CAJA_PREFERENCES_DESKTOP_NETWORK_NAME);
266         link->details->activation_location = g_file_new_for_uri ("network:///");
267         link->details->icon = g_themed_icon_new (CAJA_ICON_NETWORK);
268 
269         g_signal_connect_swapped (caja_desktop_preferences,
270                                   "changed::" CAJA_PREFERENCES_DESKTOP_NETWORK_NAME,
271                                   G_CALLBACK (network_name_changed),
272                                   link);
273         break;
274 
275     default:
276     case CAJA_DESKTOP_LINK_MOUNT:
277         g_assert_not_reached();
278     }
279 
280     caja_desktop_link_ensure_display_name (link);
281     create_icon_file (link);
282 
283     return link;
284 }
285 
286 CajaDesktopLink *
caja_desktop_link_new_from_mount(GMount * mount)287 caja_desktop_link_new_from_mount (GMount *mount)
288 {
289     CajaDesktopLink *link;
290     GVolume *volume;
291     char *name, *filename;
292 
293     link = CAJA_DESKTOP_LINK (g_object_new (CAJA_TYPE_DESKTOP_LINK, NULL));
294 
295     link->details->type = CAJA_DESKTOP_LINK_MOUNT;
296 
297     link->details->mount = g_object_ref (mount);
298 
299     /* We try to use the drive name to get somewhat stable filenames
300        for metadata */
301     volume = g_mount_get_volume (mount);
302     if (volume != NULL)
303     {
304         name = g_volume_get_name (volume);
305         g_object_unref (volume);
306     }
307     else
308     {
309         name = g_mount_get_name (mount);
310     }
311 
312     /* Replace slashes in name */
313     filename = g_strconcat (g_strdelimit (name, "/", '-'), ".volume", NULL);
314     link->details->filename =
315         caja_desktop_link_monitor_make_filename_unique (caja_desktop_link_monitor_get (),
316                 filename);
317     g_free (filename);
318     g_free (name);
319 
320     link->details->display_name = g_mount_get_name (mount);
321 
322     link->details->activation_location = g_mount_get_default_location (mount);
323     link->details->icon = g_mount_get_icon (mount);
324 
325     link->details->signal_handler_obj = G_OBJECT (mount);
326     link->details->signal_handler =
327         g_signal_connect (mount, "changed",
328                           G_CALLBACK (mount_changed_callback), link);
329 
330     create_icon_file (link);
331 
332     return link;
333 }
334 
335 GMount *
caja_desktop_link_get_mount(CajaDesktopLink * link)336 caja_desktop_link_get_mount (CajaDesktopLink *link)
337 {
338     if (link->details->mount)
339     {
340         return g_object_ref (link->details->mount);
341     }
342     return NULL;
343 }
344 
345 CajaDesktopLinkType
caja_desktop_link_get_link_type(CajaDesktopLink * link)346 caja_desktop_link_get_link_type (CajaDesktopLink *link)
347 {
348     return link->details->type;
349 }
350 
351 char *
caja_desktop_link_get_file_name(CajaDesktopLink * link)352 caja_desktop_link_get_file_name (CajaDesktopLink *link)
353 {
354     return g_strdup (link->details->filename);
355 }
356 
357 char *
caja_desktop_link_get_display_name(CajaDesktopLink * link)358 caja_desktop_link_get_display_name (CajaDesktopLink *link)
359 {
360     return g_strdup (link->details->display_name);
361 }
362 
363 GIcon *
caja_desktop_link_get_icon(CajaDesktopLink * link)364 caja_desktop_link_get_icon (CajaDesktopLink *link)
365 {
366     if (link->details->icon != NULL)
367     {
368         return g_object_ref (link->details->icon);
369     }
370     return NULL;
371 }
372 
373 GFile *
caja_desktop_link_get_activation_location(CajaDesktopLink * link)374 caja_desktop_link_get_activation_location (CajaDesktopLink *link)
375 {
376     if (link->details->activation_location)
377     {
378         return g_object_ref (link->details->activation_location);
379     }
380     return NULL;
381 }
382 
383 char *
caja_desktop_link_get_activation_uri(CajaDesktopLink * link)384 caja_desktop_link_get_activation_uri (CajaDesktopLink *link)
385 {
386     if (link->details->activation_location)
387     {
388         return g_file_get_uri (link->details->activation_location);
389     }
390     return NULL;
391 }
392 
393 
394 gboolean
caja_desktop_link_get_date(CajaDesktopLink * link,CajaDateType date_type,time_t * date)395 caja_desktop_link_get_date (CajaDesktopLink *link,
396                             CajaDateType     date_type,
397                             time_t               *date)
398 {
399     return FALSE;
400 }
401 
402 gboolean
caja_desktop_link_can_rename(CajaDesktopLink * link)403 caja_desktop_link_can_rename (CajaDesktopLink     *link)
404 {
405     return (link->details->type == CAJA_DESKTOP_LINK_HOME ||
406             link->details->type == CAJA_DESKTOP_LINK_TRASH ||
407             link->details->type == CAJA_DESKTOP_LINK_NETWORK ||
408             link->details->type == CAJA_DESKTOP_LINK_COMPUTER);
409 }
410 
411 gboolean
caja_desktop_link_rename(CajaDesktopLink * link,const char * name)412 caja_desktop_link_rename (CajaDesktopLink     *link,
413                           const char              *name)
414 {
415     switch (link->details->type)
416     {
417     case CAJA_DESKTOP_LINK_HOME:
418         g_settings_set_string (caja_desktop_preferences,
419                                CAJA_PREFERENCES_DESKTOP_HOME_NAME,
420                                name);
421         break;
422     case CAJA_DESKTOP_LINK_COMPUTER:
423         g_settings_set_string (caja_desktop_preferences,
424                                CAJA_PREFERENCES_DESKTOP_COMPUTER_NAME,
425                                name);
426         break;
427     case CAJA_DESKTOP_LINK_TRASH:
428         g_settings_set_string (caja_desktop_preferences,
429                                CAJA_PREFERENCES_DESKTOP_TRASH_NAME,
430                                name);
431         break;
432     case CAJA_DESKTOP_LINK_NETWORK:
433         g_settings_set_string (caja_desktop_preferences,
434                                CAJA_PREFERENCES_DESKTOP_NETWORK_NAME,
435                                name);
436         break;
437     default:
438         g_assert_not_reached ();
439         /* FIXME: Do we want volume renaming?
440          * We didn't support that before. */
441         break;
442     }
443 
444     return TRUE;
445 }
446 
447 static void
caja_desktop_link_init(CajaDesktopLink * link)448 caja_desktop_link_init (CajaDesktopLink *link)
449 {
450     link->details = caja_desktop_link_get_instance_private (link);
451 }
452 
453 static void
desktop_link_finalize(GObject * object)454 desktop_link_finalize (GObject *object)
455 {
456     CajaDesktopLink *link;
457 
458     link = CAJA_DESKTOP_LINK (object);
459 
460     if (link->details->signal_handler != 0)
461     {
462         if (g_signal_handler_is_connected(link->details->signal_handler_obj,
463                                              link->details->signal_handler)){
464             g_signal_handler_disconnect (link->details->signal_handler_obj,
465                                              link->details->signal_handler);
466         }
467     }
468 
469     if (link->details->icon_file != NULL)
470     {
471         caja_desktop_icon_file_remove (link->details->icon_file);
472         caja_file_unref (CAJA_FILE (link->details->icon_file));
473         link->details->icon_file = NULL;
474     }
475 
476     if (link->details->type == CAJA_DESKTOP_LINK_HOME)
477     {
478         g_signal_handlers_disconnect_by_func (caja_desktop_preferences,
479                                          home_name_changed,
480                                          link);
481     }
482 
483     if (link->details->type == CAJA_DESKTOP_LINK_COMPUTER)
484     {
485         g_signal_handlers_disconnect_by_func (caja_desktop_preferences,
486                                          computer_name_changed,
487                                          link);
488     }
489 
490     if (link->details->type == CAJA_DESKTOP_LINK_TRASH)
491     {
492         g_signal_handlers_disconnect_by_func (caja_desktop_preferences,
493                                          trash_name_changed,
494                                          link);
495     }
496 
497     if (link->details->type == CAJA_DESKTOP_LINK_NETWORK)
498     {
499         g_signal_handlers_disconnect_by_func (caja_desktop_preferences,
500                                          network_name_changed,
501                                          link);
502     }
503 
504     if (link->details->type == CAJA_DESKTOP_LINK_MOUNT)
505     {
506         g_object_unref (link->details->mount);
507     }
508 
509     g_free (link->details->filename);
510     g_free (link->details->display_name);
511     if (link->details->activation_location)
512     {
513         g_object_unref (link->details->activation_location);
514     }
515     if (link->details->icon)
516     {
517         g_object_unref (link->details->icon);
518     }
519 
520     G_OBJECT_CLASS (caja_desktop_link_parent_class)->finalize (object);
521 }
522 
523 static void
caja_desktop_link_class_init(CajaDesktopLinkClass * klass)524 caja_desktop_link_class_init (CajaDesktopLinkClass *klass)
525 {
526     GObjectClass *object_class;
527 
528     object_class = G_OBJECT_CLASS (klass);
529 
530     object_class->finalize = desktop_link_finalize;
531 }
532