Index: gtk/gtkfilechooserdefault.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkfilechooserdefault.c,v
retrieving revision 1.247
diff -u -r1.247 gtkfilechooserdefault.c
--- gtk/gtkfilechooserdefault.c	27 Jan 2005 20:08:56 -0000	1.247
+++ gtk/gtkfilechooserdefault.c	29 Jan 2005 17:01:51 -0000
@@ -117,6 +117,8 @@
   /* The file browsing widgets */
   GtkWidget *browse_widgets;
   GtkWidget *browse_shortcuts_tree_view;
+  GtkWidget *browse_shortcuts_popup_menu;
+  GtkWidget *browse_shortcuts_popup_menu_remove_shortcut_item;
   GtkWidget *browse_shortcuts_add_button;
   GtkWidget *browse_shortcuts_remove_button;
   GtkWidget *browse_files_tree_view;
@@ -172,9 +174,13 @@
   GSource *edited_idle;
   char *edited_new_text;
 
-  gulong settings_signal_id;
+  gulong settings_icon_theme_name_signal_id;
+  gulong settings_icon_sizes_signal_id;
   int icon_size;
 
+  gulong settings_file_single_click_activate_id;
+  gboolean single_click_activate;
+
   gulong toplevel_set_focus_id;
   GtkWidget *toplevel_last_focus_widget;
 
@@ -365,6 +371,9 @@
 static gboolean shortcuts_key_press_event_cb (GtkWidget             *widget,
 					      GdkEventKey           *event,
 					      GtkFileChooserDefault *impl);
+static gboolean shortcuts_button_press_event_cb (GtkWidget             *widget,
+						 GdkEventButton        *event,
+						 GtkFileChooserDefault *impl);
 
 static gboolean shortcuts_select_func   (GtkTreeSelection      *selection,
 					 GtkTreeModel          *model,
@@ -400,6 +409,13 @@
 			 GtkTreeIter        *iter,
 			 gpointer            user_data);
 
+static void popup_position_func (GtkMenu   *menu,
+				 gint      *x,
+				 gint      *y,
+				 gboolean  *push_in,
+				 gpointer	user_data);
+
+
 static void path_bar_clicked           (GtkPathBar            *path_bar,
 					GtkFilePath           *file_path,
 					gboolean               child_is_hidden,
@@ -665,6 +681,7 @@
   impl->icon_size = FALLBACK_ICON_SIZE;
   impl->load_state = LOAD_EMPTY;
   impl->pending_select_paths = NULL;
+  impl->single_click_activate = FALSE;
 
   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (impl), TRUE);
   gtk_box_set_spacing (GTK_BOX (impl), 12);
@@ -2285,6 +2302,9 @@
       g_free (tip);
     }
 
+  if (impl->browse_shortcuts_popup_menu_remove_shortcut_item)
+    gtk_widget_set_sensitive (impl->browse_shortcuts_popup_menu_remove_shortcut_item, removable);
+
   g_free (name);
 }
 
@@ -2846,6 +2866,163 @@
   return FALSE;
 }
 
+/* When single-click is enabled, display a hand when cursor
+ * is above a file */
+static gboolean
+tree_view_motion_event_cb (GtkWidget             *widget,
+			   GdkEventMotion        *event,
+			   GtkFileChooserDefault *impl)
+{
+  static GdkDisplay *last_display = NULL;
+  static GdkCursor  *hand_cursor = NULL;
+
+  GdkDisplay *current_display;
+
+  if (!impl->single_click_activate)
+    return FALSE;
+
+  g_assert (GTK_IS_TREE_VIEW (widget));
+
+  current_display = gtk_widget_get_display (widget);
+  g_assert (current_display);
+
+  if (!last_display || /* first run */
+      current_display != last_display) /* switched display */
+    {
+      if (hand_cursor)
+	gdk_cursor_unref (hand_cursor);
+
+      hand_cursor = gdk_cursor_new_for_display (current_display,
+		      				GDK_HAND2);
+    }
+
+  if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
+			  	     event->x, event->y,
+				     NULL, NULL, NULL, NULL))
+    gdk_window_set_cursor (widget->window, hand_cursor);
+  else
+    gdk_window_set_cursor (widget->window, NULL);
+
+  last_display = current_display;
+
+  return TRUE;
+}
+
+/* Callback used when the shortcut list's popup menu is detached */
+static void
+shortcuts_popup_menu_detach_cb (GtkWidget *attach_widget,
+				GtkMenu   *menu)
+{
+  GtkFileChooserDefault *impl;
+
+  impl = g_object_get_data (G_OBJECT (attach_widget), "GtkFileChooserDefault");
+  g_assert (GTK_IS_FILE_CHOOSER_DEFAULT (impl));
+
+  impl->browse_shortcuts_popup_menu = NULL;
+  impl->browse_shortcuts_popup_menu_remove_shortcut_item = NULL;
+}
+
+/* Constructs the popup menu for the shortcuts list if needed */
+static void
+shortcuts_build_popup_menu (GtkFileChooserDefault *impl)
+{
+  GtkWidget *item;
+
+  if (impl->browse_shortcuts_popup_menu)
+    return;
+
+  impl->browse_shortcuts_popup_menu = gtk_menu_new ();
+  gtk_menu_attach_to_widget (GTK_MENU (impl->browse_shortcuts_popup_menu),
+			     impl->browse_shortcuts_tree_view,
+			     shortcuts_popup_menu_detach_cb);
+
+  item = gtk_image_menu_item_new_with_mnemonic (_("_Remove from Shortcuts"));
+  impl->browse_shortcuts_popup_menu_remove_shortcut_item = item;
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
+				 gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
+  gtk_widget_set_sensitive (item, FALSE);
+  g_signal_connect_swapped (item, "activate",
+		  	    G_CALLBACK (remove_selected_bookmarks), impl);
+  gtk_widget_show (item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu), item);
+
+  bookmarks_check_remove_sensitivity (impl);
+}
+
+static void
+shortcuts_popup_menu (GtkFileChooserDefault *impl,
+		      GdkEventButton        *event)
+{
+  shortcuts_build_popup_menu (impl);
+
+  if (event)
+    gtk_menu_popup (GTK_MENU (impl->browse_shortcuts_popup_menu),
+		    NULL, NULL, NULL, NULL,
+		    event->button, event->time);
+  else
+    {
+      gtk_menu_popup (GTK_MENU (impl->browse_shortcuts_popup_menu),
+		      NULL, NULL,
+		      popup_position_func, impl->browse_shortcuts_tree_view,
+		      0, GDK_CURRENT_TIME);
+      gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu),
+				   FALSE);
+    }
+}
+
+/* Callback used for the GtkWidget::popup-menu signal of the shortcut list */
+static gboolean
+shortcuts_popup_menu_cb (GtkWidget *widget,
+			 GtkFileChooserDefault *impl)
+{
+  shortcuts_popup_menu (impl, NULL);
+  return TRUE;
+}
+
+/* Handler for GtkWidget::button-press-event on the shortcuts list */
+static gboolean
+shortcuts_button_press_event_cb (GtkWidget             *widget,
+				 GdkEventButton        *event,
+				 GtkFileChooserDefault *impl)
+{
+  GtkTreePath       *path;
+  GtkTreeViewColumn *column;
+  GtkTreeSelection  *selection;
+
+  if (event->button == 3)
+    {
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
+
+      if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
+			      		 event->x, event->y, &path, NULL, NULL, NULL))
+        {
+          gtk_tree_selection_select_path (selection, path);
+          shortcuts_popup_menu (impl, event);
+        }
+      else
+	gtk_tree_selection_unselect_all (selection);
+
+      gtk_tree_path_free (path);
+
+    }
+  else
+    {
+      if (!impl->single_click_activate ||
+	  !gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
+					  event->x, event->y, &path, &column, NULL, NULL))
+	return FALSE;
+
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
+      gtk_tree_selection_select_path (selection, path);
+
+      gtk_tree_view_row_activated (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), path, column);
+
+      gtk_tree_path_free (path);
+    }
+
+  return TRUE;
+}
+
 
 /* Creates the widgets for the shortcuts and bookmarks tree */
 static GtkWidget *
@@ -2870,6 +3047,7 @@
   impl->browse_shortcuts_tree_view = gtk_tree_view_new ();
   g_signal_connect (impl->browse_shortcuts_tree_view, "key-press-event",
 		    G_CALLBACK (tree_view_keybinding_cb), impl);
+  g_object_set_data (G_OBJECT (impl->browse_shortcuts_tree_view), "GtkFileChooserDefault", impl);
   atk_object_set_name (gtk_widget_get_accessible (impl->browse_shortcuts_tree_view), _("Shortcuts"));
   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), FALSE);
 
@@ -2901,6 +3079,11 @@
 
   g_signal_connect (impl->browse_shortcuts_tree_view, "key-press-event",
 		    G_CALLBACK (shortcuts_key_press_event_cb), impl);
+  g_signal_connect (impl->browse_shortcuts_tree_view, "button-press-event",
+		    G_CALLBACK (shortcuts_button_press_event_cb), impl);
+
+  g_signal_connect (impl->browse_shortcuts_tree_view, "popup-menu",
+		    G_CALLBACK (shortcuts_popup_menu_cb), impl);
 
   g_signal_connect (impl->browse_shortcuts_tree_view, "drag-begin",
 		    G_CALLBACK (shortcuts_drag_begin_cb), impl);
@@ -2918,6 +3101,9 @@
   g_signal_connect (impl->browse_shortcuts_tree_view, "drag-data-received",
 		    G_CALLBACK (shortcuts_drag_data_received_cb), impl);
 
+  g_signal_connect (impl->browse_shortcuts_tree_view, "motion-notify-event",
+		    G_CALLBACK (tree_view_motion_event_cb), impl);
+
   gtk_container_add (GTK_CONTAINER (swin), impl->browse_shortcuts_tree_view);
   gtk_widget_show (impl->browse_shortcuts_tree_view);
 
@@ -3045,8 +3231,8 @@
 
 /* Callback used when the file list's popup menu is detached */
 static void
-popup_menu_detach_cb (GtkWidget *attach_widget,
-		      GtkMenu   *menu)
+file_list_popup_menu_detach_cb (GtkWidget *attach_widget,
+				GtkMenu   *menu)
 {
   GtkFileChooserDefault *impl;
 
@@ -3096,7 +3282,7 @@
   impl->browse_files_popup_menu = gtk_menu_new ();
   gtk_menu_attach_to_widget (GTK_MENU (impl->browse_files_popup_menu),
 			     impl->browse_files_tree_view,
-			     popup_menu_detach_cb);
+			     file_list_popup_menu_detach_cb);
 
   item = gtk_image_menu_item_new_with_mnemonic (_("_Add to Shortcuts"));
   impl->browse_files_popup_menu_add_shortcut_item = item;
@@ -3126,6 +3312,8 @@
 		    G_CALLBACK (show_hidden_toggled_cb), impl);
   gtk_widget_show (item);
   gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
+
+  bookmarks_check_add_sensitivity (impl);
 }
 
 /* Updates the popup menu for the file list, creating it if necessary */
@@ -3216,10 +3404,39 @@
 			    GdkEventButton        *event,
 			    GtkFileChooserDefault *impl)
 {
-  if (event->button != 3)
-    return FALSE;
+  GtkTreePath       *path;
+  GtkTreeViewColumn *column;
+  GtkTreeSelection  *selection;
+
+  if (event->button == 3)
+    {
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+
+      if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (impl->browse_files_tree_view),
+			      		 event->x, event->y, &path, NULL, NULL, NULL))
+	gtk_tree_selection_select_path (selection, path);
+      else
+	gtk_tree_selection_unselect_all (selection);
+
+      gtk_tree_path_free (path);
+
+      file_list_popup_menu (impl, event);
+    }
+  else
+    {
+      if (!impl->single_click_activate ||
+	  !gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (impl->browse_files_tree_view),
+		  			  event->x, event->y, &path, &column, NULL, NULL))
+	return FALSE;
+
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+      gtk_tree_selection_select_path (selection, path);
+
+      gtk_tree_view_row_activated (GTK_TREE_VIEW (impl->browse_files_tree_view), path, column);
+
+      gtk_tree_path_free (path);
+    }
 
-  file_list_popup_menu (impl, event);
   return TRUE;
 }
 
@@ -3257,6 +3474,9 @@
   g_signal_connect (impl->browse_files_tree_view, "button-press-event",
 		    G_CALLBACK (list_button_press_event_cb), impl);
 
+  g_signal_connect (impl->browse_files_tree_view, "motion-notify-event",
+		    G_CALLBACK (tree_view_motion_event_cb), impl);
+
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
   gtk_tree_selection_set_select_function (selection,
 					  list_select_func,
@@ -3965,17 +4185,35 @@
 
 /* Removes the settings signal handler.  It's safe to call multiple times */
 static void
-remove_settings_signal (GtkFileChooserDefault *impl,
-			GdkScreen             *screen)
+remove_settings_signals (GtkFileChooserDefault *impl,
+			 GdkScreen             *screen)
 {
-  if (impl->settings_signal_id)
+  GtkSettings *settings;
+
+  if (screen)
+	  settings = gtk_settings_get_for_screen (screen);
+  else
+	  settings = gtk_settings_get_default ();
+
+  if (impl->settings_icon_theme_name_signal_id)
     {
-      GtkSettings *settings;
+      g_signal_handler_disconnect (settings,
+				   impl->settings_icon_theme_name_signal_id);
+      impl->settings_icon_theme_name_signal_id = 0;
+    }
 
-      settings = gtk_settings_get_for_screen (screen);
+  if (impl->settings_icon_sizes_signal_id)
+    {
       g_signal_handler_disconnect (settings,
-				   impl->settings_signal_id);
-      impl->settings_signal_id = 0;
+				   impl->settings_icon_sizes_signal_id);
+      impl->settings_icon_sizes_signal_id = 0;
+    }
+
+  if (impl->settings_file_single_click_activate_id)
+    {
+      g_signal_handler_disconnect (settings,
+		      		   impl->settings_file_single_click_activate_id);
+      impl->settings_file_single_click_activate_id = 0;
     }
 }
 
@@ -3990,7 +4228,7 @@
       impl->extra_widget = NULL;
     }
 
-  remove_settings_signal (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
+  remove_settings_signals (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
 
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -4070,40 +4308,37 @@
   gtk_widget_queue_resize (impl->browse_files_tree_view);
 }
 
-/* Callback used when a GtkSettings value changes */
 static void
-settings_notify_cb (GObject               *object,
-		    GParamSpec            *pspec,
-		    GtkFileChooserDefault *impl)
+single_click_notify_cb (GObject               *settings,
+			GParamSpec            *pspec,
+			GtkFileChooserDefault *impl)
 {
-  const char *name;
-
-  name = g_param_spec_get_name (pspec);
-
-  if (strcmp (name, "gtk-icon-theme-name") == 0
-      || strcmp (name, "gtk-icon-sizes") == 0)
-    change_icon_theme (impl);
+	g_object_get (settings, "gtk-file-single-click-activate", &(impl->single_click_activate));
 }
 
-/* Installs a signal handler for GtkSettings so that we can monitor changes in
- * the icon theme.
+/* Installs signal handlers for GtkSettings so that we can monitor changes
  */
 static void
-check_icon_theme (GtkFileChooserDefault *impl)
+setup_settings_signals (GtkFileChooserDefault *impl)
 {
   GtkSettings *settings;
 
-  if (impl->settings_signal_id)
-    return;
-
   if (gtk_widget_has_screen (GTK_WIDGET (impl)))
-    {
-      settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
-      impl->settings_signal_id = g_signal_connect (settings, "notify",
-						   G_CALLBACK (settings_notify_cb), impl);
+    settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
+  else
+    settings = gtk_settings_get_default ();
 
-      change_icon_theme (impl);
-    }
+  impl->settings_icon_theme_name_signal_id = g_signal_connect_swapped (settings, "notify::gtk-icon-theme-name",
+		      						       G_CALLBACK (change_icon_theme), impl);
+
+  impl->settings_icon_sizes_signal_id = g_signal_connect_swapped (settings, "notify::gtk-icon-sizes",
+		      						  G_CALLBACK (change_icon_theme), impl);
+
+  impl->settings_file_single_click_activate_id = g_signal_connect (settings, "notify::gtk-file-single-click-activate",
+		      						   G_CALLBACK (single_click_notify_cb), impl);
+
+  change_icon_theme (impl);
+  single_click_notify_cb (G_OBJECT (settings), NULL, impl);
 }
 
 static void
@@ -4134,8 +4369,8 @@
   if (GTK_WIDGET_CLASS (parent_class)->screen_changed)
     GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, previous_screen);
 
-  remove_settings_signal (impl, previous_screen);
-  check_icon_theme (impl);
+  remove_settings_signals (impl, previous_screen);
+  setup_settings_signals (impl);
 
   g_signal_emit_by_name (widget, "default-size-changed");
 }
