static void
thunar_chooser_button_pressed (ThunarChooserButton *chooser_button,
                               GtkWidget           *button)
{
  ThunarVfsMimeApplication *default_application;
  ThunarVfsMimeInfo        *info;
  ThunarIconFactory        *icon_factory;
  GtkIconTheme             *icon_theme;
  const gchar              *icon_name;
  GdkPixbuf                *icon;
  GtkWidget                *image;
  GtkWidget                *item;
  GtkWidget                *menu;
  GList                    *applications;
  GList                    *lp;
  gint                      icon_size;

  _thunar_return_if_fail (THUNAR_IS_CHOOSER_BUTTON (chooser_button));
  _thunar_return_if_fail (chooser_button->button == button);
  _thunar_return_if_fail (GTK_IS_BUTTON (button));

  /* verify that we have a valid file */
  if (G_UNLIKELY (chooser_button->file == NULL))
    return;

  /* determine the mime info for the file */
  info = thunar_file_get_mime_info (chooser_button->file);

  /* determine the default application */
  default_application = thunar_vfs_mime_database_get_default_application (chooser_button->database, info);
  if (G_UNLIKELY (default_application == NULL))
    {
      /* no default application, just popup the application chooser */
      thunar_chooser_button_activate_other (chooser_button);
      return;
    }

  /* determine all applications that claim to be able to handle the file */
  applications = thunar_vfs_mime_database_get_applications (chooser_button->database, info);

  /* make sure the default application comes first */
  lp = g_list_find (applications, default_application);
  if (G_LIKELY (lp != NULL))
    {
      applications = g_list_delete_link (applications, lp);
      g_object_unref (G_OBJECT (default_application));
    }
  applications = g_list_prepend (applications, default_application);

  /* allocate a new popup menu */
  menu = gtk_menu_new ();

  /* determine the icon size for menus */
  gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_size, &icon_size);

  /* determine the icon factory for our screen */
  icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (button));
  icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);

  /* add the other possible applications */
  for (lp = applications; lp != NULL; lp = lp->next)
    {
      item = gtk_image_menu_item_new_with_label (thunar_vfs_mime_handler_get_name (lp->data));
      g_object_set_data_full (G_OBJECT (item), I_("thunar-vfs-mime-application"), lp->data, g_object_unref);
      g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_chooser_button_activate), chooser_button);
      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
      gtk_widget_show (item);

      /* setup the icon for the application */
      icon_name = thunar_vfs_mime_handler_lookup_icon_name (lp->data, icon_theme);
      icon = thunar_icon_factory_load_icon (icon_factory, icon_name, icon_size, NULL, FALSE);
      image = gtk_image_new_from_pixbuf (icon);
      gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
      gtk_widget_show (image);
      if (G_LIKELY (icon != NULL))
        g_object_unref (icon);
    }

  /* cleanup */
  g_object_unref (G_OBJECT (icon_factory));

  /* append a separator */
  item = gtk_separator_menu_item_new ();
  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  gtk_widget_show (item);

  /* release the applications list */
  g_list_free (applications);

  /* add the "Other Application..." choice */
  item = gtk_image_menu_item_new_with_mnemonic (_("_Other Application..."));
  g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_chooser_button_activate_other), chooser_button);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  gtk_widget_show (item);

  /* make sure the menu has atleast the same width as the chooser */
  if (menu->allocation.width < button->allocation.width)
    gtk_widget_set_size_request (menu, button->allocation.width, -1);

  /* run the menu on the button's screen (takes over the floating reference of menu) */
  thunar_gtk_menu_run (GTK_MENU (menu), button, menu_position, button, 0, gtk_get_current_event_time ());

  /* yeppa, that's a requirement */
  gtk_button_released (GTK_BUTTON (button));
}
static void
thunar_location_entry_button_clicked (GtkWidget           *button,
                                      ThunarLocationEntry *location_entry)
{
  ThunarShortcutsModel *model;
  ThunarIconFactory    *icon_factory;
  ThunarVfsVolume      *volume;
  GtkIconTheme         *icon_theme;
  const gchar          *icon_name;
  GtkTreeIter           iter;
  ThunarFile           *file;
  GtkWidget            *image;
  GtkWidget            *item;
  GtkWidget            *menu;
  GdkPixbuf            *icon;
  gint                  icon_size;
  gint                  width;

  _thunar_return_if_fail (THUNAR_IS_LOCATION_ENTRY (location_entry));
  _thunar_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));

  /* allocate a new menu */
  menu = gtk_menu_new ();

  /* determine the icon theme and factory */
  icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (button));
  icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);

  /* determine the icon size for menus */
  gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_size, &icon_size);

  /* load the menu items from the shortcuts model */
  model = thunar_shortcuts_model_get_default ();
  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter))
    {
      do
        {
          /* determine the file and volume for the item */
          gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
                              THUNAR_SHORTCUTS_MODEL_COLUMN_FILE, &file,
                              THUNAR_SHORTCUTS_MODEL_COLUMN_VOLUME, &volume,
                              -1);

          /* check if we have a separator here */
          if (G_UNLIKELY (file == NULL && volume == NULL))
            {
              /* generate a separator the menu */
              item = gtk_separator_menu_item_new ();
            }
          else if (G_UNLIKELY (volume != NULL))
            {
              /* generate an image menu item for the volume */
              item = gtk_image_menu_item_new_with_label (thunar_vfs_volume_get_name (volume));

              /* load the icon for the volume */
              icon_name = thunar_vfs_volume_lookup_icon_name (volume, icon_theme);
              icon = thunar_icon_factory_load_icon (icon_factory, icon_name, icon_size, NULL, FALSE);
              if (G_LIKELY (icon != NULL))
                {
                  /* generate an image for the menu item */
                  image = gtk_image_new_from_pixbuf (icon);
                  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
                  g_object_unref (G_OBJECT (icon));
                  gtk_widget_show (image);
                }
            }
          else
            {
              /* generate an image menu item for the file */
              item = gtk_image_menu_item_new_with_label (thunar_file_get_display_name (file));

              /* load the icon for the file and generate the image for the menu item */
              icon = thunar_icon_factory_load_file_icon (icon_factory, file, THUNAR_FILE_ICON_STATE_DEFAULT, icon_size);
              image = gtk_image_new_from_pixbuf (icon);
              gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
              g_object_unref (G_OBJECT (icon));
              gtk_widget_show (image);
            }

          /* connect the file and volume to the item */
          g_object_set_data_full (G_OBJECT (item), I_("thunar-vfs-volume"), volume, g_object_unref);
          g_object_set_data_full (G_OBJECT (item), I_("thunar-file"), file, g_object_unref);

          /* append the new item to the menu */
          g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (thunar_location_entry_item_activated), location_entry);
          gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
          gtk_widget_show (item);
        }
      while (gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter));
    }

  /* make sure the menu has atleast the same width as the location entry */
  width = GTK_WIDGET (location_entry)->allocation.width - 2 * gtk_container_get_border_width (GTK_CONTAINER (location_entry));
  if (G_LIKELY (menu->allocation.width < width))
    gtk_widget_set_size_request (menu, width, -1);

  /* select the first visible or selectable item in the menu */
  gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), TRUE);

  /* enable the button, making sure that we do not recurse on the "clicked" signal by temporarily blocking the handler */
  g_signal_handlers_block_by_func (G_OBJECT (button), G_CALLBACK (thunar_location_entry_button_clicked), location_entry);
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
  g_signal_handlers_unblock_by_func (G_OBJECT (button), G_CALLBACK (thunar_location_entry_button_clicked), location_entry);

  /* run the menu, taking ownership over the menu object */
  thunar_gtk_menu_run (GTK_MENU (menu), button, menu_position, location_entry, 1, gtk_get_current_event_time ());

  /* disable the button, making sure that we do not recurse on the "clicked" signal by temporarily blocking the handler */
  g_signal_handlers_block_by_func (G_OBJECT (button), G_CALLBACK (thunar_location_entry_button_clicked), location_entry);
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
  g_signal_handlers_unblock_by_func (G_OBJECT (button), G_CALLBACK (thunar_location_entry_button_clicked), location_entry);

  /* clean up */
  g_object_unref (G_OBJECT (icon_factory));
  g_object_unref (G_OBJECT (model));
}
Esempio n. 3
0
/**
 * thunar_dnd_ask:
 * @widget    : the widget on which the drop was performed.
 * @folder    : the #ThunarFile to which the @path_list is being dropped.
 * @path_list : the #GFile<!---->s of the files being dropped to @file.
 * @timestamp : the time of the drop event.
 * @actions   : the list of actions supported for the drop.
 *
 * Pops up a menu that asks the user to choose one of the
 * @actions or to cancel the drop. If the user chooses a
 * valid #GdkDragAction from @actions, then this action is
 * returned. Else if the user cancels the drop, 0 will be
 * returned.
 *
 * This method can be used to implement a response to the
 * #GDK_ACTION_ASK action on drops.
 *
 * Return value: the selected #GdkDragAction or 0 to cancel.
 **/
GdkDragAction
thunar_dnd_ask (GtkWidget    *widget,
                ThunarFile   *folder,
                GList        *path_list,
                guint         timestamp,
                GdkDragAction dnd_actions)
{
  static const GdkDragAction dnd_action_items[] = { GDK_ACTION_COPY, GDK_ACTION_MOVE, GDK_ACTION_LINK };
  static const gchar        *dnd_action_names[] = { N_ ("_Copy here"), N_ ("_Move here"), N_ ("_Link here") };
  static const gchar        *dnd_action_icons[] = { "stock_folder-copy", "stock_folder-move", NULL };

  ThunarxProviderFactory *factory;
  GdkDragAction           dnd_action = 0;
  ThunarFile             *file;
  GtkWidget              *window;
  GtkWidget              *image;
  GtkWidget              *menu;
  GtkWidget              *item;
  GList                  *file_list = NULL;
  GList                  *providers = NULL;
  GList                  *actions = NULL;
  GList                  *lp;
  guint                   n;

  _thunar_return_val_if_fail (thunar_file_is_directory (folder), 0);
  _thunar_return_val_if_fail (GTK_IS_WIDGET (widget), 0);

  /* connect to the provider factory */
  factory = thunarx_provider_factory_get_default ();

  /* prepare the popup menu */
  menu = gtk_menu_new ();

  /* append the various items */
  for (n = 0; n < G_N_ELEMENTS (dnd_action_items); ++n)
    if (G_LIKELY ((dnd_actions & dnd_action_items[n]) != 0))
      {
        item = gtk_image_menu_item_new_with_mnemonic (_(dnd_action_names[n]));
        g_object_set_data (G_OBJECT (item), I_("dnd-action"), GUINT_TO_POINTER (dnd_action_items[n]));
        g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (dnd_action_selected), &dnd_action);
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
        gtk_widget_show (item);

        /* add image to the menu item */
        if (G_LIKELY (dnd_action_icons[n] != NULL))
          {
            image = gtk_image_new_from_icon_name (dnd_action_icons[n], GTK_ICON_SIZE_MENU);
            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
          }
      }

  /* append the separator */
  item = gtk_separator_menu_item_new ();
  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  gtk_widget_show (item);

  /* determine the toplevel window the widget belongs to */
  window = gtk_widget_get_toplevel (widget);
  if (G_LIKELY (window != NULL && gtk_widget_get_toplevel (window)))
    {
      /* check if we can resolve all paths */
      for (lp = path_list; lp != NULL; lp = lp->next)
        {
          /* try to resolve this path */
          file = thunar_file_cache_lookup (lp->data);
          if (G_LIKELY (file != NULL))
            file_list = g_list_prepend (file_list, file);
          else
            break;
        }

      /* check if we resolved all paths (and have atleast one file) */
      if (G_LIKELY (file_list != NULL && lp == NULL))
        {
          /* load the menu providers from the provider factory */
          providers = thunarx_provider_factory_list_providers (factory, THUNARX_TYPE_MENU_PROVIDER);

          /* load the dnd actions offered by the menu providers */
          for (lp = providers; lp != NULL; lp = lp->next)
            {
              /* merge the actions from this provider */
              actions = g_list_concat (actions, thunarx_menu_provider_get_dnd_actions (lp->data, window, THUNARX_FILE_INFO (folder), file_list));
              g_object_unref (G_OBJECT (lp->data));
            }
          g_list_free (providers);

          /* check if we have atleast one action */
          if (G_UNLIKELY (actions != NULL))
            {
              /* add menu items for all actions */
              for (lp = actions; lp != NULL; lp = lp->next)
                {
                  /* add a menu item for the action */
                  item = gtk_action_create_menu_item (lp->data);
                  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
                  g_object_unref (G_OBJECT (lp->data));
                  gtk_widget_show (item);
                }
              g_list_free (actions);

              /* append another separator */
              item = gtk_separator_menu_item_new ();
              gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
              gtk_widget_show (item);
            }
        }
    }

  /* append the cancel item */
  item = gtk_image_menu_item_new_from_stock (GTK_STOCK_CANCEL, NULL);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  gtk_widget_show (item);

  /* run the menu on the widget's screen (takes over the floating reference of menu) */
  thunar_gtk_menu_run (GTK_MENU (menu), widget, NULL, NULL, 3, timestamp);

  /* cleanup */
  g_object_unref (G_OBJECT (factory));
  g_list_free_full (file_list, g_object_unref);

  return dnd_action;
}