X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtktextview.c;h=2de8a1e623be9f15d7b3bf23ead0c54b9a9580cb;hb=5e2c23214564f7dcc687fa8467020eeb6b9407a9;hp=ed3d98bb361c6645acd892d300e1a98ab19e704f;hpb=320613c439c6c7eeb5bc64685522195e0a6adc4e;p=~andy%2Fgtk diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index ed3d98bb3..2de8a1e62 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -53,7 +53,8 @@ #include "gtktexthandleprivate.h" #include "gtkstylecontextprivate.h" #include "gtkcssstylepropertyprivate.h" -#include "gtkselectionwindow.h" +#include "gtkbubblewindowprivate.h" +#include "gtktoolbar.h" #include "a11y/gtktextviewaccessibleprivate.h" @@ -238,6 +239,7 @@ struct _GtkTextViewPrivate guint vscroll_policy : 1; guint cursor_handle_dragged : 1; guint selection_handle_dragged : 1; + guint populate_all : 1; }; struct _GtkTextPendingScroll @@ -292,7 +294,8 @@ enum PROP_HSCROLL_POLICY, PROP_VSCROLL_POLICY, PROP_INPUT_PURPOSE, - PROP_INPUT_HINTS + PROP_INPUT_HINTS, + PROP_POPULATE_ALL }; static void gtk_text_view_finalize (GObject *object); @@ -860,6 +863,22 @@ gtk_text_view_class_init (GtkTextViewClass *klass) GTK_INPUT_HINT_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** GtkTextView:populate-all: + * + * If ::populate-all is %TRUE, the #GtkTextView::populate-popup + * signal is also emitted for touch popups. + * + * Since: 3.8 + */ + g_object_class_install_property (gobject_class, + PROP_POPULATE_ALL, + g_param_spec_boolean ("populate-all", + P_("Populate all"), + P_("Whether to emit ::populate-popup for touch popups"), + FALSE, + GTK_PARAM_READWRITE)); + + /* GtkScrollable interface */ g_object_class_override_property (gobject_class, PROP_HADJUSTMENT, "hadjustment"); g_object_class_override_property (gobject_class, PROP_VADJUSTMENT, "vadjustment"); @@ -1122,13 +1141,22 @@ gtk_text_view_class_init (GtkTextViewClass *klass) /** * GtkTextView::populate-popup: * @text_view: The text view on which the signal is emitted - * @menu: the menu that is being populated + * @popup: the container that is being populated * - * The ::populate-popup signal gets emitted before showing the + * The ::populate-popup signal gets emitted before showing the * context menu of the text view. * * If you need to add items to the context menu, connect - * to this signal and append your menuitems to the @menu. + * to this signal and append your items to the @popup, which + * will be a #GtkMenu in this case. + * + * If #GtkEntry::populate-toolbar is %TRUE, this signal will + * also be emitted to populate touch popups. In this case, + * @popup will be a different container, e.g. a #GtkToolbar. + * + * The signal handler should not make assumptions about the + * type of @widget, but check whether @popup is a #GtkMenu + * or #GtkToolbar or another kind of container. */ signals[POPULATE_POPUP] = g_signal_new (I_("populate-popup"), @@ -1138,7 +1166,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass) NULL, NULL, _gtk_marshal_VOID__OBJECT, G_TYPE_NONE, 1, - GTK_TYPE_MENU); + GTK_TYPE_WIDGET); /** * GtkTextView::select-all: @@ -3263,6 +3291,10 @@ gtk_text_view_set_property (GObject *object, gtk_text_view_set_input_hints (text_view, g_value_get_flags (value)); break; + case PROP_POPULATE_ALL: + text_view->priv->populate_all = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3367,6 +3399,10 @@ gtk_text_view_get_property (GObject *object, g_value_set_flags (value, gtk_text_view_get_input_hints (text_view)); break; + case PROP_POPULATE_ALL: + g_value_set_boolean (value, priv->populate_all); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -8762,51 +8798,102 @@ gtk_text_view_get_selection_rect (GtkTextView *text_view, rect->height = y2 - y1; } -static gboolean -gtk_text_view_selection_bubble_popup_cb (gpointer user_data) +static void +activate_bubble_cb (GtkWidget *item, + GtkTextView *text_view) +{ + const gchar *signal = g_object_get_data (G_OBJECT (item), "gtk-signal"); + g_signal_emit_by_name (text_view, signal); + _gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (text_view->priv->selection_bubble)); +} + +static void +append_bubble_action (GtkTextView *text_view, + GtkWidget *toolbar, + const gchar *stock_id, + const gchar *signal, + gboolean sensitive) +{ + GtkToolItem *item = gtk_tool_button_new_from_stock (stock_id); + g_object_set_data (G_OBJECT (item), I_("gtk-signal"), (char *)signal); + g_signal_connect (item, "clicked", G_CALLBACK (activate_bubble_cb), text_view); + gtk_widget_set_sensitive (GTK_WIDGET (item), sensitive); + gtk_widget_show (GTK_WIDGET (item)); + gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1); +} + +static void +bubble_targets_received (GtkClipboard *clipboard, + GtkSelectionData *data, + gpointer user_data) { GtkTextView *text_view = user_data; GtkTextViewPrivate *priv = text_view->priv; cairo_rectangle_int_t rect; gboolean has_selection; + gboolean has_clipboard; + gboolean can_insert; + GtkTextIter iter; + GtkTextIter sel_start, sel_end; GdkWindow *window; + GtkWidget *toolbar; has_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view), - NULL, NULL); + &sel_start, &sel_end); if (!priv->editable && !has_selection) { priv->selection_bubble_timeout_id = 0; - return FALSE; + return; } if (priv->selection_bubble) gtk_widget_destroy (priv->selection_bubble); window = gtk_widget_get_window (GTK_WIDGET (text_view)); - priv->selection_bubble = gtk_selection_window_new (); - gtk_selection_window_set_editable (GTK_SELECTION_WINDOW (priv->selection_bubble), - priv->editable); - gtk_selection_window_set_has_selection (GTK_SELECTION_WINDOW (priv->selection_bubble), - has_selection); - - g_signal_connect_swapped (priv->selection_bubble, "cut", - G_CALLBACK (gtk_text_view_cut_clipboard), - text_view); - g_signal_connect_swapped (priv->selection_bubble, "copy", - G_CALLBACK (gtk_text_view_copy_clipboard), - text_view); - g_signal_connect_swapped (priv->selection_bubble, "paste", - G_CALLBACK (gtk_text_view_paste_clipboard), - text_view); + priv->selection_bubble = _gtk_bubble_window_new (); + toolbar = GTK_WIDGET (gtk_toolbar_new ()); + gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_TEXT); + gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE); + gtk_widget_show (toolbar); + gtk_container_add (GTK_CONTAINER (priv->selection_bubble), toolbar); + + gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, + gtk_text_buffer_get_insert (get_buffer (text_view))); + can_insert = gtk_text_iter_can_insert (&iter, priv->editable); + has_clipboard = gtk_selection_data_targets_include_text (data); + + append_bubble_action (text_view, toolbar, GTK_STOCK_CUT, "cut-clipboard", + has_selection && + range_contains_editable_text (&sel_start, &sel_end, + priv->editable)); + append_bubble_action (text_view, toolbar, GTK_STOCK_COPY, "copy-clipboard", + has_selection); + append_bubble_action (text_view, toolbar, GTK_STOCK_PASTE, "paste-clipboard", + can_insert && has_clipboard); + + if (priv->populate_all) + g_signal_emit (text_view, signals[POPULATE_POPUP], 0, toolbar); gtk_text_view_get_selection_rect (text_view, &rect); rect.x -= priv->xoffset; rect.y -= priv->yoffset; - gtk_bubble_window_popup (GTK_BUBBLE_WINDOW (priv->selection_bubble), + _gtk_bubble_window_popup (GTK_BUBBLE_WINDOW (priv->selection_bubble), window, &rect, GTK_POS_TOP); priv->selection_bubble_timeout_id = 0; - return FALSE; +} + +static gboolean +gtk_text_view_selection_bubble_popup_cb (gpointer user_data) +{ + GtkTextView *text_view = user_data; + gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view), + GDK_SELECTION_CLIPBOARD), + gdk_atom_intern_static_string ("TARGETS"), + bubble_targets_received, + text_view); + + return G_SOURCE_REMOVE; } static void @@ -8817,7 +8904,7 @@ gtk_text_view_selection_bubble_popup_unset (GtkTextView *text_view) priv = text_view->priv; if (priv->selection_bubble) - gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble)); + _gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble)); if (priv->selection_bubble_timeout_id) { @@ -8837,8 +8924,8 @@ gtk_text_view_selection_bubble_popup_set (GtkTextView *text_view) g_source_remove (priv->selection_bubble_timeout_id); priv->selection_bubble_timeout_id = - gdk_threads_add_timeout_seconds (1, gtk_text_view_selection_bubble_popup_cb, - text_view); + gdk_threads_add_timeout (1000, gtk_text_view_selection_bubble_popup_cb, + text_view); } /* Child GdkWindows */ @@ -9009,8 +9096,13 @@ text_window_scroll (GtkTextWindow *win, gint dx, gint dy) { + GtkTextView *view = GTK_TEXT_VIEW (win->widget); + GtkTextViewPrivate *priv = view->priv; + if (dx != 0 || dy != 0) { + if (priv->selection_bubble) + _gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble)); gdk_window_scroll (win->bin_window, dx, dy); } }