+static void
+psppire_data_sheet_primary_get_cb (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ guint info,
+ gpointer data)
+{
+ PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (data);
+ struct casereader *reader;
+ struct dictionary *dict;
+
+ if (psppire_data_sheet_fetch_clip (data_sheet, FALSE, &reader, &dict))
+ {
+ psppire_data_sheet_clipboard_set (selection_data, info,
+ reader, dict);
+ casereader_destroy (reader);
+ dict_destroy (dict);
+ }
+}
+
+static void
+psppire_data_sheet_update_primary_selection (PsppireDataSheet *data_sheet,
+ gboolean should_own)
+{
+ GtkClipboard *clipboard;
+ GdkDisplay *display;
+
+ display = gtk_widget_get_display (GTK_WIDGET (data_sheet));
+ clipboard = gtk_clipboard_get_for_display (display, GDK_SELECTION_PRIMARY);
+ g_return_if_fail (clipboard != NULL);
+
+ if (data_sheet->owns_primary_selection && !should_own)
+ {
+ data_sheet->owns_primary_selection = FALSE;
+ gtk_clipboard_clear (clipboard);
+ }
+ else if (should_own)
+ data_sheet->owns_primary_selection =
+ gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
+ psppire_data_sheet_primary_get_cb,
+ NULL, G_OBJECT (data_sheet));
+}
+\f
+/* A callback for when the clipboard contents have been received. */
+static void
+psppire_data_sheet_clip_received_cb (GtkClipboard *clipboard,
+ GtkSelectionData *sd,
+ gpointer data)
+{
+ PsppireDataSheet *data_sheet = data;
+ PsppireDataStore *store = data_sheet->data_store;
+ struct range_set *rows, *cols;
+ gint count = 0;
+ gint next_row, next_column;
+ gint first_column;
+ char *c;
+
+ if ( gtk_selection_data_get_length (sd) < 0 )
+ return;
+
+ if ( gtk_selection_data_get_data_type (sd) != gdk_atom_intern ("UTF8_STRING", FALSE))
+ return;
+
+ c = (char *) gtk_selection_data_get_data (sd);
+
+ /* Get the starting selected position in the data sheet. (Possibly we should
+ only paste into the selected range if it's larger than one cell?) */
+ if (!psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols))
+ return;
+ next_row = range_set_first (rows)->start;
+ first_column = next_column = range_set_first (cols)->start;
+ range_set_destroy (rows);
+ range_set_destroy (cols);
+
+ g_return_if_fail (next_row >= 0);
+ g_return_if_fail (next_column >= 0);
+
+ while (count < gtk_selection_data_get_length (sd))
+ {
+ gint row = next_row;
+ gint column = next_column;
+ struct variable *var;
+ char *s = c;
+
+ while (*c != '\t' && *c != '\n' && count < gtk_selection_data_get_length (sd))
+ {
+ c++;
+ count++;
+ }
+ if ( *c == '\t')
+ {
+ next_row = row ;
+ next_column = column + 1;
+ }
+ else if ( *c == '\n')
+ {
+ next_row = row + 1;
+ next_column = first_column;
+ }
+ *c++ = '\0';
+ count++;
+
+ var = psppire_dict_get_variable (store->dict, column);
+ if (var != NULL)
+ psppire_data_store_set_string (store, s, row, var, FALSE);
+ }
+}
+
+static void
+psppire_data_sheet_targets_received_cb (GtkClipboard *clipboard,
+ GdkAtom *atoms,
+ gint n_atoms,
+ gpointer data)
+{
+ GtkAction *action = GTK_ACTION (data);
+ gboolean compatible_target;
+ gint i;
+
+ compatible_target = FALSE;
+ for (i = 0; i < G_N_ELEMENTS (targets); i++)
+ {
+ GdkAtom target = gdk_atom_intern (targets[i].target, TRUE);
+ gint j;
+
+ for (j = 0; j < n_atoms; j++)
+ if (target == atoms[j])
+ {
+ compatible_target = TRUE;
+ break;
+ }
+ }
+
+ gtk_action_set_sensitive (action, compatible_target);
+ g_object_unref (action);
+}
+
+static void
+on_owner_change (GtkClipboard *clip, GdkEventOwnerChange *event, gpointer data)
+{
+ PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (data);
+ GtkAction *action = get_action_assert (data_sheet->builder, "edit_paste");
+
+ g_object_ref (action);
+ gtk_clipboard_request_targets (clip, psppire_data_sheet_targets_received_cb,
+ action);
+}