diff --git a/ChangeLog b/ChangeLog index 382fa7f516d185986472d9588be2e0beb5fbf572..e5c2e819a6b1e61d036639977226114685af8f2a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2006-01-10 Benedikt Meurer <benny@xfce.org> + + * thunar/thunar-path-entry.c(thunar_path_entry_activate): If we have + a pending completion, accept the completion first, without activating + the entry. This makes it more consistent with the behaviour when + completing from the popup window. + * thunar/thunar-path-entry.c(thunar_path_entry_parse): Properly + transform all parts of the filename to the local encoding. + * thunar/thunar-text-renderer.c(thunar_text_renderer_set_widget): + Calculate the approx. character dimensions based on the font metrics + for the active widget font. + * thunar/thunar-window.c(thunar_window_action_go_up): Handle errors + properly. + * thunar/thunar-standard-view-ui.xml, thunar/thunar-standard-view.c: + Add support to view the properties of the current folder. + * thunar/thunar-file.{c,h}, thunar/thunar-location-buttons.c, + thunar/thunar-shortcuts-model.c, thunar/thunar-window.c: Change + special file naming (home and root folder) to be consistent with + what GtkFileChooser does. + * thunar/thunar-properties-dialog.c(thunar_properties_dialog_update): + Display only the name of the file in the dialog title. + * thunar/thunar-standard-view.c: Add support for the XDS protocol. + * README: Add notes about supported standards. + 2006-01-09 Benedikt Meurer <benny@xfce.org> * thunar-vfs/thunar-vfs-util.{c,h}: Add thunar_vfs_expand_filename(), diff --git a/README b/README index f783d622c6b91dc00e1ec9d06d632e0310359d49..50c50a8f4ba5fb476f98865953f7810249ef6469 100644 --- a/README +++ b/README @@ -57,6 +57,30 @@ can be setup using the configure flag `--enable-debug' (check the output of exactly what you do. +Standards compliance +==================== + +Thunar supports the following standards/specifications: + + * XDG Base Directory Specification + http://freedesktop.org/wiki/Standards_2fbasedir_2dspec + + * Shared MIME Database Specification + http://freedesktop.org/wiki/Standards_2fshared_2dmime_2dinfo_2dspec + + * X Direct Save (XDS) Protocol for the X Window System + http://freedesktop.org/wiki/Standards_2fdirect_2dsave + + * Icon Theme Specification + http://freedesktop.org/wiki/Standards_2ficon_2dtheme_2dspec + + * Thumbnail Managing Standard + http://jens.triq.net/thumbnail-spec/index.html + + * File URI Specification + http://freedesktop.org/wiki/Standards_2ffile_2duri_2dspec + + How to report bugs? =================== diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c index bef5364ba032b28a2c6f88743770d95bc0e27581..d60b27090d7cb3bb943625c5a6113edc35cddbb4 100644 --- a/thunar/thunar-file.c +++ b/thunar/thunar-file.c @@ -246,20 +246,6 @@ thunar_file_class_init (ThunarFileClass *klass) NULL, EXO_PARAM_READABLE)); - /** - * ThunarFile::special-name: - * - * The file's special name, see thunar_file_get_special_name() - * for details. - **/ - g_object_class_install_property (gobject_class, - PROP_SPECIAL_NAME, - g_param_spec_string ("special-name", - "Special Name", - "Special Name", - NULL, - EXO_PARAM_READABLE)); - /** * ThunarFile::changed: * @file : the #ThunarFile instance. @@ -388,10 +374,6 @@ thunar_file_get_property (GObject *object, g_value_set_static_string (value, thunar_file_get_display_name (file)); break; - case PROP_SPECIAL_NAME: - g_value_set_static_string (value, thunar_file_get_special_name (file)); - break; - default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -506,11 +488,8 @@ thunar_file_real_changed (ThunarFile *file) */ thunar_file_set_thumb_state (file, THUNAR_FILE_THUMB_STATE_UNKNOWN); - /* notify about changes of the display-name and special-name properties */ - g_object_freeze_notify (G_OBJECT (file)); + /* notify about changes of the display-name property */ g_object_notify (G_OBJECT (file), "display-name"); - g_object_notify (G_OBJECT (file), "special-name"); - g_object_thaw_notify (G_OBJECT (file)); } @@ -1042,37 +1021,13 @@ thunar_file_get_display_name (const ThunarFile *file) /* root directory is always displayed as 'Filesystem' */ if (thunar_file_is_root (file)) - return _("Filesystem"); + return _("File System"); return file->info->display_name; } -/** - * thunar_file_get_special_name: - * @file : a #ThunarFile instance. - * - * Returns the special name for the @file, e.g. "Filesystem" for the #ThunarFile - * referring to "/" and so on. If there's no special name for this @file, the - * value of the "display-name" property will be returned instead. - * - * Return value: the special name of @file. - **/ -const gchar* -thunar_file_get_special_name (const ThunarFile *file) -{ - g_return_val_if_fail (THUNAR_IS_FILE (file), NULL); - - /* home dir has special name, root dir is handled in get_display_name() */ - if (thunar_file_is_home (file)) - return _("Home"); - - return thunar_file_get_display_name (file); -} - - - /** * thunar_file_get_date: * @file : a #ThunarFile instance. diff --git a/thunar/thunar-file.h b/thunar/thunar-file.h index 3a9885160a1a6e9fffb1421270c45a75af105cb0..eafcc7ac8364781c87343bcf5c2f6e069de219bb 100644 --- a/thunar/thunar-file.h +++ b/thunar/thunar-file.h @@ -137,7 +137,6 @@ GdkDragAction thunar_file_accepts_drop (ThunarFile GdkDragAction actions); const gchar *thunar_file_get_display_name (const ThunarFile *file); -const gchar *thunar_file_get_special_name (const ThunarFile *file); static inline ThunarVfsInfo *thunar_file_get_info (const ThunarFile *file); static inline ThunarVfsPath *thunar_file_get_path (const ThunarFile *file); diff --git a/thunar/thunar-location-buttons.c b/thunar/thunar-location-buttons.c index f48a4b6c0708a0792ef88121bc0f3e061af5c7d8..a63316c740a33e34eeeb7da9e2e805ba14fa8aba 100644 --- a/thunar/thunar-location-buttons.c +++ b/thunar/thunar-location-buttons.c @@ -890,7 +890,7 @@ thunar_location_buttons_make_button (ThunarLocationButtons *buttons, { /* only non-root nodes have a label */ label = g_object_new (GTK_TYPE_LABEL, NULL); - exo_binding_new (G_OBJECT (file), "special-name", G_OBJECT (label), "label"); + exo_binding_new (G_OBJECT (file), "display-name", G_OBJECT (label), "label"); g_object_set_qdata (G_OBJECT (button), gtk_label_quark, label); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); gtk_widget_show (label); diff --git a/thunar/thunar-path-entry.c b/thunar/thunar-path-entry.c index e8e2a4ff49374323b000fb8be6a8dfcfac750726..ab4b09306df2a21ac3f089f9b3ead24e668ad962 100644 --- a/thunar/thunar-path-entry.c +++ b/thunar/thunar-path-entry.c @@ -730,11 +730,16 @@ thunar_path_entry_activate (GtkEntry *entry) { ThunarPathEntry *path_entry = THUNAR_PATH_ENTRY (entry); - /* place cursor at the end of the text if we have completion set */ if (G_LIKELY (path_entry->has_completion)) - gtk_editable_set_position (GTK_EDITABLE (path_entry), -1); - - (*GTK_ENTRY_CLASS (thunar_path_entry_parent_class)->activate) (entry); + { + /* place cursor at the end of the text if we have completion set */ + gtk_editable_set_position (GTK_EDITABLE (path_entry), -1); + } + else + { + /* emit the "activate" signal */ + (*GTK_ENTRY_CLASS (thunar_path_entry_parent_class)->activate) (entry); + } } @@ -1179,32 +1184,39 @@ thunar_path_entry_parse (ThunarPathEntry *path_entry, if (G_UNLIKELY (last_slash == NULL)) { /* no slash character, it's relative to the home dir */ - *folder_part = g_strdup (xfce_get_homedir ()); - *file_part = filename; - return TRUE; + *file_part = g_filename_from_utf8 (filename, -1, NULL, NULL, error); + if (G_LIKELY (*file_part != NULL)) + *folder_part = g_strdup (xfce_get_homedir ()); } - - if (G_LIKELY (last_slash != filename)) - *folder_part = g_filename_from_utf8 (filename, last_slash - filename, NULL, NULL, error); else - *folder_part = g_strdup ("/"); - - if (G_LIKELY (*folder_part != NULL)) { - /* if folder_part doesn't start with '/', it's relative to the home dir */ - if (G_UNLIKELY (**folder_part != G_DIR_SEPARATOR)) + if (G_LIKELY (last_slash != filename)) + *folder_part = g_filename_from_utf8 (filename, last_slash - filename, NULL, NULL, error); + else + *folder_part = g_strdup ("/"); + + if (G_LIKELY (*folder_part != NULL)) { - path = xfce_get_homefile (*folder_part, NULL); - g_free (*folder_part); - *folder_part = path; - } + /* if folder_part doesn't start with '/', it's relative to the home dir */ + if (G_UNLIKELY (**folder_part != G_DIR_SEPARATOR)) + { + path = xfce_get_homefile (*folder_part, NULL); + g_free (*folder_part); + *folder_part = path; + } - /* determine the file part */ - *file_part = g_strdup (last_slash + 1); - } - else - { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, _("Invalid path")); + /* determine the file part */ + *file_part = g_filename_from_utf8 (last_slash + 1, -1, NULL, NULL, error); + if (G_UNLIKELY (*file_part == NULL)) + { + g_free (*folder_part); + *folder_part = NULL; + } + } + else + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, _("Invalid path")); + } } /* release the filename */ diff --git a/thunar/thunar-properties-dialog.c b/thunar/thunar-properties-dialog.c index af9414e170269eb41dcbae63c8856a3198c44aae..734e5f7aea4236dfb3e6d7b7a6c454de03b8d1c8 100644 --- a/thunar/thunar-properties-dialog.c +++ b/thunar/thunar-properties-dialog.c @@ -1,6 +1,6 @@ /* $Id$ */ /*- - * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org> + * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -603,9 +603,7 @@ thunar_properties_dialog_update (ThunarPropertiesDialog *dialog) if (G_LIKELY (strcmp (name, gtk_entry_get_text (GTK_ENTRY (dialog->name_entry))) != 0)) { gtk_entry_set_text (GTK_ENTRY (dialog->name_entry), name); - str = g_strdup_printf (_("%s Info"), name); - gtk_window_set_title (GTK_WINDOW (dialog), str); - g_free (str); + gtk_window_set_title (GTK_WINDOW (dialog), name); /* grab the input focus to the name entry */ gtk_widget_grab_focus (dialog->name_entry); diff --git a/thunar/thunar-shortcuts-model.c b/thunar/thunar-shortcuts-model.c index 359dad7d853ee855f85fe1345a5e4b336d160d92..562ff844594696998fbf58befdb6ef80e378dff3 100644 --- a/thunar/thunar-shortcuts-model.c +++ b/thunar/thunar-shortcuts-model.c @@ -1,6 +1,6 @@ /* $Id$ */ /*- - * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org> + * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -493,7 +493,7 @@ thunar_shortcuts_model_get_value (GtkTreeModel *tree_model, else if (shortcut->name != NULL) g_value_set_static_string (value, shortcut->name); else if (shortcut->file != NULL) - g_value_set_static_string (value, thunar_file_get_special_name (shortcut->file)); + g_value_set_static_string (value, thunar_file_get_display_name (shortcut->file)); else g_value_set_static_string (value, ""); break; diff --git a/thunar/thunar-standard-view-ui.xml b/thunar/thunar-standard-view-ui.xml index 2184d7d80e68b4743e794247d096180475d48e35..f7a2031f0ed56734695b61401f399ebf7d972e53 100644 --- a/thunar/thunar-standard-view-ui.xml +++ b/thunar/thunar-standard-view-ui.xml @@ -3,7 +3,7 @@ <!-- $Id$ - Copyright (c) 2005 Benedikt Meurer <benny@xfce.org> + Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org> Thunar standard view user interface description file. Do NOT simply edit this file if you don't know how the whole system @@ -69,6 +69,8 @@ <menuitem action="paste" name="paste" /> <separator /> <placeholder name="placeholder-custom-actions" /> + <separator /> + <menuitem action="properties" name="properties" /> </popup> </ui> diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c index f6da3cc2a622606227c40e603263f679d500dc98..e3a1a8784b4d3f3711fb19d03c1010b2bdd4a9db 100644 --- a/thunar/thunar-standard-view.c +++ b/thunar/thunar-standard-view.c @@ -70,6 +70,7 @@ enum enum { TEXT_URI_LIST, + XDND_DIRECT_SAVE0, }; @@ -114,6 +115,10 @@ static GdkDragAction thunar_standard_view_get_dest_actions (ThunarStand gint y, guint time, ThunarFile **file_return); +static ThunarFile *thunar_standard_view_get_drop_file (ThunarStandardView *standard_view, + gint x, + gint y, + GtkTreePath **path_return); static GList *thunar_standard_view_get_selected_files (ThunarStandardView *standard_view); static GList *thunar_standard_view_get_selected_paths (ThunarStandardView *standard_view); static void thunar_standard_view_merge_custom_actions (ThunarStandardView *standard_view, @@ -256,7 +261,7 @@ static const GtkActionEntry action_entries[] = { "file-context-menu", NULL, N_ ("File Context Menu"), NULL, NULL, NULL, }, { "folder-context-menu", NULL, N_ ("Folder Context Menu"), NULL, NULL, NULL, }, { "create-folder", NULL, N_ ("Create _Folder..."), "<control><shift>N", N_ ("Create an empty folder within the current folder"), G_CALLBACK (thunar_standard_view_action_create_folder), }, - { "properties", GTK_STOCK_PROPERTIES, N_ ("_Properties"), "<alt>Return", N_ ("View the properties of the selected file"), G_CALLBACK (thunar_standard_view_action_properties), }, + { "properties", GTK_STOCK_PROPERTIES, N_ ("_Properties..."), "<alt>Return", N_ ("View the properties of the selected file"), G_CALLBACK (thunar_standard_view_action_properties), }, { "copy", GTK_STOCK_COPY, N_ ("_Copy Files"), NULL, N_ ("Copy the selected files"), G_CALLBACK (thunar_standard_view_action_copy), }, { "cut", GTK_STOCK_CUT, N_ ("Cu_t Files"), NULL, N_ ("Cut the selected files"), G_CALLBACK (thunar_standard_view_action_cut), }, { "paste", GTK_STOCK_PASTE, N_ ("_Paste Files"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_paste), }, @@ -279,6 +284,7 @@ static const GtkTargetEntry drag_targets[] = static const GtkTargetEntry drop_targets[] = { { "text/uri-list", 0, TEXT_URI_LIST, }, + { "XdndDirectSave0", 0, XDND_DIRECT_SAVE0, }, }; @@ -1022,24 +1028,10 @@ thunar_standard_view_get_dest_actions (ThunarStandardView *standard_view, GdkDragAction actions = 0; GdkDragAction action = 0; GtkTreePath *path; - GtkTreeIter iter; ThunarFile *file; - /* determine the path for the given coordinates */ - path = (*THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->get_path_at_pos) (standard_view, x, y); - if (G_LIKELY (path != NULL)) - { - /* determine the file for the path */ - gtk_tree_model_get_iter (GTK_TREE_MODEL (standard_view->model), &iter, path); - file = thunar_list_model_get_file (standard_view->model, &iter); - } - else - { - /* determine the current directory */ - file = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (standard_view)); - if (G_LIKELY (file != NULL)) - g_object_ref (G_OBJECT (file)); - } + /* determine the file and path for the given coordinates */ + file = thunar_standard_view_get_drop_file (standard_view, x, y, &path); /* check if we can drop there */ if (G_LIKELY (file != NULL)) @@ -1065,9 +1057,6 @@ thunar_standard_view_get_dest_actions (ThunarStandardView *standard_view, if (G_UNLIKELY (file_return != NULL)) *file_return = g_object_ref (G_OBJECT (file)); } - - /* release the file reference */ - g_object_unref (G_OBJECT (file)); } /* reset path if we cannot drop */ @@ -1096,6 +1085,8 @@ thunar_standard_view_get_dest_actions (ThunarStandardView *standard_view, gdk_drag_status (context, action, time); /* clean up */ + if (G_LIKELY (file != NULL)) + g_object_unref (G_OBJECT (file)); if (G_LIKELY (path != NULL)) gtk_tree_path_free (path); @@ -1104,6 +1095,43 @@ thunar_standard_view_get_dest_actions (ThunarStandardView *standard_view, +static ThunarFile* +thunar_standard_view_get_drop_file (ThunarStandardView *standard_view, + gint x, + gint y, + GtkTreePath **path_return) +{ + GtkTreePath *path = NULL; + GtkTreeIter iter; + ThunarFile *file = NULL; + + /* determine the path for the given coordinates */ + path = (*THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->get_path_at_pos) (standard_view, x, y); + if (G_LIKELY (path != NULL)) + { + /* determine the file for the path */ + gtk_tree_model_get_iter (GTK_TREE_MODEL (standard_view->model), &iter, path); + file = thunar_list_model_get_file (standard_view->model, &iter); + } + else + { + /* determine the current directory */ + file = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (standard_view)); + if (G_LIKELY (file != NULL)) + g_object_ref (G_OBJECT (file)); + } + + /* return the path (if any) */ + if (G_LIKELY (path_return != NULL)) + *path_return = path; + else if (G_LIKELY (path != NULL)) + gtk_tree_path_free (path); + + return file; +} + + + static GList* thunar_standard_view_get_selected_files (ThunarStandardView *standard_view) { @@ -1405,14 +1433,27 @@ static void thunar_standard_view_action_properties (GtkAction *action, ThunarStandardView *standard_view) { - GtkWidget *toplevel; - GtkWidget *dialog; - GList *files; + ThunarFile *current_directory; + GtkWidget *toplevel; + GtkWidget *dialog; + GList *files; g_return_if_fail (GTK_IS_ACTION (action)); g_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view)); + /* determine the currently selected files */ files = thunar_standard_view_get_selected_files (standard_view); + if (G_UNLIKELY (files == NULL)) + { + /* if we don't have any files selected, we just popup + * the properties dialog for the current folder. + */ + current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (standard_view)); + if (G_LIKELY (current_directory != NULL)) + files = g_list_prepend (files, g_object_ref (G_OBJECT (current_directory))); + } + + /* popup the properties dialog if we have exactly one file */ if (G_LIKELY (g_list_length (files) == 1)) { toplevel = gtk_widget_get_toplevel (GTK_WIDGET (standard_view)); @@ -1426,6 +1467,8 @@ thunar_standard_view_action_properties (GtkAction *action, gtk_widget_show (dialog); } } + + /* cleanup */ thunar_file_list_free (files); } @@ -1908,27 +1951,73 @@ thunar_standard_view_drag_drop (GtkWidget *view, guint time, ThunarStandardView *standard_view) { - GdkAtom target; + ThunarVfsPath *path; + ThunarFile *file = NULL; + GdkAtom target; + guchar *prop_text; + gint prop_len; + gchar *uri = NULL; target = gtk_drag_dest_find_target (view, context, NULL); - if (G_LIKELY (target != GDK_NONE)) - { - /* set state so the drag-data-received knows that - * this is really a drop this time. - */ - standard_view->priv->drop_occurred = TRUE; - - /* request the drag data from the source */ - gtk_drag_get_data (view, context, target, time); - - /* we'll call gtk_drag_finish() later */ - return TRUE; - } - else + if (G_UNLIKELY (target == GDK_NONE)) { /* we cannot handle the drag data */ return FALSE; } + else if (G_UNLIKELY (target == gdk_atom_intern ("XdndDirectSave0", FALSE))) + { + /* determine the file for the drop position */ + file = thunar_standard_view_get_drop_file (standard_view, x, y, NULL); + if (G_LIKELY (file != NULL)) + { + /* determine the file name from the DnD source window */ + if (gdk_property_get (context->source_window, gdk_atom_intern ("XdndDirectSave0", FALSE), + gdk_atom_intern ("text/plain", FALSE), 0, 1024, FALSE, NULL, NULL, + &prop_len, &prop_text) && prop_text != NULL) + { + /* zero-terminate the string */ + prop_text = g_realloc (prop_text, prop_len + 1); + prop_text[prop_len] = '\0'; + + /* allocate the relative path for the target */ + path = thunar_vfs_path_relative (thunar_file_get_path (file), (const gchar *) prop_text); + + /* determine the new URI */ + uri = thunar_vfs_path_dup_uri (path); + + /* setup the property */ + gdk_property_change (GDK_DRAWABLE (context->source_window), + gdk_atom_intern ("XdndDirectSave0", FALSE), + gdk_atom_intern ("text/plain", FALSE), 8, + GDK_PROP_MODE_REPLACE, uri, strlen (uri)); + + /* cleanup */ + thunar_vfs_path_unref (path); + g_free (prop_text); + g_free (uri); + } + + /* release the file reference */ + g_object_unref (G_OBJECT (file)); + } + + /* if uri == NULL, we didn't set the property */ + if (G_UNLIKELY (uri == NULL)) + return FALSE; + } + + /* set state so the drag-data-received knows that + * this is really a drop this time. + */ + standard_view->priv->drop_occurred = TRUE; + + /* request the drag data from the source (initiates + * saving in case of XdndDirectSave). + */ + gtk_drag_get_data (view, context, target, time); + + /* we'll call gtk_drag_finish() later */ + return TRUE; } @@ -1965,30 +2054,53 @@ thunar_standard_view_drag_data_received (GtkWidget *view, /* reset the state */ standard_view->priv->drop_occurred = FALSE; - /* determine the drop position */ - actions = thunar_standard_view_get_dest_actions (standard_view, context, x, y, time, &file); - if (G_LIKELY ((actions & (GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK)) != 0)) + /* check if we're doing XdndDirectSave */ + if (G_UNLIKELY (info == XDND_DIRECT_SAVE0)) { - /* ask the user what to do with the drop data */ - action = (context->action == GDK_ACTION_ASK) ? thunar_dnd_ask (GTK_WIDGET (standard_view), time, actions) : context->action; + /* we don't handle XdndDirectSave stage (3), result "F" yet */ + if (G_UNLIKELY (selection_data->format == 8 && selection_data->length == 1 && selection_data->data[0] == 'F')) + { + /* indicate that we don't provide "F" fallback */ + gdk_property_change (GDK_DRAWABLE (context->source_window), + gdk_atom_intern ("XdndDirectSave0", FALSE), + gdk_atom_intern ("text/plain", FALSE), 8, + GDK_PROP_MODE_REPLACE, "", 0); + } + else if (G_LIKELY (selection_data->format == 8 && selection_data->length == 1 && selection_data->data[0] == 'S')) + { + // FIXME: Reload the folder contents! + } - /* perform the requested action */ - if (G_LIKELY (action != 0)) + /* in either case, we succeed! */ + succeed = TRUE; + } + else if (G_LIKELY (info == TEXT_URI_LIST)) + { + /* determine the drop position */ + actions = thunar_standard_view_get_dest_actions (standard_view, context, x, y, time, &file); + if (G_LIKELY ((actions & (GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK)) != 0)) { - succeed = thunar_dnd_perform (GTK_WIDGET (standard_view), file, standard_view->priv->drop_path_list, - action, thunar_standard_view_new_files_closure (standard_view)); + /* ask the user what to do with the drop data */ + action = (context->action == GDK_ACTION_ASK) ? thunar_dnd_ask (GTK_WIDGET (standard_view), time, actions) : context->action; + + /* perform the requested action */ + if (G_LIKELY (action != 0)) + { + succeed = thunar_dnd_perform (GTK_WIDGET (standard_view), file, standard_view->priv->drop_path_list, + action, thunar_standard_view_new_files_closure (standard_view)); + } } + + /* release the file reference */ + if (G_LIKELY (file != NULL)) + g_object_unref (G_OBJECT (file)); } - /* release the file reference */ - if (G_LIKELY (file != NULL)) - g_object_unref (G_OBJECT (file)); + /* tell the peer that we handled the drop */ + gtk_drag_finish (context, succeed, FALSE, time); /* disable the highlighting and release the drag data */ thunar_standard_view_drag_leave (view, context, time, standard_view); - - /* tell the peer that we handled the drop */ - gtk_drag_finish (context, succeed, FALSE, time); } } @@ -2032,26 +2144,59 @@ thunar_standard_view_drag_motion (GtkWidget *view, guint time, ThunarStandardView *standard_view) { - GdkAtom target; + GdkDragAction action = 0; + GtkTreePath *path; + ThunarFile *file = NULL; + GdkAtom target; /* request the drop data on-demand (if we don't have it already) */ if (G_UNLIKELY (!standard_view->priv->drop_data_ready)) { /* check if we can handle that drag data (yet?) */ target = gtk_drag_dest_find_target (view, context, NULL); - if (G_UNLIKELY (target == GDK_NONE)) + if (G_UNLIKELY (target == gdk_atom_intern ("XdndDirectSave0", FALSE))) { - /* we cannot handle the drag data */ - gdk_drag_status (context, 0, time); + /* determine the file for the given coordinates */ + file = thunar_standard_view_get_drop_file (standard_view, x, y, &path); + + /* check if we can save here */ + if (G_LIKELY (file != NULL && thunar_file_is_directory (file) && thunar_file_is_writable (file))) + action = context->suggested_action; + + /* reset path if we cannot drop */ + if (G_UNLIKELY (action == 0 && path != NULL)) + { + gtk_tree_path_free (path); + path = NULL; + } + + /* do the view highlighting */ + if (standard_view->priv->drop_highlight != (path == NULL && action != 0)) + { + standard_view->priv->drop_highlight = (path == NULL && action != 0); + gtk_widget_queue_draw (GTK_WIDGET (standard_view)); + } + + /* setup drop-file for the icon renderer to highlight the target */ + g_object_set (G_OBJECT (standard_view->icon_renderer), "drop-file", (action != 0) ? file : NULL, NULL); + + /* do the item highlighting */ + (*THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->highlight_path) (standard_view, path); + + /* cleanup */ + if (G_LIKELY (file != NULL)) + g_object_unref (G_OBJECT (file)); + if (G_LIKELY (path != NULL)) + gtk_tree_path_free (path); } else { /* request the drag data from the source */ gtk_drag_get_data (view, context, target, time); - - /* and deny the drop so far */ - gdk_drag_status (context, 0, time); } + + /* tell Gdk whether we can drop here */ + gdk_drag_status (context, action, time); } else { @@ -2452,7 +2597,7 @@ thunar_standard_view_selection_changed (ThunarStandardView *standard_view) gtk_action_set_sensitive (standard_view->priv->action_create_folder, writable); /* update the "Properties" action */ - gtk_action_set_sensitive (standard_view->priv->action_properties, (n_selected_files == 1)); + gtk_action_set_sensitive (standard_view->priv->action_properties, (n_selected_files == 1 || (n_selected_files == 0 && current_directory != NULL))); /* update the "Copy File(s)" action */ g_object_set (G_OBJECT (standard_view->priv->action_copy), diff --git a/thunar/thunar-text-renderer.c b/thunar/thunar-text-renderer.c index 42d3bc2db80c5e3ed413b85aec352cde1f379264..cf41b3081238263f50c67fa51fc655a50d9730d7 100644 --- a/thunar/thunar-text-renderer.c +++ b/thunar/thunar-text-renderer.c @@ -1,6 +1,6 @@ /* $Id$ */ /*- - * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org> + * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -634,11 +634,10 @@ static void thunar_text_renderer_set_widget (ThunarTextRenderer *text_renderer, GtkWidget *widget) { - // FIXME: The sample text should be translatable with a hint to translators! - static const gchar SAMPLE_TEXT[] = "The Quick Brown Fox Jumps Over the Lazy Dog"; - PangoRectangle extents; - gint focus_padding; - gint focus_line_width; + PangoFontMetrics *metrics; + PangoContext *context; + gint focus_padding; + gint focus_line_width; if (G_LIKELY (widget == text_renderer->widget)) return; @@ -664,12 +663,15 @@ thunar_text_renderer_set_widget (ThunarTextRenderer *text_renderer, g_signal_connect_swapped (G_OBJECT (text_renderer->widget), "destroy", G_CALLBACK (thunar_text_renderer_invalidate), text_renderer); g_signal_connect_swapped (G_OBJECT (text_renderer->widget), "style-set", G_CALLBACK (thunar_text_renderer_invalidate), text_renderer); + /* allocate a new pango layout for this widget */ + context = gtk_widget_get_pango_context (widget); + text_renderer->layout = pango_layout_new (context); + /* calculate the average character dimensions */ - text_renderer->layout = gtk_widget_create_pango_layout (widget, SAMPLE_TEXT); - pango_layout_get_pixel_extents (text_renderer->layout, NULL, &extents); - pango_layout_set_width (text_renderer->layout, -1); - text_renderer->char_width = extents.width / g_utf8_strlen (SAMPLE_TEXT, sizeof (SAMPLE_TEXT) - 1); - text_renderer->char_height = extents.height; + metrics = pango_context_get_metrics (context, widget->style->font_desc, pango_context_get_language (context)); + text_renderer->char_width = PANGO_PIXELS (pango_font_metrics_get_approximate_char_width (metrics)); + text_renderer->char_height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics)); + pango_font_metrics_unref (metrics); /* determine the focus-padding and focus-line-width style properties from the widget */ gtk_widget_style_get (widget, "focus-padding", &focus_padding, "focus-line-width", &focus_line_width, NULL); diff --git a/thunar/thunar-window.c b/thunar/thunar-window.c index b0d13b0d5ed305d9032a11c24c5dbe44b1dfd969..a55fc890e2848d5ba584e0f9550b023072a1cce5 100644 --- a/thunar/thunar-window.c +++ b/thunar/thunar-window.c @@ -920,11 +920,19 @@ thunar_window_action_go_up (GtkAction *action, ThunarWindow *window) { ThunarFile *parent; + GError *error = NULL; - // FIXME: error handling - parent = thunar_file_get_parent (window->current_directory, NULL); - thunar_window_set_current_directory (window, parent); - g_object_unref (G_OBJECT (parent)); + parent = thunar_file_get_parent (window->current_directory, &error); + if (G_LIKELY (parent != NULL)) + { + thunar_window_set_current_directory (window, parent); + g_object_unref (G_OBJECT (parent)); + } + else + { + thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open parent folder")); + g_error_free (error); + } } @@ -1089,7 +1097,7 @@ thunar_window_current_directory_changed (ThunarFile *current_directory, /* set window title and icon */ icon = thunar_icon_factory_load_file_icon (window->icon_factory, current_directory, THUNAR_FILE_ICON_STATE_DEFAULT, 48); - gtk_window_set_title (GTK_WINDOW (window), thunar_file_get_special_name (current_directory)); + gtk_window_set_title (GTK_WINDOW (window), thunar_file_get_display_name (current_directory)); gtk_window_set_icon (GTK_WINDOW (window), icon); g_object_unref (G_OBJECT (icon)); }