From 567447456ef526028dea0d54bbd7a86355fa9979 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 22 Nov 2017 16:47:43 -0500 Subject: [PATCH] text view: Support the Emoji chooser Similar to GtkEntry, add an "Insert Emoji" context menu item, and add the same keybindings. We don't add the icon here, since it is not clear where it would go. https://bugzilla.gnome.org/show_bug.cgi?id=790029 --- gtk/gtktextview.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++ gtk/gtktextview.h | 2 +- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 3f24ec459b..86644637cf 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -57,6 +57,7 @@ #include "gtkpopover.h" #include "gtktoolbar.h" #include "gtkmagnifierprivate.h" +#include "gtkemojichooser.h" #include "a11y/gtktextviewaccessibleprivate.h" @@ -325,6 +326,7 @@ enum TOGGLE_CURSOR_VISIBLE, PREEDIT_CHANGED, EXTEND_SELECTION, + INSERT_EMOJI, LAST_SIGNAL }; @@ -575,6 +577,7 @@ static void gtk_text_view_set_hadjustment_values (GtkTextView *text_view); static void gtk_text_view_set_vadjustment_values (GtkTextView *text_view); static void gtk_text_view_update_im_spot_location (GtkTextView *text_view); +static void gtk_text_view_insert_emoji (GtkTextView *text_view); /* Container methods */ static void gtk_text_view_add (GtkContainer *container, @@ -754,6 +757,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass) klass->toggle_overwrite = gtk_text_view_toggle_overwrite; klass->create_buffer = gtk_text_view_create_buffer; klass->extend_selection = gtk_text_view_extend_selection; + klass->insert_emoji = gtk_text_view_insert_emoji; /* * Properties @@ -1401,6 +1405,25 @@ gtk_text_view_class_init (GtkTextViewClass *klass) GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE, GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE); + /** + * GtkTextView::insert-emoji: + * @text_view: the object which received the signal + * + * The ::insert-emoji signal is a + * [keybinding signal][GtkBindingSignal] + * which gets emitted to present the Emoji chooser for the text_view. + * + * The default bindings for this signal are Ctrl-. and Ctrl-; + */ + signals[INSERT_EMOJI] = + g_signal_new (I_("insert-emoji"), + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkTextViewClass, insert_emoji), + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + /* * Key bindings */ @@ -1599,6 +1622,12 @@ gtk_text_view_class_init (GtkTextViewClass *klass) gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Insert, 0, "toggle-overwrite", 0); + /* Emoji */ + gtk_binding_entry_add_signal (binding_set, GDK_KEY_period, GDK_CONTROL_MASK, + "insert-emoji", 0); + gtk_binding_entry_add_signal (binding_set, GDK_KEY_semicolon, GDK_CONTROL_MASK, + "insert-emoji", 0); + /* Caret mode */ gtk_binding_entry_add_signal (binding_set, GDK_KEY_F7, 0, "toggle-cursor-visible", 0); @@ -8887,6 +8916,16 @@ popup_targets_received (GtkClipboard *clipboard, gtk_widget_show (menuitem); gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem); + if ((gtk_text_view_get_input_hints (text_view) & GTK_INPUT_HINT_NO_EMOJI) == 0) + { + menuitem = gtk_menu_item_new_with_mnemonic (_("Insert _Emoji")); + gtk_widget_set_sensitive (menuitem, can_insert); + g_signal_connect_swapped (menuitem, "activate", + G_CALLBACK (gtk_text_view_insert_emoji), text_view); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem); + } + g_signal_emit (text_view, signals[POPULATE_POPUP], 0, priv->popup_menu); @@ -10299,3 +10338,40 @@ gtk_text_view_get_monospace (GtkTextView *text_view) return gtk_style_context_has_class (context, GTK_STYLE_CLASS_MONOSPACE); } + +static void +gtk_text_view_insert_emoji (GtkTextView *text_view) +{ + GtkWidget *chooser; + GtkTextIter iter; + GdkRectangle rect; + GtkTextBuffer *buffer; + + if (gtk_widget_get_ancestor (GTK_WIDGET (text_view), GTK_TYPE_EMOJI_CHOOSER) != NULL) + return; + + chooser = GTK_WIDGET (g_object_get_data (G_OBJECT (text_view), "gtk-emoji-chooser")); + if (!chooser) + { + chooser = gtk_emoji_chooser_new (); + g_object_set_data (G_OBJECT (text_view), "gtk-emoji-chooser", chooser); + + gtk_popover_set_relative_to (GTK_POPOVER (chooser), GTK_WIDGET (text_view)); + g_signal_connect_swapped (chooser, "emoji-picked", + G_CALLBACK (gtk_text_view_insert_at_cursor), text_view); + } + + buffer = get_buffer (text_view); + gtk_text_buffer_get_iter_at_mark (buffer, &iter, + gtk_text_buffer_get_insert (buffer)); + + gtk_text_view_get_iter_location (text_view, &iter, (GdkRectangle *) &rect); + gtk_text_view_buffer_to_window_coords (text_view, GTK_TEXT_WINDOW_TEXT, + rect.x, rect.y, &rect.x, &rect.y); + _text_window_to_widget_coords (text_view, &rect.x, &rect.y); + + gtk_popover_set_pointing_to (GTK_POPOVER (chooser), &rect); + + gtk_popover_popup (GTK_POPOVER (chooser)); +} + diff --git a/gtk/gtktextview.h b/gtk/gtktextview.h index 7f536a295f..8cfe231de5 100644 --- a/gtk/gtktextview.h +++ b/gtk/gtktextview.h @@ -191,6 +191,7 @@ struct _GtkTextViewClass const GtkTextIter *location, GtkTextIter *start, GtkTextIter *end); + void (* insert_emoji) (GtkTextView *text_view); /*< private >*/ @@ -199,7 +200,6 @@ struct _GtkTextViewClass void (*_gtk_reserved2) (void); void (*_gtk_reserved3) (void); void (*_gtk_reserved4) (void); - void (*_gtk_reserved5) (void); }; GDK_AVAILABLE_IN_ALL