/* Clipboard
 *
 * GtkClipboard is used for clipboard handling. This demo shows how to
 * copy and paste text to and from the clipboard.
 *
 * It also shows how to transfer images via the clipboard or via
 * drag-and-drop, and how to make clipboard contents persist after
 * the application exits. Clipboard persistence requires a clipboard
 * manager to run.
 */

#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <string.h>

void
copy_button_clicked (GtkWidget *button,
                     gpointer   user_data)
{
  GtkWidget *entry;
  GtkClipboard *clipboard;

  entry = GTK_WIDGET (user_data);

  /* Get the clipboard object */
  clipboard = gtk_widget_get_clipboard (entry,
                                        GDK_SELECTION_CLIPBOARD);

  /* Set clipboard text */
  gtk_clipboard_set_text (clipboard, gtk_entry_get_text (GTK_ENTRY (entry)), -1);
}

void
paste_received (GtkClipboard *clipboard,
                const gchar  *text,
                gpointer      user_data)
{
  GtkWidget *entry;

  entry = GTK_WIDGET (user_data);

  /* Set the entry text */
  if(text)
    gtk_entry_set_text (GTK_ENTRY (entry), text);
}

void
paste_button_clicked (GtkWidget *button,
                     gpointer   user_data)
{
  GtkWidget *entry;
  GtkClipboard *clipboard;

  entry = GTK_WIDGET (user_data);

  /* Get the clipboard object */
  clipboard = gtk_widget_get_clipboard (entry,
                                        GDK_SELECTION_CLIPBOARD);

  /* Request the contents of the clipboard, contents_received will be
     called when we do get the contents.
   */
  gtk_clipboard_request_text (clipboard,
                              paste_received, entry);
}

static GdkPixbuf *
get_image_pixbuf (GtkImage *image)
{
  const gchar *icon_name;
  GtkIconSize size;
  GtkIconTheme *icon_theme;
  int width;

  switch (gtk_image_get_storage_type (image))
    {
    case GTK_IMAGE_PIXBUF:
      return g_object_ref (gtk_image_get_pixbuf (image));
    case GTK_IMAGE_ICON_NAME:
      gtk_image_get_icon_name (image, &icon_name, &size);
      icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (image)));
      gtk_icon_size_lookup (size, &width, NULL);
      return gtk_icon_theme_load_icon (icon_theme,
                                       icon_name,
                                       width,
                                       GTK_ICON_LOOKUP_GENERIC_FALLBACK,
                                       NULL);
    default:
      g_warning ("Image storage type %d not handled",
                 gtk_image_get_storage_type (image));
      return NULL;
    }
}

static void
drag_begin (GtkWidget      *widget,
            GdkDragContext *context,
            gpointer        data)
{
  GdkPixbuf *pixbuf;

  pixbuf = get_image_pixbuf (GTK_IMAGE (data));
  gtk_drag_set_icon_pixbuf (context, pixbuf, -2, -2);
  g_object_unref (pixbuf);
}

void
drag_data_get (GtkWidget        *widget,
               GdkDragContext   *context,
               GtkSelectionData *selection_data,
               guint             info,
               guint             time,
               gpointer          data)
{
  GdkPixbuf *pixbuf;

  pixbuf = get_image_pixbuf (GTK_IMAGE (data));
  gtk_selection_data_set_pixbuf (selection_data, pixbuf);
  g_object_unref (pixbuf);
}

static void
drag_data_received (GtkWidget        *widget,
                    GdkDragContext   *context,
                    gint              x,
                    gint              y,
                    GtkSelectionData *selection_data,
                    guint             info,
                    guint32           time,
                    gpointer          data)
{
  GdkPixbuf *pixbuf;

  if (gtk_selection_data_get_length (selection_data) > 0)
    {
      pixbuf = gtk_selection_data_get_pixbuf (selection_data);
      gtk_image_set_from_pixbuf (GTK_IMAGE (data), pixbuf);
      g_object_unref (pixbuf);
    }
}

static void
copy_image (GtkMenuItem *item,
            gpointer     data)
{
  GtkClipboard *clipboard;
  GdkPixbuf *pixbuf;

  clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
  pixbuf = get_image_pixbuf (GTK_IMAGE (data));

  gtk_clipboard_set_image (clipboard, pixbuf);
  g_object_unref (pixbuf);
}

static void
paste_image (GtkMenuItem *item,
             gpointer     data)
{
  GtkClipboard *clipboard;
  GdkPixbuf *pixbuf;

  clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
  pixbuf = gtk_clipboard_wait_for_image (clipboard);

  if (pixbuf)
    {
      gtk_image_set_from_pixbuf (GTK_IMAGE (data), pixbuf);
      g_object_unref (pixbuf);
    }
}

static gboolean
button_press (GtkWidget      *widget,
              GdkEventButton *button,
              gpointer        data)
{
  GtkWidget *menu;
  GtkWidget *item;

  if (button->button != GDK_BUTTON_SECONDARY)
    return FALSE;

  menu = gtk_menu_new ();

  item = gtk_menu_item_new_with_mnemonic (_("_Copy"));
  g_signal_connect (item, "activate", G_CALLBACK (copy_image), data);
  gtk_widget_show (item);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);

  item = gtk_menu_item_new_with_mnemonic (_("_Paste"));
  g_signal_connect (item, "activate", G_CALLBACK (paste_image), data);
  gtk_widget_show (item);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);

  gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *) button);
  return TRUE;
}

GtkWidget *
do_clipboard (GtkWidget *do_widget)
{
  static GtkWidget *window = NULL;

  if (!window)
    {
      GtkWidget *vbox, *hbox;
      GtkWidget *label;
      GtkWidget *entry, *button;
      GtkWidget *ebox, *image;
      GtkClipboard *clipboard;

      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
      gtk_window_set_screen (GTK_WINDOW (window),
                             gtk_widget_get_screen (do_widget));
      gtk_window_set_title (GTK_WINDOW (window), "Clipboard");

      g_signal_connect (window, "destroy",
                        G_CALLBACK (gtk_widget_destroyed), &window);

      vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
      gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);

      gtk_container_add (GTK_CONTAINER (window), vbox);

      label = gtk_label_new ("\"Copy\" will copy the text\nin the entry to the clipboard");

      gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);

      hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
      gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
      gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);

      /* Create the first entry */
      entry = gtk_entry_new ();
      gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);

      /* Create the button */
      button = gtk_button_new_with_mnemonic (_("_Copy"));
      gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
      g_signal_connect (button, "clicked",
                        G_CALLBACK (copy_button_clicked), entry);

      label = gtk_label_new ("\"Paste\" will paste the text from the clipboard to the entry");
      gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);

      hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
      gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
      gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);

      /* Create the second entry */
      entry = gtk_entry_new ();
      gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);

      /* Create the button */
      button = gtk_button_new_with_mnemonic (_("_Paste"));
      gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
      g_signal_connect (button, "clicked",
                        G_CALLBACK (paste_button_clicked), entry);

      label = gtk_label_new ("Images can be transferred via the clipboard, too");
      gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);

      hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
      gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
      gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);

      /* Create the first image */
      image = gtk_image_new_from_icon_name ("dialog-warning",
                                            GTK_ICON_SIZE_BUTTON);
      ebox = gtk_event_box_new ();
      gtk_container_add (GTK_CONTAINER (ebox), image);
      gtk_container_add (GTK_CONTAINER (hbox), ebox);

      /* make ebox a drag source */
      gtk_drag_source_set (ebox, GDK_BUTTON1_MASK, NULL, 0, GDK_ACTION_COPY);
      gtk_drag_source_add_image_targets (ebox);
      g_signal_connect (ebox, "drag-begin",
                        G_CALLBACK (drag_begin), image);
      g_signal_connect (ebox, "drag-data-get",
                        G_CALLBACK (drag_data_get), image);

      /* accept drops on ebox */
      gtk_drag_dest_set (ebox, GTK_DEST_DEFAULT_ALL,
                         NULL, 0, GDK_ACTION_COPY);
      gtk_drag_dest_add_image_targets (ebox);
      g_signal_connect (ebox, "drag-data-received",
                        G_CALLBACK (drag_data_received), image);

      /* context menu on ebox */
      g_signal_connect (ebox, "button-press-event",
                        G_CALLBACK (button_press), image);

      /* Create the second image */
      image = gtk_image_new_from_icon_name ("process-stop",
                                            GTK_ICON_SIZE_BUTTON);
      ebox = gtk_event_box_new ();
      gtk_container_add (GTK_CONTAINER (ebox), image);
      gtk_container_add (GTK_CONTAINER (hbox), ebox);

      /* make ebox a drag source */
      gtk_drag_source_set (ebox, GDK_BUTTON1_MASK, NULL, 0, GDK_ACTION_COPY);
      gtk_drag_source_add_image_targets (ebox);
      g_signal_connect (ebox, "drag-begin",
                        G_CALLBACK (drag_begin), image);
      g_signal_connect (ebox, "drag-data-get",
                        G_CALLBACK (drag_data_get), image);

      /* accept drops on ebox */
      gtk_drag_dest_set (ebox, GTK_DEST_DEFAULT_ALL,
                         NULL, 0, GDK_ACTION_COPY);
      gtk_drag_dest_add_image_targets (ebox);
      g_signal_connect (ebox, "drag-data-received",
                        G_CALLBACK (drag_data_received), image);

      /* context menu on ebox */
      g_signal_connect (ebox, "button-press-event",
                        G_CALLBACK (button_press), image);

      /* tell the clipboard manager to make the data persistent */
      clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
      gtk_clipboard_set_can_store (clipboard, NULL, 0);
    }

  if (!gtk_widget_get_visible (window))
    gtk_widget_show_all (window);
  else
    gtk_widget_destroy (window);

  return window;
}
