summaryrefslogtreecommitdiff
path: root/src/file-manager/fm-desktop-icon-view.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/file-manager/fm-desktop-icon-view.c')
-rw-r--r--src/file-manager/fm-desktop-icon-view.c881
1 files changed, 881 insertions, 0 deletions
diff --git a/src/file-manager/fm-desktop-icon-view.c b/src/file-manager/fm-desktop-icon-view.c
new file mode 100644
index 00000000..4a1bab93
--- /dev/null
+++ b/src/file-manager/fm-desktop-icon-view.c
@@ -0,0 +1,881 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* fm-desktop-icon-view.c - implementation of icon view for managing the desktop.
+
+ Copyright (C) 2000, 2001 Eazel, Inc.mou
+
+ The Mate Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Mate Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Mate Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Authors: Mike Engber <[email protected]>
+ Gene Z. Ragan <[email protected]>
+ Miguel de Icaza <[email protected]>
+*/
+
+#include <config.h>
+#include "fm-icon-container.h"
+#include "fm-desktop-icon-view.h"
+#include "fm-actions.h"
+
+#include <X11/Xatom.h>
+#include <gtk/gtk.h>
+#include <dirent.h>
+#include <eel/eel-glib-extensions.h>
+#include <eel/eel-mate-extensions.h>
+#include <eel/eel-gtk-extensions.h>
+#include <eel/eel-gtk-macros.h>
+#include <eel/eel-stock-dialogs.h>
+#include <eel/eel-string.h>
+#include <eel/eel-vfs-extensions.h>
+#include <fcntl.h>
+#include <gdk/gdkx.h>
+#include <glib/gi18n.h>
+#include <libcaja-private/caja-desktop-icon-file.h>
+#include <libcaja-private/caja-directory-background.h>
+#include <libcaja-private/caja-directory-notify.h>
+#include <libcaja-private/caja-file-changes-queue.h>
+#include <libcaja-private/caja-file-operations.h>
+#include <libcaja-private/caja-file-utilities.h>
+#include <libcaja-private/caja-ui-utilities.h>
+#include <libcaja-private/caja-global-preferences.h>
+#include <libcaja-private/caja-view-factory.h>
+#include <libcaja-private/caja-link.h>
+#include <libcaja-private/caja-metadata.h>
+#include <libcaja-private/caja-monitor.h>
+#include <libcaja-private/caja-program-choosing.h>
+#include <libcaja-private/caja-trash-monitor.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* Timeout to check the desktop directory for updates */
+#define RESCAN_TIMEOUT 4
+
+struct FMDesktopIconViewDetails
+{
+ GdkWindow *root_window;
+ GtkActionGroup *desktop_action_group;
+ guint desktop_merge_id;
+
+ /* For the desktop rescanning
+ */
+ gulong delayed_init_signal;
+ guint reload_desktop_timeout;
+ gboolean pending_rescan;
+};
+
+static void fm_desktop_icon_view_init (FMDesktopIconView *desktop_icon_view);
+static void fm_desktop_icon_view_class_init (FMDesktopIconViewClass *klass);
+static void default_zoom_level_changed (gpointer user_data);
+static gboolean real_supports_auto_layout (FMIconView *view);
+static gboolean real_supports_scaling (FMIconView *view);
+static gboolean real_supports_keep_aligned (FMIconView *view);
+static gboolean real_supports_labels_beside_icons (FMIconView *view);
+static void real_merge_menus (FMDirectoryView *view);
+static void real_update_menus (FMDirectoryView *view);
+static gboolean real_supports_zooming (FMDirectoryView *view);
+static void fm_desktop_icon_view_update_icon_container_fonts (FMDesktopIconView *view);
+
+EEL_CLASS_BOILERPLATE (FMDesktopIconView,
+ fm_desktop_icon_view,
+ FM_TYPE_ICON_VIEW)
+
+static char *desktop_directory;
+static time_t desktop_dir_modify_time;
+
+static void
+desktop_directory_changed_callback (gpointer callback_data)
+{
+ g_free (desktop_directory);
+ desktop_directory = caja_get_desktop_directory ();
+}
+
+static void
+lockdown_disable_command_line_changed_callback (gpointer callback_data)
+{
+ fm_directory_view_update_menus (FM_DIRECTORY_VIEW (callback_data));
+}
+
+static CajaIconContainer *
+get_icon_container (FMDesktopIconView *icon_view)
+{
+ g_return_val_if_fail (FM_IS_DESKTOP_ICON_VIEW (icon_view), NULL);
+ g_return_val_if_fail (CAJA_IS_ICON_CONTAINER (gtk_bin_get_child (GTK_BIN (icon_view))), NULL);
+
+ return CAJA_ICON_CONTAINER (gtk_bin_get_child (GTK_BIN (icon_view)));
+}
+
+static void
+icon_container_set_workarea (CajaIconContainer *icon_container,
+ GdkScreen *screen,
+ long *workareas,
+ int n_items)
+{
+ int left, right, top, bottom;
+ int screen_width, screen_height;
+ int i;
+
+ left = right = top = bottom = 0;
+
+ screen_width = gdk_screen_get_width (screen);
+ screen_height = gdk_screen_get_height (screen);
+
+ for (i = 0; i < n_items; i += 4)
+ {
+ int x = workareas [i];
+ int y = workareas [i + 1];
+ int width = workareas [i + 2];
+ int height = workareas [i + 3];
+
+ if ((x + width) > screen_width || (y + height) > screen_height)
+ continue;
+
+ left = MAX (left, x);
+ right = MAX (right, screen_width - width - x);
+ top = MAX (top, y);
+ bottom = MAX (bottom, screen_height - height - y);
+ }
+
+ caja_icon_container_set_margins (icon_container,
+ left, right, top, bottom);
+}
+
+static void
+net_workarea_changed (FMDesktopIconView *icon_view,
+ GdkWindow *window)
+{
+ long *nworkareas = NULL;
+ long *workareas = NULL;
+ GdkAtom type_returned;
+ int format_returned;
+ int length_returned;
+ CajaIconContainer *icon_container;
+ GdkScreen *screen;
+
+ g_return_if_fail (FM_IS_DESKTOP_ICON_VIEW (icon_view));
+
+ icon_container = get_icon_container (icon_view);
+
+ /* Find the number of desktops so we know how long the
+ * workareas array is going to be (each desktop will have four
+ * elements in the workareas array describing
+ * x,y,width,height) */
+ gdk_error_trap_push ();
+ if (!gdk_property_get (window,
+ gdk_atom_intern ("_NET_NUMBER_OF_DESKTOPS", FALSE),
+ gdk_x11_xatom_to_atom (XA_CARDINAL),
+ 0, 4, FALSE,
+ &type_returned,
+ &format_returned,
+ &length_returned,
+ (guchar **) &nworkareas))
+ {
+ g_warning("Can not calculate _NET_NUMBER_OF_DESKTOPS");
+ }
+ if (gdk_error_trap_pop()
+ || nworkareas == NULL
+ || type_returned != gdk_x11_xatom_to_atom (XA_CARDINAL)
+ || format_returned != 32)
+ g_warning("Can not calculate _NET_NUMBER_OF_DESKTOPS");
+
+ /* Note : gdk_property_get() is broken (API documents admit
+ * this). As a length argument, it expects the number of
+ * _bytes_ of data you require. Internally, gdk_property_get
+ * converts that value to a count of 32 bit (4 byte) elements.
+ * However, the length returned is in bytes, but is calculated
+ * via the count of returned elements * sizeof(long). This
+ * means on a 64 bit system, the number of bytes you have to
+ * request does not correspond to the number of bytes you get
+ * back, and is the reason for the workaround below.
+ */
+ gdk_error_trap_push ();
+ if (nworkareas == NULL || (*nworkareas < 1)
+ || !gdk_property_get (window,
+ gdk_atom_intern ("_NET_WORKAREA", FALSE),
+ gdk_x11_xatom_to_atom (XA_CARDINAL),
+ 0, ((*nworkareas) * 4 * 4), FALSE,
+ &type_returned,
+ &format_returned,
+ &length_returned,
+ (guchar **) &workareas))
+ {
+ g_warning("Can not get _NET_WORKAREA");
+ workareas = NULL;
+ }
+
+ if (gdk_error_trap_pop ()
+ || workareas == NULL
+ || type_returned != gdk_x11_xatom_to_atom (XA_CARDINAL)
+ || ((*nworkareas) * 4 * sizeof(long)) != length_returned
+ || format_returned != 32)
+ {
+ g_warning("Can not determine workarea, guessing at layout");
+ caja_icon_container_set_margins (icon_container,
+ 0, 0, 0, 0);
+ }
+ else
+ {
+ screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
+
+ icon_container_set_workarea (
+ icon_container, screen, workareas, length_returned / sizeof (long));
+ }
+
+ if (nworkareas != NULL)
+ g_free (nworkareas);
+
+ if (workareas != NULL)
+ g_free (workareas);
+}
+
+static GdkFilterReturn
+desktop_icon_view_property_filter (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ XEvent *xevent = gdk_xevent;
+ FMDesktopIconView *icon_view;
+
+ icon_view = FM_DESKTOP_ICON_VIEW (data);
+
+ switch (xevent->type)
+ {
+ case PropertyNotify:
+ if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name ("_NET_WORKAREA"))
+ net_workarea_changed (icon_view, event->any.window);
+ break;
+ default:
+ break;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+fm_desktop_icon_view_destroy (GtkObject *object)
+{
+ FMDesktopIconView *icon_view;
+ GtkUIManager *ui_manager;
+
+ icon_view = FM_DESKTOP_ICON_VIEW (object);
+
+ /* Remove desktop rescan timeout. */
+ if (icon_view->details->reload_desktop_timeout != 0)
+ {
+ g_source_remove (icon_view->details->reload_desktop_timeout);
+ icon_view->details->reload_desktop_timeout = 0;
+ }
+
+ ui_manager = fm_directory_view_get_ui_manager (FM_DIRECTORY_VIEW (icon_view));
+ if (ui_manager != NULL)
+ {
+ caja_ui_unmerge_ui (ui_manager,
+ &icon_view->details->desktop_merge_id,
+ &icon_view->details->desktop_action_group);
+ }
+
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
+}
+
+static void
+fm_desktop_icon_view_finalize (GObject *object)
+{
+ FMDesktopIconView *icon_view;
+
+ icon_view = FM_DESKTOP_ICON_VIEW (object);
+
+ eel_preferences_remove_callback (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL,
+ default_zoom_level_changed,
+ icon_view);
+
+ eel_preferences_remove_callback (CAJA_PREFERENCES_LOCKDOWN_COMMAND_LINE,
+ lockdown_disable_command_line_changed_callback,
+ icon_view);
+
+ g_free (icon_view->details);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+fm_desktop_icon_view_class_init (FMDesktopIconViewClass *class)
+{
+ G_OBJECT_CLASS (class)->finalize = fm_desktop_icon_view_finalize;
+
+ GTK_OBJECT_CLASS (class)->destroy = fm_desktop_icon_view_destroy;
+
+ FM_DIRECTORY_VIEW_CLASS (class)->merge_menus = real_merge_menus;
+ FM_DIRECTORY_VIEW_CLASS (class)->update_menus = real_update_menus;
+ FM_DIRECTORY_VIEW_CLASS (class)->supports_zooming = real_supports_zooming;
+
+ FM_ICON_VIEW_CLASS (class)->supports_auto_layout = real_supports_auto_layout;
+ FM_ICON_VIEW_CLASS (class)->supports_scaling = real_supports_scaling;
+ FM_ICON_VIEW_CLASS (class)->supports_keep_aligned = real_supports_keep_aligned;
+ FM_ICON_VIEW_CLASS (class)->supports_labels_beside_icons = real_supports_labels_beside_icons;
+}
+
+static void
+fm_desktop_icon_view_handle_middle_click (CajaIconContainer *icon_container,
+ GdkEventButton *event,
+ FMDesktopIconView *desktop_icon_view)
+{
+ XButtonEvent x_event;
+
+ /* During a mouse click we have the pointer and keyboard grab.
+ * We will send a fake event to the root window which will cause it
+ * to try to get the grab so we need to let go ourselves.
+ */
+ gdk_pointer_ungrab (GDK_CURRENT_TIME);
+ gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+
+ /* Stop the event because we don't want anyone else dealing with it. */
+ gdk_flush ();
+ g_signal_stop_emission_by_name (icon_container, "middle_click");
+
+ /* build an X event to represent the middle click. */
+ x_event.type = ButtonPress;
+ x_event.send_event = True;
+ x_event.display = GDK_DISPLAY ();
+ x_event.window = GDK_ROOT_WINDOW ();
+ x_event.root = GDK_ROOT_WINDOW ();
+ x_event.subwindow = 0;
+ x_event.time = event->time;
+ x_event.x = event->x;
+ x_event.y = event->y;
+ x_event.x_root = event->x_root;
+ x_event.y_root = event->y_root;
+ x_event.state = event->state;
+ x_event.button = event->button;
+ x_event.same_screen = True;
+
+ /* Send it to the root window, the window manager will handle it. */
+ XSendEvent (GDK_DISPLAY (), GDK_ROOT_WINDOW (), True,
+ ButtonPressMask, (XEvent *) &x_event);
+}
+
+static void
+unrealized_callback (GtkWidget *widget, FMDesktopIconView *desktop_icon_view)
+{
+ g_return_if_fail (desktop_icon_view->details->root_window != NULL);
+
+ /* Remove the property filter */
+ gdk_window_remove_filter (desktop_icon_view->details->root_window,
+ desktop_icon_view_property_filter,
+ desktop_icon_view);
+ desktop_icon_view->details->root_window = NULL;
+}
+
+static void
+realized_callback (GtkWidget *widget, FMDesktopIconView *desktop_icon_view)
+{
+ GdkWindow *root_window;
+ GdkScreen *screen;
+ GtkAllocation allocation;
+
+ g_return_if_fail (desktop_icon_view->details->root_window == NULL);
+
+ screen = gtk_widget_get_screen (widget);
+
+ /* Ugly HACK for the problem that the views realize at the
+ * wrong size and then get resized. (This is a problem with
+ * MateComponentPlug.) This was leading to problems where initial
+ * layout was done at 60x60 stacking all desktop icons in
+ * the top left corner.
+ */
+ allocation.x = 0;
+ allocation.y = 0;
+ allocation.width = gdk_screen_get_width (screen);
+ allocation.height = gdk_screen_get_height (screen);
+ gtk_widget_size_allocate (GTK_WIDGET(get_icon_container(desktop_icon_view)),
+ &allocation);
+
+ root_window = gdk_screen_get_root_window (screen);
+
+ desktop_icon_view->details->root_window = root_window;
+
+ /* Read out the workarea geometry and update the icon container accordingly */
+ net_workarea_changed (desktop_icon_view, root_window);
+
+ /* Setup the property filter */
+ gdk_window_set_events (root_window, GDK_PROPERTY_CHANGE_MASK);
+ gdk_window_add_filter (root_window,
+ desktop_icon_view_property_filter,
+ desktop_icon_view);
+}
+
+static CajaZoomLevel
+get_default_zoom_level (void)
+{
+ static gboolean auto_storage_added = FALSE;
+ static CajaZoomLevel default_zoom_level = CAJA_ZOOM_LEVEL_STANDARD;
+
+ if (!auto_storage_added)
+ {
+ auto_storage_added = TRUE;
+ eel_preferences_add_auto_enum (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL,
+ (int *) &default_zoom_level);
+ }
+
+ return CLAMP (default_zoom_level, CAJA_ZOOM_LEVEL_SMALLEST, CAJA_ZOOM_LEVEL_LARGEST);
+}
+
+static void
+default_zoom_level_changed (gpointer user_data)
+{
+ CajaZoomLevel new_level;
+ FMDesktopIconView *desktop_icon_view;
+
+ desktop_icon_view = FM_DESKTOP_ICON_VIEW (user_data);
+ new_level = get_default_zoom_level ();
+
+ caja_icon_container_set_zoom_level (get_icon_container (desktop_icon_view),
+ new_level);
+}
+
+static gboolean
+do_desktop_rescan (gpointer data)
+{
+ FMDesktopIconView *desktop_icon_view;
+ struct stat buf;
+
+ desktop_icon_view = FM_DESKTOP_ICON_VIEW (data);
+ if (desktop_icon_view->details->pending_rescan)
+ {
+ return TRUE;
+ }
+
+ if (stat (desktop_directory, &buf) == -1)
+ {
+ return TRUE;
+ }
+
+ if (buf.st_ctime == desktop_dir_modify_time)
+ {
+ return TRUE;
+ }
+
+ desktop_icon_view->details->pending_rescan = TRUE;
+
+ caja_directory_force_reload (
+ fm_directory_view_get_model (
+ FM_DIRECTORY_VIEW (desktop_icon_view)));
+ return TRUE;
+}
+
+static void
+done_loading (GtkObject *DirectoryView, FMDesktopIconView *desktop_icon_view)
+{
+ struct stat buf;
+
+ desktop_icon_view->details->pending_rescan = FALSE;
+ if (stat (desktop_directory, &buf) == -1)
+ {
+ return;
+ }
+
+ desktop_dir_modify_time = buf.st_ctime;
+}
+
+/* This function is used because the CajaDirectory model does not
+ * exist always in the desktop_icon_view, so we wait until it has been
+ * instantiated.
+ */
+static void
+delayed_init (FMDesktopIconView *desktop_icon_view)
+{
+ /* Keep track of the load time. */
+ g_signal_connect_object (fm_directory_view_get_model (FM_DIRECTORY_VIEW (desktop_icon_view)),
+ "done_loading",
+ G_CALLBACK (done_loading), desktop_icon_view, 0);
+
+ /* Monitor desktop directory. */
+ desktop_icon_view->details->reload_desktop_timeout =
+ g_timeout_add_seconds (RESCAN_TIMEOUT, do_desktop_rescan, desktop_icon_view);
+
+ g_signal_handler_disconnect (desktop_icon_view,
+ desktop_icon_view->details->delayed_init_signal);
+
+ desktop_icon_view->details->delayed_init_signal = 0;
+}
+
+static void
+font_changed_callback (gpointer callback_data)
+{
+ g_return_if_fail (FM_IS_DESKTOP_ICON_VIEW (callback_data));
+
+ fm_desktop_icon_view_update_icon_container_fonts (FM_DESKTOP_ICON_VIEW (callback_data));
+}
+
+static void
+fm_desktop_icon_view_update_icon_container_fonts (FMDesktopIconView *icon_view)
+{
+ CajaIconContainer *icon_container;
+ char *font;
+
+ icon_container = get_icon_container (icon_view);
+ g_assert (icon_container != NULL);
+
+ font = eel_preferences_get (CAJA_PREFERENCES_DESKTOP_FONT);
+
+ caja_icon_container_set_font (icon_container, font);
+
+ g_free (font);
+}
+
+static void
+fm_desktop_icon_view_init (FMDesktopIconView *desktop_icon_view)
+{
+ CajaIconContainer *icon_container;
+ GtkAllocation allocation;
+ GtkAdjustment *hadj, *vadj;
+
+ if (desktop_directory == NULL)
+ {
+ eel_preferences_add_callback (CAJA_PREFERENCES_DESKTOP_IS_HOME_DIR,
+ desktop_directory_changed_callback,
+ NULL);
+ desktop_directory_changed_callback (NULL);
+ }
+
+ fm_icon_view_filter_by_screen (FM_ICON_VIEW (desktop_icon_view), TRUE);
+ icon_container = get_icon_container (desktop_icon_view);
+ caja_icon_container_set_use_drop_shadows (icon_container, TRUE);
+ fm_icon_container_set_sort_desktop (FM_ICON_CONTAINER (icon_container), TRUE);
+
+ /* Set up details */
+ desktop_icon_view->details = g_new0 (FMDesktopIconViewDetails, 1);
+
+ /* Do a reload on the desktop if we don't have FAM, a smarter
+ * way to keep track of the items on the desktop.
+ */
+ if (!caja_monitor_active ())
+ {
+ desktop_icon_view->details->delayed_init_signal = g_signal_connect_object
+ (desktop_icon_view, "begin_loading",
+ G_CALLBACK (delayed_init), desktop_icon_view, 0);
+ }
+
+ caja_icon_container_set_is_fixed_size (icon_container, TRUE);
+ caja_icon_container_set_is_desktop (icon_container, TRUE);
+ caja_icon_container_set_store_layout_timestamps (icon_container, TRUE);
+
+ /* Set allocation to be at 0, 0 */
+ gtk_widget_get_allocation (GTK_WIDGET (icon_container), &allocation);
+ allocation.x = 0;
+ allocation.y = 0;
+ gtk_widget_set_allocation (GTK_WIDGET (icon_container), &allocation);
+
+ gtk_widget_queue_resize (GTK_WIDGET (icon_container));
+
+ hadj = gtk_layout_get_hadjustment (GTK_LAYOUT (icon_container));
+ vadj = gtk_layout_get_vadjustment (GTK_LAYOUT (icon_container));
+
+ eel_gtk_adjustment_set_value (hadj, 0);
+ eel_gtk_adjustment_set_value (vadj, 0);
+
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (desktop_icon_view),
+ GTK_SHADOW_NONE);
+
+ fm_directory_view_ignore_hidden_file_preferences
+ (FM_DIRECTORY_VIEW (desktop_icon_view));
+
+ fm_directory_view_set_show_foreign (FM_DIRECTORY_VIEW (desktop_icon_view),
+ FALSE);
+
+ /* Set our default layout mode */
+ caja_icon_container_set_layout_mode (icon_container,
+ gtk_widget_get_direction (GTK_WIDGET(icon_container)) == GTK_TEXT_DIR_RTL ?
+ CAJA_ICON_LAYOUT_T_B_R_L :
+ CAJA_ICON_LAYOUT_T_B_L_R);
+
+ g_signal_connect_object (icon_container, "middle_click",
+ G_CALLBACK (fm_desktop_icon_view_handle_middle_click), desktop_icon_view, 0);
+ g_signal_connect_object (desktop_icon_view, "realize",
+ G_CALLBACK (realized_callback), desktop_icon_view, 0);
+ g_signal_connect_object (desktop_icon_view, "unrealize",
+ G_CALLBACK (unrealized_callback), desktop_icon_view, 0);
+
+ eel_preferences_add_callback (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL,
+ default_zoom_level_changed,
+ desktop_icon_view);
+
+ eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_DESKTOP_FONT,
+ font_changed_callback,
+ desktop_icon_view, G_OBJECT (desktop_icon_view));
+
+ default_zoom_level_changed (desktop_icon_view);
+ fm_desktop_icon_view_update_icon_container_fonts (desktop_icon_view);
+
+ eel_preferences_add_callback (CAJA_PREFERENCES_LOCKDOWN_COMMAND_LINE,
+ lockdown_disable_command_line_changed_callback,
+ desktop_icon_view);
+
+}
+
+static void
+action_new_launcher_callback (GtkAction *action, gpointer data)
+{
+ char *desktop_directory;
+
+ g_assert (FM_DIRECTORY_VIEW (data));
+
+ desktop_directory = caja_get_desktop_directory ();
+
+ caja_launch_application_from_command (gtk_widget_get_screen (GTK_WIDGET (data)),
+ "mate-desktop-item-edit",
+ "mate-desktop-item-edit",
+ FALSE,
+ "--create-new", desktop_directory, NULL);
+ g_free (desktop_directory);
+
+}
+
+static void
+action_change_background_callback (GtkAction *action,
+ gpointer data)
+{
+ g_assert (FM_DIRECTORY_VIEW (data));
+
+ caja_launch_application_from_command (gtk_widget_get_screen (GTK_WIDGET (data)),
+ _("Background"),
+ "mate-appearance-properties",
+ FALSE,
+ "--show-page=background", NULL);
+}
+
+static void
+action_empty_trash_conditional_callback (GtkAction *action,
+ gpointer data)
+{
+ g_assert (FM_IS_DIRECTORY_VIEW (data));
+
+ caja_file_operations_empty_trash (GTK_WIDGET (data));
+}
+
+static gboolean
+trash_link_is_selection (FMDirectoryView *view)
+{
+ GList *selection;
+ CajaDesktopLink *link;
+ gboolean result;
+
+ result = FALSE;
+
+ selection = fm_directory_view_get_selection (view);
+
+ if (eel_g_list_exactly_one_item (selection) &&
+ CAJA_IS_DESKTOP_ICON_FILE (selection->data))
+ {
+ link = caja_desktop_icon_file_get_link (CAJA_DESKTOP_ICON_FILE (selection->data));
+ /* link may be NULL if the link was recently removed (unmounted) */
+ if (link != NULL &&
+ caja_desktop_link_get_link_type (link) == CAJA_DESKTOP_LINK_TRASH)
+ {
+ result = TRUE;
+ }
+ if (link)
+ {
+ g_object_unref (link);
+ }
+ }
+
+ caja_file_list_free (selection);
+
+ return result;
+}
+
+static void
+real_update_menus (FMDirectoryView *view)
+{
+ FMDesktopIconView *desktop_view;
+ char *label;
+ gboolean disable_command_line;
+ gboolean include_empty_trash;
+ GtkAction *action;
+
+ g_assert (FM_IS_DESKTOP_ICON_VIEW (view));
+
+ EEL_CALL_PARENT (FM_DIRECTORY_VIEW_CLASS, update_menus, (view));
+
+ desktop_view = FM_DESKTOP_ICON_VIEW (view);
+
+ /* New Launcher */
+ disable_command_line = eel_preferences_get_boolean (CAJA_PREFERENCES_LOCKDOWN_COMMAND_LINE);
+ action = gtk_action_group_get_action (desktop_view->details->desktop_action_group,
+ FM_ACTION_NEW_LAUNCHER_DESKTOP);
+ gtk_action_set_visible (action,
+ !disable_command_line);
+
+ /* Empty Trash */
+ include_empty_trash = trash_link_is_selection (view);
+ action = gtk_action_group_get_action (desktop_view->details->desktop_action_group,
+ FM_ACTION_EMPTY_TRASH_CONDITIONAL);
+ gtk_action_set_visible (action,
+ include_empty_trash);
+ if (include_empty_trash)
+ {
+ label = g_strdup (_("E_mpty Trash"));
+ g_object_set (action , "label", label, NULL);
+ gtk_action_set_sensitive (action,
+ !caja_trash_monitor_is_empty ());
+ g_free (label);
+ }
+}
+
+static const GtkActionEntry desktop_view_entries[] =
+{
+ /* name, stock id */
+ {
+ "New Launcher Desktop", NULL,
+ /* label, accelerator */
+ N_("Create L_auncher..."), NULL,
+ /* tooltip */
+ N_("Create a new launcher"),
+ G_CALLBACK (action_new_launcher_callback)
+ },
+ /* name, stock id */
+ {
+ "Change Background", NULL,
+ /* label, accelerator */
+ N_("Change Desktop _Background"), NULL,
+ /* tooltip */
+ N_("Show a window that lets you set your desktop background's pattern or color"),
+ G_CALLBACK (action_change_background_callback)
+ },
+ /* name, stock id */
+ {
+ "Empty Trash Conditional", NULL,
+ /* label, accelerator */
+ N_("Empty Trash"), NULL,
+ /* tooltip */
+ N_("Delete all items in the Trash"),
+ G_CALLBACK (action_empty_trash_conditional_callback)
+ },
+};
+
+static void
+real_merge_menus (FMDirectoryView *view)
+{
+ FMDesktopIconView *desktop_view;
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ const char *ui;
+
+ EEL_CALL_PARENT (FM_DIRECTORY_VIEW_CLASS, merge_menus, (view));
+
+ desktop_view = FM_DESKTOP_ICON_VIEW (view);
+
+ ui_manager = fm_directory_view_get_ui_manager (view);
+
+ action_group = gtk_action_group_new ("DesktopViewActions");
+ gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
+ desktop_view->details->desktop_action_group = action_group;
+ gtk_action_group_add_actions (action_group,
+ desktop_view_entries, G_N_ELEMENTS (desktop_view_entries),
+ view);
+
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ g_object_unref (action_group); /* owned by ui manager */
+
+ ui = caja_ui_string_get ("caja-desktop-icon-view-ui.xml");
+ desktop_view->details->desktop_merge_id =
+ gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, NULL);
+}
+
+static gboolean
+real_supports_auto_layout (FMIconView *view)
+{
+ /* Can't use auto-layout on the desktop, because doing so
+ * would cause all sorts of complications involving the
+ * fixed-size window.
+ */
+ return FALSE;
+}
+
+static gboolean
+real_supports_scaling (FMIconView *view)
+{
+ return TRUE;
+}
+
+static gboolean
+real_supports_keep_aligned (FMIconView *view)
+{
+ return TRUE;
+}
+
+static gboolean
+real_supports_labels_beside_icons (FMIconView *view)
+{
+ return FALSE;
+}
+
+static gboolean
+real_supports_zooming (FMDirectoryView *view)
+{
+ /* Can't zoom on the desktop, because doing so would cause all
+ * sorts of complications involving the fixed-size window.
+ */
+ return FALSE;
+}
+
+static CajaView *
+fm_desktop_icon_view_create (CajaWindowSlotInfo *slot)
+{
+ FMIconView *view;
+
+ view = g_object_new (FM_TYPE_DESKTOP_ICON_VIEW,
+ "window-slot", slot,
+ NULL);
+ return CAJA_VIEW (view);
+}
+
+static gboolean
+fm_desktop_icon_view_supports_uri (const char *uri,
+ GFileType file_type,
+ const char *mime_type)
+{
+ if (g_str_has_prefix (uri, EEL_DESKTOP_URI))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static CajaViewInfo fm_desktop_icon_view =
+{
+ FM_DESKTOP_ICON_VIEW_ID,
+ "Desktop View",
+ "_Desktop",
+ N_("The desktop view encountered an error."),
+ N_("The desktop view encountered an error while starting up."),
+ "Display this location with the desktop view.",
+ fm_desktop_icon_view_create,
+ fm_desktop_icon_view_supports_uri
+};
+
+void
+fm_desktop_icon_view_register (void)
+{
+ fm_desktop_icon_view.error_label = _(fm_desktop_icon_view.error_label);
+ fm_desktop_icon_view.startup_error_label = _(fm_desktop_icon_view.startup_error_label);
+
+ caja_view_factory_register (&fm_desktop_icon_view);
+}