From 2d9be98845d47b06b4a76f507ba18d343f237568 Mon Sep 17 00:00:00 2001
From: Benedikt Meurer <benny@xfce.org>
Date: Sat, 18 Feb 2006 23:00:25 +0000
Subject: [PATCH] 2006-02-18	Benedikt Meurer <benny@xfce.org>

	* thunar/thunar-location-button.c: Change icon to "drop icon" while
	  dragging over a location button that can accept the drop.
	* thunar/thunar-location-button.c: Add context menu to the location
	  buttons as requested on thunar-dev.




(Old svn revision: 19959)
---
 ChangeLog                       |   7 ++
 thunar/thunar-location-button.c | 192 ++++++++++++++++++++++++++++----
 2 files changed, 175 insertions(+), 24 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index dfce47df2..2ef9326ad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2006-02-18	Benedikt Meurer <benny@xfce.org>
+
+	* thunar/thunar-location-button.c: Change icon to "drop icon" while
+	  dragging over a location button that can accept the drop.
+	* thunar/thunar-location-button.c: Add context menu to the location
+	  buttons as requested on thunar-dev.
+
 2006-02-18	Benedikt Meurer <benny@xfce.org>
 
 	* thunar/thunar-location-button.c: Set toggle button state to
diff --git a/thunar/thunar-location-button.c b/thunar/thunar-location-button.c
index 32e34a8a4..0f0afe698 100644
--- a/thunar/thunar-location-button.c
+++ b/thunar/thunar-location-button.c
@@ -29,6 +29,7 @@
 #endif
 
 #include <thunar/thunar-application.h>
+#include <thunar/thunar-clipboard-manager.h>
 #include <thunar/thunar-dnd.h>
 #include <thunar/thunar-icon-factory.h>
 #include <thunar/thunar-location-button.h>
@@ -70,6 +71,8 @@ static GdkDragAction  thunar_location_button_get_dest_actions       (ThunarLocat
                                                                      GdkDragContext             *context,
                                                                      GtkWidget                  *button,
                                                                      guint                       time);
+static void           thunar_location_button_open_in_new_window     (ThunarLocationButton       *location_button);
+static void           thunar_location_button_paste_files_here       (ThunarLocationButton       *location_button);
 static void           thunar_location_button_file_changed           (ThunarLocationButton       *location_button,
                                                                      ThunarFile                 *file);
 static gboolean       thunar_location_button_button_press_event     (GtkWidget                  *button,
@@ -122,20 +125,23 @@ struct _ThunarLocationButton
 {
   GtkAlignment __parent__;
 
-  GtkWidget  *image;
-  GtkWidget  *label;
+  GtkWidget          *image;
+  GtkWidget          *label;
 
+  /* the current icon state (i.e. accepting drops) */
+  ThunarFileIconState file_icon_state;
+  
   /* enter folders using DnD */
-  gint        enter_timeout_id;
+  gint                enter_timeout_id;
 
   /* drop support for the button */
-  GList      *drop_path_list;
-  guint       drop_data_ready : 1;
-  guint       drop_occurred : 1;
+  GList              *drop_path_list;
+  guint               drop_data_ready : 1;
+  guint               drop_occurred : 1;
 
   /* public properties */
-  guint       active : 1;
-  ThunarFile *file;
+  guint               active : 1;
+  ThunarFile         *file;
 };
 
 
@@ -402,6 +408,44 @@ thunar_location_button_get_dest_actions (ThunarLocationButton *location_button,
 
 
 
+static void
+thunar_location_button_open_in_new_window (ThunarLocationButton *location_button)
+{
+  ThunarApplication *application;
+
+  g_return_if_fail (THUNAR_IS_LOCATION_BUTTON (location_button));
+
+  /* verify that we still have a valid file */
+  if (G_LIKELY (location_button->file != NULL))
+    {
+      /* open a new window for the folder */
+      application = thunar_application_get ();
+      thunar_application_open_window (application, location_button->file, gtk_widget_get_screen (GTK_WIDGET (location_button)));
+      g_object_unref (G_OBJECT (application));
+    }
+}
+
+
+
+static void
+thunar_location_button_paste_files_here (ThunarLocationButton *location_button)
+{
+  ThunarClipboardManager *clipboard;
+
+  g_return_if_fail (THUNAR_IS_LOCATION_BUTTON (location_button));
+
+  /* verify that we still have a valid file */
+  if (G_LIKELY (location_button->file != NULL))
+    {
+      /* paste files from the clipboard to the folder represented by this button */
+      clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (GTK_WIDGET (location_button)));
+      thunar_clipboard_manager_paste_files (clipboard, thunar_file_get_path (location_button->file), GTK_WIDGET (location_button), NULL);
+      g_object_unref (G_OBJECT (clipboard));
+    }
+}
+
+
+
 static void
 thunar_location_button_file_changed (ThunarLocationButton *location_button,
                                      ThunarFile           *file)
@@ -421,7 +465,7 @@ thunar_location_button_file_changed (ThunarLocationButton *location_button,
   /* update the icon for the image and DnD */
   icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (location_button)));
   icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);
-  icon = thunar_icon_factory_load_file_icon (icon_factory, file, THUNAR_FILE_ICON_STATE_DEFAULT, size);
+  icon = thunar_icon_factory_load_file_icon (icon_factory, file, location_button->file_icon_state, size);
   gtk_drag_source_set_icon_pixbuf (GTK_BIN (location_button)->child, icon);
   gtk_image_set_from_pixbuf (GTK_IMAGE (location_button->image), icon);
   g_object_unref (G_OBJECT (icon_factory));
@@ -448,11 +492,92 @@ thunar_location_button_button_press_event (GtkWidget            *button,
                                            GdkEventButton       *event,
                                            ThunarLocationButton *location_button)
 {
+  ThunarClipboardManager *clipboard;
+  GtkWidget              *image;
+  GtkWidget              *item;
+  GtkWidget              *menu;
+  GMainLoop              *loop;
+
   g_return_val_if_fail (THUNAR_IS_LOCATION_BUTTON (location_button), FALSE);
 
-  /* set button state to inconsistent while holding down the middle-mouse-button */
+  /* check if we can handle the button event */
   if (G_UNLIKELY (event->button == 2))
-    gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (button), TRUE);
+    {
+      /* set button state to inconsistent while holding down the middle-mouse-button */
+      gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (button), TRUE);
+    }
+  else if (event->button == 3)
+    {
+      /* prepare the internal main loop */
+      loop = g_main_loop_new (NULL, FALSE);
+
+      /* make sure the location button isn't deleted in the meantime */
+      g_object_ref (G_OBJECT (location_button));
+
+      /* grab a reference on the clipboard manager for this display */
+      clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (button));
+
+      /* prepare the popup menu */
+      menu = gtk_menu_new ();
+      gtk_menu_set_screen (GTK_MENU (menu), gtk_widget_get_screen (button));
+      g_signal_connect_swapped (G_OBJECT (menu), "deactivate", G_CALLBACK (g_main_loop_quit), loop);
+      exo_gtk_object_ref_sink (GTK_OBJECT (menu));
+
+      /* append the "Open" action */
+      item = gtk_image_menu_item_new_with_mnemonic (_("_Open"));
+      exo_binding_new_with_negation (G_OBJECT (location_button), "active", G_OBJECT (item), "sensitive");
+      g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_location_button_clicked), location_button);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show (item);
+
+      /* add the image for the open action */
+      image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
+      gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+      gtk_widget_show (image);
+
+      /* append the "Open in New Window" action */
+      item = gtk_menu_item_new_with_label (_("Open in New Window"));
+      g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_location_button_open_in_new_window), location_button);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show (item);
+
+      /* append a separator item */
+      item = gtk_separator_menu_item_new ();
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show (item);
+
+      /* append the "Paste Files Here" action */
+      item = gtk_image_menu_item_new_with_mnemonic (_("_Paste Files Here"));
+      exo_binding_new (G_OBJECT (clipboard), "can-paste", G_OBJECT (item), "sensitive");
+      g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_location_button_paste_files_here), location_button);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show (item);
+
+      /* add the image for the paste action */
+      image = gtk_image_new_from_stock (GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU);
+      gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+      gtk_widget_show (image);
+
+      /* set button state to inconsistent while the menu is open */
+      gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (button), TRUE);
+
+      /* run the internal loop */
+      gtk_grab_add (menu);
+      gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button, event->time);
+      g_main_loop_run (loop);
+      gtk_grab_remove (menu);
+
+      /* reset the button state to default */
+      gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (button), FALSE);
+
+      /* cleanup */
+      g_object_unref (G_OBJECT (location_button));
+      g_object_unref (G_OBJECT (clipboard));
+      g_object_unref (G_OBJECT (menu));
+      g_main_loop_unref (loop);
+
+      return TRUE;
+    }
 
   return FALSE;
 }
@@ -464,8 +589,6 @@ thunar_location_button_button_release_event (GtkWidget            *button,
                                              GdkEventButton       *event,
                                              ThunarLocationButton *location_button)
 {
-  ThunarApplication *application;
-
   g_return_val_if_fail (THUNAR_IS_LOCATION_BUTTON (location_button), FALSE);
 
   /* reset inconsistent button state after releasing the middle-mouse-button */
@@ -475,13 +598,7 @@ thunar_location_button_button_release_event (GtkWidget            *button,
       gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (button), FALSE);
 
       /* open folder in window on middle-click events */
-      if (G_LIKELY (location_button->file != NULL))
-        {
-          /* popup a new window */
-          application = thunar_application_get ();
-          thunar_application_open_window (application, location_button->file, gtk_widget_get_screen (button));
-          g_object_unref (G_OBJECT (application));
-        }
+      thunar_location_button_open_in_new_window (location_button);
     }
 
   return FALSE;
@@ -614,6 +731,17 @@ thunar_location_button_drag_leave (GtkWidget            *button,
   g_return_if_fail (GTK_IS_BUTTON (button));
   g_return_if_fail (THUNAR_IS_LOCATION_BUTTON (location_button));
 
+  /* reset the file icon state to default appearance */
+  if (G_LIKELY (location_button->file_icon_state != THUNAR_FILE_ICON_STATE_DEFAULT))
+    {
+      /* we may switch to "drop icon state" during drag motion */
+      location_button->file_icon_state = THUNAR_FILE_ICON_STATE_DEFAULT;
+
+      /* update the user interface if we still have a file */
+      if (G_LIKELY (location_button->file != NULL))
+        thunar_location_button_file_changed (location_button, location_button->file);
+    }
+
   /* reset the "drop data ready" status and free the path list */
   if (G_LIKELY (location_button->drop_data_ready))
     {
@@ -637,9 +765,11 @@ thunar_location_button_drag_motion (GtkWidget            *button,
                                     guint                 time,
                                     ThunarLocationButton *location_button)
 {
-  GtkSettings *settings;
-  GdkAtom      target;
-  gint         delay;
+  ThunarFileIconState file_icon_state;
+  GdkDragAction       actions;
+  GtkSettings        *settings;
+  GdkAtom             target;
+  gint                delay;
 
   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
   g_return_val_if_fail (THUNAR_IS_LOCATION_BUTTON (location_button), FALSE);
@@ -673,7 +803,21 @@ thunar_location_button_drag_motion (GtkWidget            *button,
   else
     {
       /* check whether we can drop into the buttons' folder */
-      thunar_location_button_get_dest_actions (location_button, context, button, time);
+      actions = thunar_location_button_get_dest_actions (location_button, context, button, time);
+
+      /* determine the new file icon state */
+      file_icon_state = (actions == 0) ? THUNAR_FILE_ICON_STATE_DEFAULT : THUNAR_FILE_ICON_STATE_DROP;
+
+      /* check if we need to update the user interface */
+      if (G_UNLIKELY (location_button->file_icon_state != file_icon_state))
+        {
+          /* apply the new icon state */
+          location_button->file_icon_state = file_icon_state;
+
+          /* update the user interface if we have a file */
+          if (G_LIKELY (location_button->file != NULL))
+            thunar_location_button_file_changed (location_button, location_button->file);
+        }
     }
 
   return FALSE;
-- 
GitLab