+ gdk_window_end_draw_frame (win, ctx);
+ cairo_region_destroy (region);
+}
+
+/* Return the horizontal position to place a widget whose
+ width is CHILD_WIDTH */
+static gint
+get_xpos (const struct psppire_output_view *view, gint child_width)
+{
+ GdkWindow *gdkw = gtk_widget_get_window (GTK_WIDGET (view->output));
+ guint w = gdk_window_get_width (gdkw);
+ int gutter = 0;
+ g_object_get (view->output, "border-width", &gutter, NULL);
+ return (gtk_widget_get_direction (GTK_WIDGET (view->output)) == GTK_TEXT_DIR_RTL) ? w - child_width - gutter: gutter;
+}
+
+static struct output_view_item *
+find_selected_item (struct psppire_output_view *view)
+{
+ struct output_view_item *item = NULL;
+ if (view == NULL)
+ return NULL;
+ if (view->items == NULL)
+ return NULL;
+
+ for (item = view->items; item < &view->items[view->n_items]; item++)
+ {
+ GtkWidget *widget = GTK_WIDGET (item->drawing_area);
+ if GTK_IS_WIDGET (widget)
+ {
+ GtkStateFlags state = gtk_widget_get_state_flags (widget);
+ if (state & GTK_STATE_FLAG_SELECTED)
+ return item;
+ }
+ }
+ return NULL;
+}
+
+
+static void
+set_copy_action (struct psppire_output_view *view,
+ gboolean state)
+{
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view->output));
+ GAction *copy_action = g_action_map_lookup_action (G_ACTION_MAP (toplevel),
+ "copy");
+ g_object_set (copy_action,
+ "enabled", state,
+ NULL);
+}
+
+static void
+clear_selection (struct psppire_output_view *view)
+{
+ if (view == NULL)
+ return;
+ struct output_view_item *item = find_selected_item (view);
+ if (item == NULL)
+ return;
+ set_copy_action (view, FALSE);
+ GtkWidget *widget = GTK_WIDGET (item->drawing_area);
+ if (GTK_IS_WIDGET (widget))
+ {
+ gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_SELECTED);
+ gtk_widget_queue_draw (widget);
+ }
+}
+
+static gboolean
+off_item_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ struct psppire_output_view *view)
+{
+ /* buttontime is set by button_press_event_cb
+ If our event->time is equal to the time from the
+ button_press_event_cb, then we handle the same event.
+ In that case we must not clear the selection because
+ it was just set by button_press_event_cb from the item */
+ if (event->time != view->buttontime)
+ clear_selection (view);
+ return FALSE; /* Forward the event -> DragNDrop */
+}
+
+static gboolean
+button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ struct psppire_output_view *view)
+{
+ view->buttontime = event->time;
+ clear_selection (view);
+ set_copy_action (view, TRUE);
+ gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
+ gtk_widget_queue_draw (widget);
+ return FALSE; /* Forward Event -> off_item will trigger */
+}
+
+static void
+drag_data_get_cb (GtkWidget *widget, GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint target_type, guint time,
+ struct psppire_output_view *view)
+{
+ view->selected_item = find_selected_item (view);
+ clipboard_get_cb (NULL, selection_data, target_type, view);
+}
+
+static void
+create_drawing_area (struct psppire_output_view *view,
+ GtkWidget *drawing_area, struct xr_rendering *r,
+ int tw, int th, const struct output_item *item)
+{
+ struct string_map options = STRING_MAP_INITIALIZER (options);
+ string_map_insert (&options, "transparent", "true");
+ string_map_insert (&options, "systemcolors", "true");
+ xr_rendering_apply_options (r, &options);
+
+ g_object_set_data_full (G_OBJECT (drawing_area),
+ "rendering", r, free_rendering);
+ g_signal_connect (drawing_area, "button-press-event",
+ G_CALLBACK (button_press_event_cb), view);
+ gtk_widget_add_events (drawing_area, GDK_BUTTON_PRESS_MASK);
+
+ { /* Drag and Drop */
+ GtkTargetList *tl = build_target_list (item);
+ g_assert (tl);
+ gtk_drag_source_set (drawing_area, GDK_BUTTON1_MASK, NULL, 0, GDK_ACTION_COPY);
+ gtk_drag_source_set_target_list (drawing_area, tl);
+ gtk_target_list_unref (tl);
+ g_signal_connect (drawing_area, "drag-data-get",
+ G_CALLBACK (drag_data_get_cb), view);
+ }
+ GtkStyleContext *context = gtk_widget_get_style_context (drawing_area);
+ gtk_style_context_add_class (context,
+ GTK_STYLE_CLASS_VIEW);
+ g_signal_connect (drawing_area, "draw",
+ G_CALLBACK (draw_callback), view);
+
+ gtk_widget_set_size_request (drawing_area, tw, th);
+ gint xpos = get_xpos (view, tw);
+
+ gtk_layout_put (view->output, drawing_area, xpos, view->y);
+
+ gtk_widget_show (drawing_area);