diff --git a/ChangeLog b/ChangeLog index dfce47df2cc413575ff62d09f2898d828c9e1755..2ef9326ad4d915232cb399a62aa90929d9e74ec0 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 32e34a8a488c892d6529b9001bc26420cde33616..0f0afe698bb8cf9abd9ad59592cde98b2d12331f 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;