Log Message
[GTK] Need WebKitContextMenuItemType to open emoji picker https://bugs.webkit.org/show_bug.cgi?id=176760
Reviewed by Michael Catanzaro. Source/WebCore: Add a new context menu item to insert an emoji. * loader/EmptyClients.cpp: Empty implementation of ContextMenuClient::insertEmoji(). * page/ContextMenuClient.h: Add insertEmoji for GTK port. * page/ContextMenuController.cpp: (WebCore::ContextMenuController::contextMenuItemSelected): Handle insert emoji action. (WebCore::ContextMenuController::populate): Add insert emoji item after select all. (WebCore::ContextMenuController::checkOrEnableIfNeeded const): Handle insert emoji action. * platform/ContextMenuItem.h: Add insert emoji action. * platform/LocalizedStrings.h: * platform/gtk/LocalizedStringsGtk.cpp: (WebCore::contextMenuItemTagInsertEmoji): Source/WebCore/platform/gtk/po: * POTFILES.in: Add WebKitEmojiChooser.cpp. Source/WebKit: Add a default implementation to show the emoji chooser when requested by the application, either using the context menu or keyboard shortcuts. GtkEmojiChooser is private in GTK, so we include our own copy, adapted to the WebKit coding style. The emoji chooser is always shown by default when using GTK >= 3.24 for any editable content. I'm going to add public API in a follow up patch to be able to use your own chooser, or even prevent the default chooser from being shown, similar to what we do for other UI elements like file chooser, color chooser, print dialog, etc. * Shared/API/glib/WebKitContextMenuActions.cpp: (webkitContextMenuActionGetActionTag): Handle insert emoji action. (webkitContextMenuActionGetForContextMenuItem): Ditto. (webkitContextMenuActionGetLabel): Ditto. * SourcesGTK.txt: * UIProcess/API/gtk/WebKitContextMenuActions.h: * UIProcess/API/gtk/WebKitEmojiChooser.cpp: Added. (webkitEmojiChooserAddEmoji): (webkitEmojiChooserAddRecentItem): (emojiActivated): (emojiDataHasVariations): (webkitEmojiChooserShowVariations): (emojiLongPressed): (emojiPressed): (emojiPopupMenu): (verticalAdjustmentChanged): (webkitEmojiChooserSetupSectionBox): (scrollToSection): (webkitEmojiChooserSetupSectionButton): (webkitEmojiChooserSetupRecent): (webkitEmojiChooserEnsureEmptyResult): (webkitEmojiChooserSearchChanged): (webkitEmojiChooserSetupFilters): (webkitEmojiChooserInitializeEmojiMaxWidth): (webkitEmojiChooserConstructed): (webkitEmojiChooserShow): (webkit_emoji_chooser_class_init): (webkitEmojiChooserNew): * UIProcess/API/gtk/WebKitEmojiChooser.h: Added. * UIProcess/API/gtk/WebKitWebViewBase.cpp: (_WebKitWebViewBasePrivate::_WebKitWebViewBasePrivate): Add a timer to release the emoji chooser if not used after 2 minutes. (_WebKitWebViewBasePrivate::releaseEmojiChooserTimerFired): Destroy the emoji chooser. (emojiChooserEmojiPicked): Complete the operation using the given emoji text. (emojiChooserClosed): Complete the operation if needed using an empty string. (webkitWebViewBaseShowEmojiChooser): Create the emoji chooser if needed and show it. * UIProcess/API/gtk/WebKitWebViewBasePrivate.h: * UIProcess/WebPageProxy.h: Add showEmojiPicker(). * UIProcess/WebPageProxy.messages.in: Add ShowEmojiPicker message. * UIProcess/gtk/KeyBindingTranslator.cpp: (WebKit::insertEmojiCallback): Add GtkInsertEmoji command. (WebKit::KeyBindingTranslator::KeyBindingTranslator): Connect to insert-emoji signal. * UIProcess/gtk/WebPageProxyGtk.cpp: (WebKit::WebPageProxy::showEmojiPicker): Call webkitWebViewBaseShowEmojiChooser(). * WebProcess/WebCoreSupport/WebContextMenuClient.h: Override insertEmoji() for GTK port. * WebProcess/WebCoreSupport/WebEditorClient.h: Add insertEmoji() for GTK port. * WebProcess/WebCoreSupport/gtk/WebContextMenuClientGtk.cpp: (WebKit::WebContextMenuClient::insertEmoji): Call WebPage::showEmojiPicker(). * WebProcess/WebCoreSupport/gtk/WebEditorClientGtk.cpp: (WebKit::WebEditorClient::handleGtkEditorCommand): Call WebPage::showEmojiPicker() if command is GtkInsertEmoji. (WebKit::WebEditorClient::executePendingEditorCommands): Handle Gtk specific commands. (WebKit::WebEditorClient::handleKeyboardEvent): Use a reference instead of a pointer for Frame. * WebProcess/WebPage/WebPage.h: * WebProcess/WebPage/gtk/WebPageGtk.cpp: (WebKit::WebPage::showEmojiPicker): Send ShowEmojiPicker message to the UI process. Tools: Update context menu test to check insert emoji action is included in default context menu for editable content. * TestWebKitAPI/Tests/WebKitGtk/TestContextMenu.cpp:
Modified Paths
- trunk/Source/WebCore/ChangeLog
- trunk/Source/WebCore/loader/EmptyClients.cpp
- trunk/Source/WebCore/page/ContextMenuClient.h
- trunk/Source/WebCore/page/ContextMenuController.cpp
- trunk/Source/WebCore/platform/ContextMenuItem.h
- trunk/Source/WebCore/platform/LocalizedStrings.h
- trunk/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp
- trunk/Source/WebCore/platform/gtk/po/ChangeLog
- trunk/Source/WebCore/platform/gtk/po/POTFILES.in
- trunk/Source/WebKit/ChangeLog
- trunk/Source/WebKit/Shared/API/glib/WebKitContextMenuActions.cpp
- trunk/Source/WebKit/SourcesGTK.txt
- trunk/Source/WebKit/UIProcess/API/gtk/WebKitContextMenuActions.h
- trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp
- trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h
- trunk/Source/WebKit/UIProcess/WebPageProxy.h
- trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in
- trunk/Source/WebKit/UIProcess/gtk/KeyBindingTranslator.cpp
- trunk/Source/WebKit/UIProcess/gtk/WebPageProxyGtk.cpp
- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebContextMenuClient.h
- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.h
- trunk/Source/WebKit/WebProcess/WebCoreSupport/gtk/WebContextMenuClientGtk.cpp
- trunk/Source/WebKit/WebProcess/WebCoreSupport/gtk/WebEditorClientGtk.cpp
- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h
- trunk/Source/WebKit/WebProcess/WebPage/gtk/WebPageGtk.cpp
- trunk/Tools/ChangeLog
- trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestContextMenu.cpp
Added Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (245459 => 245460)
--- trunk/Source/WebCore/ChangeLog 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebCore/ChangeLog 2019-05-17 12:39:30 UTC (rev 245460)
@@ -1,3 +1,23 @@
+2019-05-16 Carlos Garcia Campos <[email protected]>
+
+ [GTK] Need WebKitContextMenuItemType to open emoji picker
+ https://bugs.webkit.org/show_bug.cgi?id=176760
+
+ Reviewed by Michael Catanzaro.
+
+ Add a new context menu item to insert an emoji.
+
+ * loader/EmptyClients.cpp: Empty implementation of ContextMenuClient::insertEmoji().
+ * page/ContextMenuClient.h: Add insertEmoji for GTK port.
+ * page/ContextMenuController.cpp:
+ (WebCore::ContextMenuController::contextMenuItemSelected): Handle insert emoji action.
+ (WebCore::ContextMenuController::populate): Add insert emoji item after select all.
+ (WebCore::ContextMenuController::checkOrEnableIfNeeded const): Handle insert emoji action.
+ * platform/ContextMenuItem.h: Add insert emoji action.
+ * platform/LocalizedStrings.h:
+ * platform/gtk/LocalizedStringsGtk.cpp:
+ (WebCore::contextMenuItemTagInsertEmoji):
+
2019-05-16 Greg Doolittle <[email protected]>
AX: Unship some ARIA string reflectors that are to-be-replaced by element reflection
Modified: trunk/Source/WebCore/loader/EmptyClients.cpp (245459 => 245460)
--- trunk/Source/WebCore/loader/EmptyClients.cpp 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebCore/loader/EmptyClients.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -109,6 +109,10 @@
void searchWithSpotlight() final { }
#endif
+#if PLATFORM(GTK)
+ void insertEmoji(Frame&) final { }
+#endif
+
#if USE(ACCESSIBILITY_CONTEXT_MENUS)
void showContextMenu() final { }
#endif
Modified: trunk/Source/WebCore/page/ContextMenuClient.h (245459 => 245460)
--- trunk/Source/WebCore/page/ContextMenuClient.h 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebCore/page/ContextMenuClient.h 2019-05-17 12:39:30 UTC (rev 245460)
@@ -49,6 +49,10 @@
virtual void searchWithSpotlight() = 0;
#endif
+#if PLATFORM(GTK)
+ virtual void insertEmoji(Frame&) = 0;
+#endif
+
#if USE(ACCESSIBILITY_CONTEXT_MENUS)
virtual void showContextMenu() = 0;
#endif
Modified: trunk/Source/WebCore/page/ContextMenuController.cpp (245459 => 245460)
--- trunk/Source/WebCore/page/ContextMenuController.cpp 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebCore/page/ContextMenuController.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -357,11 +357,12 @@
case ContextMenuItemTagUnicodeInsertZWNJMark:
insertUnicodeCharacter(zeroWidthNonJoiner, *frame);
break;
-#endif
-#if PLATFORM(GTK)
case ContextMenuItemTagSelectAll:
frame->editor().command("SelectAll").execute();
break;
+ case ContextMenuItemTagInsertEmoji:
+ m_client.insertEmoji(*frame);
+ break;
#endif
case ContextMenuItemTagSpellingGuess: {
VisibleSelection selection = frame->selection().selection();
@@ -811,9 +812,8 @@
ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste());
#if PLATFORM(GTK)
ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete());
-#endif
-#if PLATFORM(GTK)
ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll());
+ ContextMenuItem InsertEmojiItem(ActionType, ContextMenuItemTagInsertEmoji, contextMenuItemTagInsertEmoji());
#endif
#if PLATFORM(GTK) || PLATFORM(WIN)
@@ -1049,9 +1049,8 @@
#if PLATFORM(GTK)
appendItem(DeleteItem, m_contextMenu.get());
appendItem(*separatorItem(), m_contextMenu.get());
-#endif
-#if PLATFORM(GTK)
appendItem(SelectAllItem, m_contextMenu.get());
+ appendItem(InsertEmojiItem, m_contextMenu.get());
#endif
if (!inPasswordField) {
@@ -1206,6 +1205,10 @@
case ContextMenuItemTagDelete:
shouldEnable = frame->editor().canDelete();
break;
+ case ContextMenuItemTagInsertEmoji:
+ shouldEnable = frame->editor().canEdit();
+ break;
+ case ContextMenuItemTagSelectAll:
case ContextMenuItemTagInputMethods:
case ContextMenuItemTagUnicode:
case ContextMenuItemTagUnicodeInsertLRMMark:
@@ -1221,11 +1224,6 @@
shouldEnable = true;
break;
#endif
-#if PLATFORM(GTK)
- case ContextMenuItemTagSelectAll:
- shouldEnable = true;
- break;
-#endif
case ContextMenuItemTagUnderline: {
shouldCheck = frame->editor().selectionHasStyle(CSSPropertyWebkitTextDecorationsInEffect, "underline") != FalseTriState;
shouldEnable = frame->editor().canEditRichly();
Modified: trunk/Source/WebCore/platform/ContextMenuItem.h (245459 => 245460)
--- trunk/Source/WebCore/platform/ContextMenuItem.h 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebCore/platform/ContextMenuItem.h 2019-05-17 12:39:30 UTC (rev 245460)
@@ -68,6 +68,7 @@
ContextMenuItemTagUnicodeInsertZWSMark,
ContextMenuItemTagUnicodeInsertZWJMark,
ContextMenuItemTagUnicodeInsertZWNJMark,
+ ContextMenuItemTagInsertEmoji,
#endif
ContextMenuItemTagSpellingGuess,
ContextMenuItemTagNoGuessesFound,
Modified: trunk/Source/WebCore/platform/LocalizedStrings.h (245459 => 245460)
--- trunk/Source/WebCore/platform/LocalizedStrings.h 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebCore/platform/LocalizedStrings.h 2019-05-17 12:39:30 UTC (rev 245460)
@@ -83,9 +83,8 @@
String contextMenuItemTagUnicodeInsertZWSMark();
String contextMenuItemTagUnicodeInsertZWJMark();
String contextMenuItemTagUnicodeInsertZWNJMark();
-#endif
-#if PLATFORM(GTK)
String contextMenuItemTagSelectAll();
+ String contextMenuItemTagInsertEmoji();
#endif
String contextMenuItemTagNoGuessesFound();
String contextMenuItemTagIgnoreSpelling();
Modified: trunk/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp (245459 => 245460)
--- trunk/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -98,6 +98,11 @@
return String::fromUTF8(_("Select _All"));
}
+String contextMenuItemTagInsertEmoji()
+{
+ return String::fromUTF8(_("Insert _Emoji"));
+}
+
String contextMenuItemTagUnicode()
{
return String::fromUTF8(_("_Insert Unicode Control Character"));
Modified: trunk/Source/WebCore/platform/gtk/po/ChangeLog (245459 => 245460)
--- trunk/Source/WebCore/platform/gtk/po/ChangeLog 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebCore/platform/gtk/po/ChangeLog 2019-05-17 12:39:30 UTC (rev 245460)
@@ -1,3 +1,12 @@
+2019-05-16 Carlos Garcia Campos <[email protected]>
+
+ [GTK] Need WebKitContextMenuItemType to open emoji picker
+ https://bugs.webkit.org/show_bug.cgi?id=176760
+
+ Reviewed by Michael Catanzaro.
+
+ * POTFILES.in: Add WebKitEmojiChooser.cpp.
+
2019-04-30 Álvaro Torralba <[email protected]>
Update Spanish Translation
Modified: trunk/Source/WebCore/platform/gtk/po/POTFILES.in (245459 => 245460)
--- trunk/Source/WebCore/platform/gtk/po/POTFILES.in 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebCore/platform/gtk/po/POTFILES.in 2019-05-17 12:39:30 UTC (rev 245460)
@@ -31,6 +31,7 @@
../../../WebKit/UIProcess/API/glib/WebKitWindowProperties.cpp
../../../WebKit/UIProcess/API/gtk/WebKitAuthenticationDialog.cpp
../../../WebKit/UIProcess/API/gtk/WebKitColorChooserRequest.cpp
+../../../WebKit/UIProcess/API/gtk/WebKitEmojiChooser.cpp
../../../WebKit/UIProcess/API/gtk/WebKitPrintCustomWidget.cpp
../../../WebKit/UIProcess/API/gtk/WebKitPrintOperation.cpp
../../../WebKit/UIProcess/API/gtk/WebKitScriptDialogImpl.cpp
Modified: trunk/Source/WebKit/ChangeLog (245459 => 245460)
--- trunk/Source/WebKit/ChangeLog 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/ChangeLog 2019-05-17 12:39:30 UTC (rev 245460)
@@ -1,3 +1,73 @@
+2019-05-16 Carlos Garcia Campos <[email protected]>
+
+ [GTK] Need WebKitContextMenuItemType to open emoji picker
+ https://bugs.webkit.org/show_bug.cgi?id=176760
+
+ Reviewed by Michael Catanzaro.
+
+ Add a default implementation to show the emoji chooser when requested by the application, either using the
+ context menu or keyboard shortcuts. GtkEmojiChooser is private in GTK, so we include our own copy, adapted to
+ the WebKit coding style. The emoji chooser is always shown by default when using GTK >= 3.24 for any editable
+ content. I'm going to add public API in a follow up patch to be able to use your own chooser, or even prevent
+ the default chooser from being shown, similar to what we do for other UI elements like file chooser, color
+ chooser, print dialog, etc.
+
+ * Shared/API/glib/WebKitContextMenuActions.cpp:
+ (webkitContextMenuActionGetActionTag): Handle insert emoji action.
+ (webkitContextMenuActionGetForContextMenuItem): Ditto.
+ (webkitContextMenuActionGetLabel): Ditto.
+ * SourcesGTK.txt:
+ * UIProcess/API/gtk/WebKitContextMenuActions.h:
+ * UIProcess/API/gtk/WebKitEmojiChooser.cpp: Added.
+ (webkitEmojiChooserAddEmoji):
+ (webkitEmojiChooserAddRecentItem):
+ (emojiActivated):
+ (emojiDataHasVariations):
+ (webkitEmojiChooserShowVariations):
+ (emojiLongPressed):
+ (emojiPressed):
+ (emojiPopupMenu):
+ (verticalAdjustmentChanged):
+ (webkitEmojiChooserSetupSectionBox):
+ (scrollToSection):
+ (webkitEmojiChooserSetupSectionButton):
+ (webkitEmojiChooserSetupRecent):
+ (webkitEmojiChooserEnsureEmptyResult):
+ (webkitEmojiChooserSearchChanged):
+ (webkitEmojiChooserSetupFilters):
+ (webkitEmojiChooserInitializeEmojiMaxWidth):
+ (webkitEmojiChooserConstructed):
+ (webkitEmojiChooserShow):
+ (webkit_emoji_chooser_class_init):
+ (webkitEmojiChooserNew):
+ * UIProcess/API/gtk/WebKitEmojiChooser.h: Added.
+ * UIProcess/API/gtk/WebKitWebViewBase.cpp:
+ (_WebKitWebViewBasePrivate::_WebKitWebViewBasePrivate): Add a timer to release the emoji chooser if not used
+ after 2 minutes.
+ (_WebKitWebViewBasePrivate::releaseEmojiChooserTimerFired): Destroy the emoji chooser.
+ (emojiChooserEmojiPicked): Complete the operation using the given emoji text.
+ (emojiChooserClosed): Complete the operation if needed using an empty string.
+ (webkitWebViewBaseShowEmojiChooser): Create the emoji chooser if needed and show it.
+ * UIProcess/API/gtk/WebKitWebViewBasePrivate.h:
+ * UIProcess/WebPageProxy.h: Add showEmojiPicker().
+ * UIProcess/WebPageProxy.messages.in: Add ShowEmojiPicker message.
+ * UIProcess/gtk/KeyBindingTranslator.cpp:
+ (WebKit::insertEmojiCallback): Add GtkInsertEmoji command.
+ (WebKit::KeyBindingTranslator::KeyBindingTranslator): Connect to insert-emoji signal.
+ * UIProcess/gtk/WebPageProxyGtk.cpp:
+ (WebKit::WebPageProxy::showEmojiPicker): Call webkitWebViewBaseShowEmojiChooser().
+ * WebProcess/WebCoreSupport/WebContextMenuClient.h: Override insertEmoji() for GTK port.
+ * WebProcess/WebCoreSupport/WebEditorClient.h: Add insertEmoji() for GTK port.
+ * WebProcess/WebCoreSupport/gtk/WebContextMenuClientGtk.cpp:
+ (WebKit::WebContextMenuClient::insertEmoji): Call WebPage::showEmojiPicker().
+ * WebProcess/WebCoreSupport/gtk/WebEditorClientGtk.cpp:
+ (WebKit::WebEditorClient::handleGtkEditorCommand): Call WebPage::showEmojiPicker() if command is GtkInsertEmoji.
+ (WebKit::WebEditorClient::executePendingEditorCommands): Handle Gtk specific commands.
+ (WebKit::WebEditorClient::handleKeyboardEvent): Use a reference instead of a pointer for Frame.
+ * WebProcess/WebPage/WebPage.h:
+ * WebProcess/WebPage/gtk/WebPageGtk.cpp:
+ (WebKit::WebPage::showEmojiPicker): Send ShowEmojiPicker message to the UI process.
+
2019-05-16 John Wilander <[email protected]>
Storage Access API: Call completion handlers in NetworkConnectionToWebProcess::hasStorageAccess() and NetworkConnectionToWebProcess::requestStorageAccess() when feature is off
Modified: trunk/Source/WebKit/Shared/API/glib/WebKitContextMenuActions.cpp (245459 => 245460)
--- trunk/Source/WebKit/Shared/API/glib/WebKitContextMenuActions.cpp 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/Shared/API/glib/WebKitContextMenuActions.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -83,6 +83,8 @@
return ContextMenuItemTagDelete;
case WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL:
return ContextMenuItemTagSelectAll;
+ case WEBKIT_CONTEXT_MENU_ACTION_INSERT_EMOJI:
+ return ContextMenuItemTagInsertEmoji;
case WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS:
return ContextMenuItemTagInputMethods;
case WEBKIT_CONTEXT_MENU_ACTION_UNICODE:
@@ -183,6 +185,8 @@
return WEBKIT_CONTEXT_MENU_ACTION_DELETE;
case ContextMenuItemTagSelectAll:
return WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL;
+ case ContextMenuItemTagInsertEmoji:
+ return WEBKIT_CONTEXT_MENU_ACTION_INSERT_EMOJI;
case ContextMenuItemTagInputMethods:
return WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS;
case ContextMenuItemTagUnicode:
@@ -281,6 +285,8 @@
return contextMenuItemTagDelete();
case WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL:
return contextMenuItemTagSelectAll();
+ case WEBKIT_CONTEXT_MENU_ACTION_INSERT_EMOJI:
+ return contextMenuItemTagInsertEmoji();
case WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS:
return contextMenuItemTagInputMethods();
case WEBKIT_CONTEXT_MENU_ACTION_UNICODE:
Modified: trunk/Source/WebKit/SourcesGTK.txt (245459 => 245460)
--- trunk/Source/WebKit/SourcesGTK.txt 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/SourcesGTK.txt 2019-05-17 12:39:30 UTC (rev 245460)
@@ -189,6 +189,7 @@
UIProcess/API/gtk/WebKitAuthenticationDialog.cpp @no-unify
UIProcess/API/gtk/WebKitColorChooser.cpp @no-unify
UIProcess/API/gtk/WebKitColorChooserRequest.cpp @no-unify
+UIProcess/API/gtk/WebKitEmojiChooser.cpp @no-unify
UIProcess/API/gtk/WebKitOptionMenu.cpp @no-unify
UIProcess/API/gtk/WebKitOptionMenuItem.cpp @no-unify
UIProcess/API/gtk/WebKitPopupMenu.cpp @no-unify
Modified: trunk/Source/WebKit/UIProcess/API/gtk/WebKitContextMenuActions.h (245459 => 245460)
--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitContextMenuActions.h 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitContextMenuActions.h 2019-05-17 12:39:30 UTC (rev 245460)
@@ -74,6 +74,7 @@
* @WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE: Mute current media element.
* @WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_VIDEO_TO_DISK: Download video to disk. Since 2.2
* @WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_AUDIO_TO_DISK: Download audio to disk. Since 2.2
+ * @WEBKIT_CONTEXT_MENU_ACTION_INSERT_EMOJI: Insert an emoji. Since 2.26
* @WEBKIT_CONTEXT_MENU_ACTION_CUSTOM: Custom action defined by applications.
*
* Enum values used to denote the stock actions for
@@ -125,6 +126,7 @@
WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE,
WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_VIDEO_TO_DISK,
WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_AUDIO_TO_DISK,
+ WEBKIT_CONTEXT_MENU_ACTION_INSERT_EMOJI,
WEBKIT_CONTEXT_MENU_ACTION_CUSTOM = 10000
} WebKitContextMenuAction;
Added: trunk/Source/WebKit/UIProcess/API/gtk/WebKitEmojiChooser.cpp (0 => 245460)
--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitEmojiChooser.cpp (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitEmojiChooser.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2019 Igalia S.L.
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// GtkEmojiChooser is private in GTK 3, so this is based in the GTK code, just adapted to
+// WebKit coding style, using some internal types from WTF to simplify the implementation
+// and not using GtkBuilder for the UI.
+
+#include "config.h"
+#include "WebKitEmojiChooser.h"
+
+#if GTK_CHECK_VERSION(3, 24, 0)
+
+#include <glib/gi18n-lib.h>
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
+#include <wtf/glib/WTFGType.h>
+#include <wtf/text/CString.h>
+
+enum {
+ EMOJI_PICKED,
+
+ LAST_SIGNAL
+};
+
+struct EmojiSection {
+ GtkWidget* heading { nullptr };
+ GtkWidget* box { nullptr };
+ GtkWidget* button { nullptr };
+ bool isEmpty { false };
+};
+
+using SectionList = Vector<EmojiSection, 9>;
+
+struct _WebKitEmojiChooserPrivate {
+ GtkWidget* stack;
+ GtkWidget* swindow;
+ GtkWidget* searchEntry;
+ SectionList sections;
+ GRefPtr<GSettings> settings;
+ HashSet<GRefPtr<GtkGesture>> gestures;
+ int emojiMaxWidth;
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+WEBKIT_DEFINE_TYPE(WebKitEmojiChooser, webkit_emoji_chooser, GTK_TYPE_POPOVER)
+
+static void emojiPopupMenu(GtkWidget*, WebKitEmojiChooser*);
+
+static const unsigned boxSpace = 6;
+
+static void emojiHovered(GtkWidget* widget, GdkEvent* event)
+{
+ if (event->type == GDK_ENTER_NOTIFY)
+ gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT, FALSE);
+ else
+ gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT);
+}
+
+static GtkWidget* webkitEmojiChooserAddEmoji(WebKitEmojiChooser* chooser, GtkFlowBox* parent, GVariant* item, bool prepend = false, gunichar modifier = 0)
+{
+ char text[64];
+ char* textPtr = text;
+ GRefPtr<GVariant> codes = adoptGRef(g_variant_get_child_value(item, 0));
+ for (unsigned i = 0; i < g_variant_n_children(codes.get()); ++i) {
+ gunichar code;
+ g_variant_get_child(codes.get(), i, "u", &code);
+ if (!code)
+ code = modifier;
+ if (code)
+ textPtr += g_unichar_to_utf8(code, textPtr);
+ }
+ // U+FE0F is the Emoji variation selector
+ textPtr += g_unichar_to_utf8(0xFE0F, textPtr);
+ textPtr[0] = '\0';
+
+ GtkWidget* label = gtk_label_new(text);
+ PangoAttrList* attributes = pango_attr_list_new();
+ pango_attr_list_insert(attributes, pango_attr_scale_new(PANGO_SCALE_X_LARGE));
+ gtk_label_set_attributes(GTK_LABEL(label), attributes);
+ pango_attr_list_unref(attributes);
+
+ PangoLayout* layout = gtk_label_get_layout(GTK_LABEL(label));
+ PangoRectangle rect;
+ pango_layout_get_extents(layout, &rect, nullptr);
+ // Check for fallback rendering that generates too wide items.
+ if (pango_layout_get_unknown_glyphs_count(layout) || rect.width >= 1.5 * chooser->priv->emojiMaxWidth) {
+ gtk_widget_destroy(label);
+ return nullptr;
+ }
+
+ GtkWidget* child = gtk_flow_box_child_new();
+ gtk_style_context_add_class(gtk_widget_get_style_context(child), "emoji");
+ g_object_set_data_full(G_OBJECT(child), "emoji-data", g_variant_ref(item), reinterpret_cast<GDestroyNotify>(g_variant_unref));
+ if (modifier)
+ g_object_set_data(G_OBJECT(child), "modifier", GUINT_TO_POINTER(modifier));
+
+ GtkWidget* eventBox = gtk_event_box_new();
+ gtk_widget_add_events(eventBox, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+ g_signal_connect(eventBox, "enter-notify-event", G_CALLBACK(emojiHovered), nullptr);
+ g_signal_connect(eventBox, "leave-notify-event", G_CALLBACK(emojiHovered), nullptr);
+ gtk_container_add(GTK_CONTAINER(eventBox), label);
+ gtk_widget_show(label);
+
+ gtk_container_add(GTK_CONTAINER(child), eventBox);
+ gtk_widget_show(eventBox);
+
+ gtk_flow_box_insert(parent, child, prepend ? 0 : -1);
+ gtk_widget_show(child);
+
+ return child;
+}
+
+static void webkitEmojiChooserAddRecentItem(WebKitEmojiChooser* chooser, GVariant* item, gunichar modifier)
+{
+ GRefPtr<GVariant> protectItem(item);
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a((auss)u)"));
+ g_variant_builder_add(&builder, "(@(auss)u)", item, modifier);
+
+ auto& section = chooser->priv->sections.first();
+
+ static const unsigned maxRecentItems = 7 * 3;
+
+ GUniquePtr<GList> children(gtk_container_get_children(GTK_CONTAINER(section.box)));
+ unsigned i = 1;
+ for (auto* l = children.get(); l; l = g_list_next(l), ++i) {
+ auto* item2 = static_cast<GVariant*>(g_object_get_data(G_OBJECT(l->data), "emoji-data"));
+ auto modifier2 = static_cast<gunichar>(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(l->data), "modifier")));
+ if (modifier == modifier2 && g_variant_equal(item, item2)) {
+ gtk_widget_destroy(GTK_WIDGET(l->data));
+ --i;
+ continue;
+ }
+
+ if (i >= maxRecentItems) {
+ gtk_widget_destroy(GTK_WIDGET(l->data));
+ continue;
+ }
+
+ g_variant_builder_add(&builder, "(@(auss)u)", item2, modifier2);
+ }
+
+ auto* child = webkitEmojiChooserAddEmoji(chooser, GTK_FLOW_BOX(section.box), item, true, modifier);
+ if (child)
+ g_signal_connect(child, "popup-menu", G_CALLBACK(emojiPopupMenu), chooser);
+
+ gtk_widget_show(section.box);
+ gtk_widget_set_sensitive(section.button, TRUE);
+
+ g_settings_set_value(chooser->priv->settings.get(), "recent-emoji", g_variant_builder_end(&builder));
+}
+
+static void emojiActivated(GtkFlowBox* box, GtkFlowBoxChild* child, WebKitEmojiChooser* chooser)
+{
+ GtkWidget* label = gtk_bin_get_child(GTK_BIN(gtk_bin_get_child(GTK_BIN(child))));
+ GUniquePtr<char> text(g_strdup(gtk_label_get_label(GTK_LABEL(label))));
+
+ auto* item = static_cast<GVariant*>(g_object_get_data(G_OBJECT(child), "emoji-data"));
+ auto modifier = static_cast<gunichar>(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(child), "modifier")));
+ webkitEmojiChooserAddRecentItem(chooser, item, modifier);
+ g_signal_emit(chooser, signals[EMOJI_PICKED], 0, text.get());
+
+ gtk_popover_popdown(GTK_POPOVER(chooser));
+}
+
+static bool emojiDataHasVariations(GVariant* emojiData)
+{
+ GRefPtr<GVariant> codes = adoptGRef(g_variant_get_child_value(emojiData, 0));
+ for (size_t i = 0; i < g_variant_n_children(codes.get()); ++i) {
+ gunichar code;
+ g_variant_get_child(codes.get(), i, "u", &code);
+ if (!code)
+ return true;
+ }
+ return false;
+}
+
+static void webkitEmojiChooserShowVariations(WebKitEmojiChooser* chooser, GtkWidget* child)
+{
+ if (!child)
+ return;
+
+ auto* emojiData = static_cast<GVariant*>(g_object_get_data(G_OBJECT(child), "emoji-data"));
+ if (!emojiData)
+ return;
+
+ if (!emojiDataHasVariations(emojiData))
+ return;
+
+ GtkWidget* popover = gtk_popover_new(child);
+ GtkWidget* view = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_style_context_add_class(gtk_widget_get_style_context(view), "view");
+ GtkWidget* box = gtk_flow_box_new();
+ g_signal_connect(box, "child-activated", G_CALLBACK(emojiActivated), chooser);
+ gtk_flow_box_set_homogeneous(GTK_FLOW_BOX(box), TRUE);
+ gtk_flow_box_set_min_children_per_line(GTK_FLOW_BOX(box), 6);
+ gtk_flow_box_set_max_children_per_line(GTK_FLOW_BOX(box), 6);
+ gtk_flow_box_set_activate_on_single_click(GTK_FLOW_BOX(box), TRUE);
+ gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(box), GTK_SELECTION_NONE);
+ gtk_container_add(GTK_CONTAINER(view), box);
+ gtk_widget_show(box);
+ gtk_container_add(GTK_CONTAINER(popover), view);
+ gtk_widget_show(view);
+
+ webkitEmojiChooserAddEmoji(chooser, GTK_FLOW_BOX(box), emojiData);
+ for (gunichar modifier = 0x1F3FB; modifier <= 0x1F3FF; ++modifier)
+ webkitEmojiChooserAddEmoji(chooser, GTK_FLOW_BOX(box), emojiData, modifier);
+
+ gtk_popover_popup(GTK_POPOVER(popover));
+}
+
+static void emojiLongPressed(GtkGesture* gesture, double x, double y, WebKitEmojiChooser* chooser)
+{
+ auto* box = GTK_FLOW_BOX(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)));
+ webkitEmojiChooserShowVariations(chooser, GTK_WIDGET(gtk_flow_box_get_child_at_pos(box, x, y)));
+}
+
+static void emojiPressed(GtkGesture* gesture, int, double x, double y, WebKitEmojiChooser* chooser)
+{
+ emojiLongPressed(gesture, x, y, chooser);
+}
+
+static void emojiPopupMenu(GtkWidget* child, WebKitEmojiChooser* chooser)
+{
+ webkitEmojiChooserShowVariations(chooser, child);
+}
+
+static void verticalAdjustmentChanged(GtkAdjustment* adjustment, WebKitEmojiChooser* chooser)
+{
+ double value = gtk_adjustment_get_value(adjustment);
+ EmojiSection* sectionToSelect = nullptr;
+ for (auto& section : chooser->priv->sections) {
+ GtkAllocation allocation;
+ if (section.heading)
+ gtk_widget_get_allocation(section.heading, &allocation);
+ else
+ gtk_widget_get_allocation(section.box, &allocation);
+
+ if (value < allocation.y - boxSpace)
+ break;
+
+ sectionToSelect = §ion;
+ }
+
+ if (!sectionToSelect)
+ sectionToSelect = &chooser->priv->sections[0];
+
+ for (auto& section : chooser->priv->sections) {
+ if (§ion == sectionToSelect)
+ gtk_widget_set_state_flags(section.button, GTK_STATE_FLAG_CHECKED, FALSE);
+ else
+ gtk_widget_unset_state_flags(section.button, GTK_STATE_FLAG_CHECKED);
+ }
+}
+
+static GtkWidget* webkitEmojiChooserSetupSectionBox(WebKitEmojiChooser* chooser, GtkBox* parent, const char* title, GtkAdjustment* adjustment, gboolean canHaveVariations = FALSE)
+{
+ EmojiSection section;
+ if (title) {
+ GtkWidget* label = gtk_label_new(title);
+ section.heading = label;
+ gtk_label_set_xalign(GTK_LABEL(label), 0);
+ gtk_box_pack_start(parent, label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+ }
+
+ GtkWidget* box = gtk_flow_box_new();
+ section.box = box;
+ g_signal_connect(box, "child-activated", G_CALLBACK(emojiActivated), chooser);
+ gtk_flow_box_set_homogeneous(GTK_FLOW_BOX(box), TRUE);
+ gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(box), GTK_SELECTION_NONE);
+ gtk_container_set_focus_vadjustment(GTK_CONTAINER(box), adjustment);
+ gtk_box_pack_start(parent, box, FALSE, FALSE, 0);
+ gtk_widget_show(box);
+
+ if (canHaveVariations) {
+ GRefPtr<GtkGesture> gesture = adoptGRef(gtk_gesture_long_press_new(box));
+ g_signal_connect(gesture.get(), "pressed", G_CALLBACK(emojiLongPressed), chooser);
+ chooser->priv->gestures.add(WTFMove(gesture));
+ GRefPtr<GtkGesture> multiGesture = adoptGRef(gtk_gesture_multi_press_new(box));
+ gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(multiGesture.get()), GDK_BUTTON_SECONDARY);
+ g_signal_connect(multiGesture.get(), "pressed", G_CALLBACK(emojiPressed), chooser);
+ chooser->priv->gestures.add(WTFMove(multiGesture));
+ }
+
+ chooser->priv->sections.append(WTFMove(section));
+ return box;
+}
+
+static void scrollToSection(GtkButton* button, gpointer data)
+{
+ auto* chooser = WEBKIT_EMOJI_CHOOSER(gtk_widget_get_ancestor(GTK_WIDGET(button), WEBKIT_TYPE_EMOJI_CHOOSER));
+ auto& section = chooser->priv->sections[GPOINTER_TO_UINT(data)];
+ GtkAdjustment* adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(chooser->priv->swindow));
+ if (section.heading) {
+ GtkAllocation allocation = { 0, 0, 0, 0 };
+ gtk_widget_get_allocation(section.heading, &allocation);
+ gtk_adjustment_set_value(adjustment, allocation.y - boxSpace);
+ } else
+ gtk_adjustment_set_value(adjustment, 0);
+}
+
+static void webkitEmojiChooserSetupSectionButton(WebKitEmojiChooser* chooser, GtkBox* parent, const char* iconName, const char* tooltip)
+{
+ GtkWidget* button = gtk_button_new_from_icon_name(iconName, GTK_ICON_SIZE_BUTTON);
+ chooser->priv->sections.last().button = button;
+ gtk_style_context_add_class(gtk_widget_get_style_context(button), "emoji-section");
+ gtk_widget_set_tooltip_text(button, tooltip);
+ g_signal_connect(button, "clicked", G_CALLBACK(scrollToSection), GUINT_TO_POINTER(chooser->priv->sections.size() - 1));
+ gtk_box_pack_start(parent, button, FALSE, FALSE, 0);
+ gtk_widget_show(button);
+}
+
+static void webkitEmojiChooserSetupRecent(WebKitEmojiChooser* chooser, GtkBox* emojiBox, GtkBox* buttonBox, GtkAdjustment* adjustment)
+{
+ GtkWidget* flowBox = webkitEmojiChooserSetupSectionBox(chooser, emojiBox, nullptr, adjustment, true);
+ webkitEmojiChooserSetupSectionButton(chooser, buttonBox, "emoji-recent-symbolic", _("Recent"));
+
+ bool isEmpty = true;
+ GRefPtr<GVariant> variant = adoptGRef(g_settings_get_value(chooser->priv->settings.get(), "recent-emoji"));
+ GVariantIter iter;
+ g_variant_iter_init(&iter, variant.get());
+ while (GRefPtr<GVariant> item = adoptGRef(g_variant_iter_next_value(&iter))) {
+ GRefPtr<GVariant> emojiData = adoptGRef(g_variant_get_child_value(item.get(), 0));
+ gunichar modifier;
+ g_variant_get_child(item.get(), 1, "u", &modifier);
+ if (auto* child = webkitEmojiChooserAddEmoji(chooser, GTK_FLOW_BOX(flowBox), emojiData.get(), true, modifier))
+ g_signal_connect(child, "popup-menu", G_CALLBACK(emojiPopupMenu), chooser);
+ isEmpty = false;
+ }
+
+ if (isEmpty) {
+ gtk_widget_hide(flowBox);
+ gtk_widget_set_sensitive(chooser->priv->sections.first().button, FALSE);
+ }
+}
+
+static void webkitEmojiChooserEnsureEmptyResult(WebKitEmojiChooser* chooser)
+{
+ if (gtk_stack_get_child_by_name(GTK_STACK(chooser->priv->stack), "empty"))
+ return;
+
+ GtkWidget* grid = gtk_grid_new();
+ gtk_grid_set_row_spacing(GTK_GRID(grid), 12);
+ gtk_widget_set_halign(grid, GTK_ALIGN_CENTER);
+ gtk_widget_set_valign(grid, GTK_ALIGN_CENTER);
+ gtk_style_context_add_class(gtk_widget_get_style_context(grid), "dim-label");
+
+ GtkWidget* image = gtk_image_new_from_icon_name("edit-find-symbolic", GTK_ICON_SIZE_DIALOG);
+ gtk_image_set_pixel_size(GTK_IMAGE(image), 72);
+ gtk_style_context_add_class(gtk_widget_get_style_context(image), "dim-label");
+ gtk_grid_attach(GTK_GRID(grid), image, 0, 0, 1, 1);
+ gtk_widget_show(image);
+
+ GtkWidget* label = gtk_label_new(_("No Results Found"));
+ PangoAttrList* attributes = pango_attr_list_new();
+ pango_attr_list_insert(attributes, pango_attr_scale_new(1.44));
+ pango_attr_list_insert(attributes, pango_attr_weight_new(PANGO_WEIGHT_BOLD));
+ gtk_label_set_attributes(GTK_LABEL(label), attributes);
+ pango_attr_list_unref(attributes);
+ gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1);
+ gtk_widget_show(label);
+
+ label = gtk_label_new(_("Try a different search"));
+ gtk_style_context_add_class(gtk_widget_get_style_context(label), "dim-label");
+ gtk_grid_attach(GTK_GRID(grid), label, 0, 2, 1, 1);
+ gtk_widget_show(label);
+
+ gtk_stack_add_named(GTK_STACK(chooser->priv->stack), grid, "empty");
+ gtk_widget_show(grid);
+}
+
+static void webkitEmojiChooserSearchChanged(WebKitEmojiChooser* chooser)
+{
+ for (auto& section : chooser->priv->sections) {
+ section.isEmpty = true;
+ gtk_flow_box_invalidate_filter(GTK_FLOW_BOX(section.box));
+ }
+
+ bool resultsFound = false;
+ for (auto& section : chooser->priv->sections) {
+ if (section.heading) {
+ gtk_widget_set_visible(section.heading, !section.isEmpty);
+ gtk_widget_set_visible(section.box, !section.isEmpty);
+ }
+ resultsFound = resultsFound || !section.isEmpty;
+ }
+
+ if (!resultsFound) {
+ webkitEmojiChooserEnsureEmptyResult(chooser);
+ gtk_stack_set_visible_child_name(GTK_STACK(chooser->priv->stack), "empty");
+ } else
+ gtk_stack_set_visible_child_name(GTK_STACK(chooser->priv->stack), "list");
+}
+
+static void webkitEmojiChooserSetupFilters(WebKitEmojiChooser* chooser)
+{
+ for (size_t i = 0; i < chooser->priv->sections.size(); ++i) {
+ gtk_flow_box_set_filter_func(GTK_FLOW_BOX(chooser->priv->sections[i].box), [](GtkFlowBoxChild* child, gpointer userData) -> gboolean {
+ auto* chooser = WEBKIT_EMOJI_CHOOSER(gtk_widget_get_ancestor(GTK_WIDGET(child), WEBKIT_TYPE_EMOJI_CHOOSER));
+ auto& section = chooser->priv->sections[GPOINTER_TO_UINT(userData)];
+ const char* text = gtk_entry_get_text(GTK_ENTRY(chooser->priv->searchEntry));
+ if (!text || !*text) {
+ section.isEmpty = false;
+ return TRUE;
+ }
+
+ auto* emojiData = static_cast<GVariant*>(g_object_get_data(G_OBJECT(child), "emoji-data"));
+ if (!emojiData) {
+ section.isEmpty = false;
+ return TRUE;
+ }
+
+ const char* name;
+ g_variant_get_child(emojiData, 1, "&s", &name);
+ if (g_str_match_string(text, name, TRUE)) {
+ section.isEmpty = false;
+ return TRUE;
+ }
+
+ return FALSE;
+ }, GUINT_TO_POINTER(i), nullptr);
+ }
+}
+
+static void webkitEmojiChooserInitializeEmojiMaxWidth(WebKitEmojiChooser* chooser)
+{
+ // Get a reasonable maximum width for an emoji. We do this to skip overly wide fallback
+ // rendering for certain emojis the font does not contain and therefore end up being
+ // rendered as multiple glyphs.
+ GRefPtr<PangoLayout> layout = adoptGRef(gtk_widget_create_pango_layout(GTK_WIDGET(chooser), "🙂"));
+ auto* attributes = pango_attr_list_new();
+ pango_attr_list_insert(attributes, pango_attr_scale_new(PANGO_SCALE_X_LARGE));
+ pango_layout_set_attributes(layout.get(), attributes);
+ pango_attr_list_unref(attributes);
+
+ PangoRectangle rect;
+ pango_layout_get_extents(layout.get(), &rect, nullptr);
+ chooser->priv->emojiMaxWidth = rect.width;
+}
+
+static void webkitEmojiChooserConstructed(GObject* object)
+{
+ WebKitEmojiChooser* chooser = WEBKIT_EMOJI_CHOOSER(object);
+ chooser->priv->settings = adoptGRef(g_settings_new("org.gtk.Settings.EmojiChooser"));
+
+ G_OBJECT_CLASS(webkit_emoji_chooser_parent_class)->constructed(object);
+
+ webkitEmojiChooserInitializeEmojiMaxWidth(chooser);
+
+ gtk_style_context_add_class(gtk_widget_get_style_context(GTK_WIDGET(object)), "emoji-picker");
+
+ GtkWidget* mainBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ GtkWidget* searchEntry = gtk_search_entry_new();
+ chooser->priv->searchEntry = searchEntry;
+ g_signal_connect_swapped(searchEntry, "search-changed", G_CALLBACK(webkitEmojiChooserSearchChanged), chooser);
+ gtk_entry_set_input_hints(GTK_ENTRY(searchEntry), GTK_INPUT_HINT_NO_EMOJI);
+ gtk_box_pack_start(GTK_BOX(mainBox), searchEntry, TRUE, FALSE, 0);
+ gtk_widget_show(searchEntry);
+
+ GtkWidget* stack = gtk_stack_new();
+ chooser->priv->stack = stack;
+ GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ GtkWidget* swindow = gtk_scrolled_window_new(nullptr, nullptr);
+ chooser->priv->swindow = swindow;
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(swindow), 250);
+ gtk_style_context_add_class(gtk_widget_get_style_context(swindow), "view");
+ gtk_box_pack_start(GTK_BOX(box), swindow, TRUE, TRUE, 0);
+ gtk_widget_show(swindow);
+
+ GtkWidget* emojiBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
+ g_object_set(emojiBox, "margin", 6, nullptr);
+ gtk_container_add(GTK_CONTAINER(swindow), emojiBox);
+ gtk_widget_show(emojiBox);
+
+ GtkWidget* buttonBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_pack_start(GTK_BOX(box), buttonBox, TRUE, FALSE, 0);
+ gtk_widget_show(buttonBox);
+
+ GtkAdjustment* vAdjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(swindow));
+ g_signal_connect(vAdjustment, "value-changed", G_CALLBACK(verticalAdjustmentChanged), chooser);
+
+ webkitEmojiChooserSetupRecent(chooser, GTK_BOX(emojiBox), GTK_BOX(buttonBox), vAdjustment);
+
+ GRefPtr<GBytes> bytes = adoptGRef(g_resources_lookup_data("/org/gtk/libgtk/emoji/emoji.data", G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr));
+ GRefPtr<GVariant> data = "" bytes.get(), TRUE);
+ GVariantIter iter;
+ g_variant_iter_init(&iter, data.get());
+ GtkWidget* flowBox = nullptr;
+ while (GRefPtr<GVariant> item = adoptGRef(g_variant_iter_next_value(&iter))) {
+ const char* name;
+ g_variant_get_child(item.get(), 1, "&s", &name);
+
+ if (!g_strcmp0(name, "grinning face")) {
+ const char* title = _("Smileys & People");
+ flowBox = webkitEmojiChooserSetupSectionBox(chooser, GTK_BOX(emojiBox), title, vAdjustment, true);
+ webkitEmojiChooserSetupSectionButton(chooser, GTK_BOX(buttonBox), "emoji-people-symbolic", title);
+ } else if (!g_strcmp0(name, "selfie")) {
+ const char* title = _("Body & Clothing");
+ flowBox = webkitEmojiChooserSetupSectionBox(chooser, GTK_BOX(emojiBox), title, vAdjustment, true);
+ webkitEmojiChooserSetupSectionButton(chooser, GTK_BOX(buttonBox), "emoji-body-symbolic", title);
+ } else if (!g_strcmp0(name, "monkey")) {
+ const char* title = _("Animals & Nature");
+ flowBox = webkitEmojiChooserSetupSectionBox(chooser, GTK_BOX(emojiBox), title, vAdjustment);
+ webkitEmojiChooserSetupSectionButton(chooser, GTK_BOX(buttonBox), "emoji-nature-symbolic", title);
+ } else if (!g_strcmp0(name, "grapes")) {
+ const char* title = _("Food & Drink");
+ flowBox = webkitEmojiChooserSetupSectionBox(chooser, GTK_BOX(emojiBox), title, vAdjustment);
+ webkitEmojiChooserSetupSectionButton(chooser, GTK_BOX(buttonBox), "emoji-food-symbolic", title);
+ } else if (!g_strcmp0(name, "globe showing Europe-Africa")) {
+ const char* title = _("Travel & Places");
+ flowBox = webkitEmojiChooserSetupSectionBox(chooser, GTK_BOX(emojiBox), title, vAdjustment);
+ webkitEmojiChooserSetupSectionButton(chooser, GTK_BOX(buttonBox), "emoji-travel-symbolic", title);
+ } else if (!g_strcmp0(name, "jack-o-lantern")) {
+ const char* title = _("Activities");
+ flowBox = webkitEmojiChooserSetupSectionBox(chooser, GTK_BOX(emojiBox), title, vAdjustment);
+ webkitEmojiChooserSetupSectionButton(chooser, GTK_BOX(buttonBox), "emoji-activities-symbolic", title);
+ } else if (!g_strcmp0(name, "muted speaker")) {
+ const char* title = _("Objects");
+ flowBox = webkitEmojiChooserSetupSectionBox(chooser, GTK_BOX(emojiBox), title, vAdjustment);
+ webkitEmojiChooserSetupSectionButton(chooser, GTK_BOX(buttonBox), "emoji-objects-symbolic", title);
+ } else if (!g_strcmp0(name, "ATM sign")) {
+ const char* title = _("Symbols");
+ flowBox = webkitEmojiChooserSetupSectionBox(chooser, GTK_BOX(emojiBox), title, vAdjustment);
+ webkitEmojiChooserSetupSectionButton(chooser, GTK_BOX(buttonBox), "emoji-symbols-symbolic", title);
+ } else if (!g_strcmp0(name, "chequered flag")) {
+ const char* title = _("Flags");
+ flowBox = webkitEmojiChooserSetupSectionBox(chooser, GTK_BOX(emojiBox), title, vAdjustment);
+ webkitEmojiChooserSetupSectionButton(chooser, GTK_BOX(buttonBox), "emoji-flags-symbolic", title);
+ }
+ auto* child = webkitEmojiChooserAddEmoji(chooser, GTK_FLOW_BOX(flowBox), item.get());
+ if (child)
+ g_signal_connect(child, "popup-menu", G_CALLBACK(emojiPopupMenu), chooser);
+ }
+
+ gtk_widget_set_state_flags(chooser->priv->sections.first().button, GTK_STATE_FLAG_CHECKED, FALSE);
+
+ gtk_stack_add_named(GTK_STACK(stack), box, "list");
+ gtk_widget_show(box);
+
+ gtk_box_pack_start(GTK_BOX(mainBox), stack, TRUE, TRUE, 0);
+ gtk_widget_show(stack);
+
+ gtk_container_add(GTK_CONTAINER(object), mainBox);
+ gtk_widget_show(mainBox);
+
+ webkitEmojiChooserSetupFilters(chooser);
+}
+
+static void webkitEmojiChooserShow(GtkWidget* widget)
+{
+ GTK_WIDGET_CLASS(webkit_emoji_chooser_parent_class)->show(widget);
+
+ WebKitEmojiChooser* chooser = WEBKIT_EMOJI_CHOOSER(widget);
+ auto* adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(chooser->priv->swindow));
+ gtk_adjustment_set_value(adjustment, 0);
+
+ gtk_entry_set_text(GTK_ENTRY(chooser->priv->searchEntry), "");
+}
+
+static void webkit_emoji_chooser_class_init(WebKitEmojiChooserClass* klass)
+{
+ GObjectClass* objectClass = G_OBJECT_CLASS(klass);
+ objectClass->constructed = webkitEmojiChooserConstructed;
+
+ GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(klass);
+ widgetClass->show = webkitEmojiChooserShow;
+
+ signals[EMOJI_PICKED] = g_signal_new(
+ "emoji-picked",
+ G_OBJECT_CLASS_TYPE(objectClass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ nullptr, nullptr,
+ nullptr,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
+}
+
+GtkWidget* webkitEmojiChooserNew()
+{
+ WebKitEmojiChooser* authDialog = WEBKIT_EMOJI_CHOOSER(g_object_new(WEBKIT_TYPE_EMOJI_CHOOSER, nullptr));
+ return GTK_WIDGET(authDialog);
+}
+
+#endif // GTK_CHECK_VERSION(3, 24, 0)
Added: trunk/Source/WebKit/UIProcess/API/gtk/WebKitEmojiChooser.h (0 => 245460)
--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitEmojiChooser.h (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitEmojiChooser.h 2019-05-17 12:39:30 UTC (rev 245460)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#if GTK_CHECK_VERSION(3, 24, 0)
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_EMOJI_CHOOSER (webkit_emoji_chooser_get_type())
+#define WEBKIT_EMOJI_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_EMOJI_CHOOSER, WebKitEmojiChooser))
+#define WEBKIT_IS_EMOJI_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_EMOJI_CHOOSER))
+#define WEBKIT_EMOJI_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_EMOJI_CHOOSER, WebKitEmojiChooserClass))
+#define WEBKIT_IS_EMOJI_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_EMOJI_CHOOSER))
+#define WEBKIT_EMOJI_CHOOSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_EMOJI_CHOOSER, WebKitEmojiChooserClass))
+
+typedef struct _WebKitEmojiChooser WebKitEmojiChooser;
+typedef struct _WebKitEmojiChooserClass WebKitEmojiChooserClass;
+typedef struct _WebKitEmojiChooserPrivate WebKitEmojiChooserPrivate;
+
+struct _WebKitEmojiChooser {
+ GtkPopover parent;
+
+ WebKitEmojiChooserPrivate* priv;
+};
+
+struct _WebKitEmojiChooserClass {
+ GtkPopoverClass parentClass;
+};
+
+GType webkit_emoji_chooser_get_type();
+GtkWidget* webkitEmojiChooserNew();
+
+G_END_DECLS
+
+#endif // GTK_CHECK_VERSION(3, 24, 0)
Modified: trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp (245459 => 245460)
--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -42,6 +42,7 @@
#include "WebEventFactory.h"
#include "WebInspectorProxy.h"
#include "WebKit2Initialize.h"
+#include "WebKitEmojiChooser.h"
#include "WebKitWebViewBaseAccessible.h"
#include "WebKitWebViewBasePrivate.h"
#include "WebPageGroup.h"
@@ -67,6 +68,7 @@
#include <wtf/Compiler.h>
#include <wtf/HashMap.h>
#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/RunLoopSourcePriority.h>
#include <wtf/glib/WTFGType.h>
#include <wtf/text/CString.h>
@@ -147,7 +149,13 @@
struct _WebKitWebViewBasePrivate {
_WebKitWebViewBasePrivate()
: updateActivityStateTimer(RunLoop::main(), this, &_WebKitWebViewBasePrivate::updateActivityStateTimerFired)
+#if GTK_CHECK_VERSION(3, 24, 0)
+ , releaseEmojiChooserTimer(RunLoop::main(), this, &_WebKitWebViewBasePrivate::releaseEmojiChooserTimerFired)
+#endif
{
+#if GTK_CHECK_VERSION(3, 24, 0)
+ releaseEmojiChooserTimer.setPriority(RunLoopSourcePriority::ReleaseUnusedResourcesTimer);
+#endif
}
void updateActivityStateTimerFired()
@@ -158,6 +166,16 @@
activityStateFlagsToUpdate = { };
}
+#if GTK_CHECK_VERSION(3, 24, 0)
+ void releaseEmojiChooserTimerFired()
+ {
+ if (emojiChooser) {
+ gtk_widget_destroy(emojiChooser);
+ emojiChooser = nullptr;
+ }
+ }
+#endif
+
WebKitWebViewChildrenMap children;
std::unique_ptr<PageClientImpl> pageClient;
RefPtr<WebPageProxy> pageProxy;
@@ -207,6 +225,12 @@
#endif
std::unique_ptr<ViewGestureController> viewGestureController;
bool isBackForwardNavigationGestureEnabled { false };
+
+#if GTK_CHECK_VERSION(3, 24, 0)
+ GtkWidget* emojiChooser;
+ CompletionHandler<void(String)> emojiChooserCompletionHandler;
+ RunLoop::Timer<WebKitWebViewBasePrivate> releaseEmojiChooserTimer;
+#endif
};
WEBKIT_DEFINE_TYPE(WebKitWebViewBase, webkit_web_view_base, GTK_TYPE_CONTAINER)
@@ -525,10 +549,21 @@
gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webView));
}
+#if GTK_CHECK_VERSION(3, 24, 0)
+static void webkitWebViewBaseCompleteEmojiChooserRequest(WebKitWebViewBase* webView, const String& text)
+{
+ if (auto completionHandler = std::exchange(webView->priv->emojiChooserCompletionHandler, nullptr))
+ completionHandler(text);
+}
+#endif
+
static void webkitWebViewBaseDispose(GObject* gobject)
{
WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(gobject);
webkitWebViewBaseSetToplevelOnScreenWindow(webView, nullptr);
+#if GTK_CHECK_VERSION(3, 24, 0)
+ webkitWebViewBaseCompleteEmojiChooserRequest(webView, emptyString());
+#endif
webView->priv->pageProxy->close();
webView->priv->acceleratedBackingStore = nullptr;
webView->priv->sleepDisabler = nullptr;
@@ -1754,3 +1789,41 @@
if (controller && controller->isSwipeGestureEnabled())
webkitWebViewBase->priv->viewGestureController->didRestoreScrollPosition();
}
+
+#if GTK_CHECK_VERSION(3, 24, 0)
+static void emojiChooserEmojiPicked(WebKitWebViewBase* webkitWebViewBase, const char* text)
+{
+ webkitWebViewBaseCompleteEmojiChooserRequest(webkitWebViewBase, String::fromUTF8(text));
+}
+
+static void emojiChooserClosed(WebKitWebViewBase* webkitWebViewBase)
+{
+ webkitWebViewBaseCompleteEmojiChooserRequest(webkitWebViewBase, emptyString());
+ webkitWebViewBase->priv->releaseEmojiChooserTimer.startOneShot(2_min);
+}
+#endif
+
+void webkitWebViewBaseShowEmojiChooser(WebKitWebViewBase* webkitWebViewBase, const IntRect& caretRect, CompletionHandler<void(String)>&& completionHandler)
+{
+#if GTK_CHECK_VERSION(3, 24, 0)
+ WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
+ priv->releaseEmojiChooserTimer.stop();
+
+ if (!priv->emojiChooser) {
+ priv->emojiChooser = webkitEmojiChooserNew();
+ g_signal_connect_swapped(priv->emojiChooser, "emoji-picked", G_CALLBACK(emojiChooserEmojiPicked), webkitWebViewBase);
+ g_signal_connect_swapped(priv->emojiChooser, "closed", G_CALLBACK(emojiChooserClosed), webkitWebViewBase);
+ gtk_popover_set_relative_to(GTK_POPOVER(priv->emojiChooser), GTK_WIDGET(webkitWebViewBase));
+ }
+
+ priv->emojiChooserCompletionHandler = WTFMove(completionHandler);
+
+ GdkRectangle gdkCaretRect = caretRect;
+ gtk_popover_set_pointing_to(GTK_POPOVER(priv->emojiChooser), &gdkCaretRect);
+ gtk_popover_popup(GTK_POPOVER(priv->emojiChooser));
+#else
+ UNUSED_PARAM(webkitWebViewBase);
+ UNUSED_PARAM(caretRect);
+ completionHandler(emptyString());
+#endif
+}
Modified: trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h (245459 => 245460)
--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h 2019-05-17 12:39:30 UTC (rev 245460)
@@ -93,3 +93,5 @@
void webkitWebViewBaseDidFailLoadForMainFrame(WebKitWebViewBase*);
void webkitWebViewBaseDidSameDocumentNavigationForMainFrame(WebKitWebViewBase*, WebKit::SameDocumentNavigationType);
void webkitWebViewBaseDidRestoreScrollPosition(WebKitWebViewBase*);
+
+void webkitWebViewBaseShowEmojiChooser(WebKitWebViewBase*, const WebCore::IntRect&, CompletionHandler<void(String)>&&);
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (245459 => 245460)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.h 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h 2019-05-17 12:39:30 UTC (rev 245460)
@@ -1774,6 +1774,7 @@
#if PLATFORM(GTK)
void getEditorCommandsForKeyEvent(const AtomicString&, Vector<String>&);
void bindAccessibilityTree(const String&);
+ void showEmojiPicker(const WebCore::IntRect&, CompletionHandler<void(String)>&&);
#endif
// Popup Menu.
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in (245459 => 245460)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in 2019-05-17 12:39:30 UTC (rev 245460)
@@ -563,4 +563,8 @@
#endif
ConfigureLoggingChannel(String channelName, enum:uint8_t WTFLogChannelState state, enum:uint8_t WTFLogLevel level)
+
+#if PLATFORM(GTK)
+ ShowEmojiPicker(WebCore::IntRect caretRect) -> (String result) Async
+#endif
}
Modified: trunk/Source/WebKit/UIProcess/gtk/KeyBindingTranslator.cpp (245459 => 245460)
--- trunk/Source/WebKit/UIProcess/gtk/KeyBindingTranslator.cpp 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/UIProcess/gtk/KeyBindingTranslator.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -60,6 +60,14 @@
translator->addPendingEditorCommand("OverWrite");
}
+#if GTK_CHECK_VERSION(3, 24, 0)
+static void insertEmojiCallback(GtkWidget* widget, KeyBindingTranslator* translator)
+{
+ g_signal_stop_emission_by_name(widget, "insert-emoji");
+ translator->addPendingEditorCommand("GtkInsertEmoji");
+}
+#endif
+
// GTK+ will still send these signals to the web view. So we can safely stop signal
// emission without breaking accessibility.
static void popupMenuCallback(GtkWidget* widget, KeyBindingTranslator*)
@@ -173,6 +181,9 @@
g_signal_connect(m_nativeWidget.get(), "toggle-overwrite", G_CALLBACK(toggleOverwriteCallback), this);
g_signal_connect(m_nativeWidget.get(), "popup-menu", G_CALLBACK(popupMenuCallback), this);
g_signal_connect(m_nativeWidget.get(), "show-help", G_CALLBACK(showHelpCallback), this);
+#if GTK_CHECK_VERSION(3, 24, 0)
+ g_signal_connect(m_nativeWidget.get(), "insert-emoji", G_CALLBACK(insertEmojiCallback), this);
+#endif
}
struct KeyCombinationEntry {
Modified: trunk/Source/WebKit/UIProcess/gtk/WebPageProxyGtk.cpp (245459 => 245460)
--- trunk/Source/WebKit/UIProcess/gtk/WebPageProxyGtk.cpp 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/UIProcess/gtk/WebPageProxyGtk.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -163,4 +163,9 @@
return webkitWebViewBaseMakeGLContextCurrent(WEBKIT_WEB_VIEW_BASE(viewWidget()));
}
+void WebPageProxy::showEmojiPicker(const WebCore::IntRect& caretRect, CompletionHandler<void(String)>&& completionHandler)
+{
+ webkitWebViewBaseShowEmojiChooser(WEBKIT_WEB_VIEW_BASE(viewWidget()), caretRect, WTFMove(completionHandler));
+}
+
} // namespace WebKit
Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebContextMenuClient.h (245459 => 245460)
--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebContextMenuClient.h 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebContextMenuClient.h 2019-05-17 12:39:30 UTC (rev 245460)
@@ -55,6 +55,10 @@
void searchWithSpotlight() override;
#endif
+#if PLATFORM(GTK)
+ void insertEmoji(WebCore::Frame&) override;
+#endif
+
#if USE(ACCESSIBILITY_CONTEXT_MENUS)
void showContextMenu() override;
#endif
Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.h (245459 => 245460)
--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.h 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.h 2019-05-17 12:39:30 UTC (rev 245460)
@@ -140,7 +140,8 @@
#endif
#if PLATFORM(GTK)
- bool executePendingEditorCommands(WebCore::Frame*, const Vector<WTF::String>&, bool);
+ bool executePendingEditorCommands(WebCore::Frame&, const Vector<WTF::String>&, bool);
+ bool handleGtkEditorCommand(WebCore::Frame&, const String& command, bool);
void getEditorCommandsForKeyEvent(const WebCore::KeyboardEvent*, Vector<WTF::String>&);
void updateGlobalSelection(WebCore::Frame*);
#endif
Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/gtk/WebContextMenuClientGtk.cpp (245459 => 245460)
--- trunk/Source/WebKit/WebProcess/WebCoreSupport/gtk/WebContextMenuClientGtk.cpp 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/gtk/WebContextMenuClientGtk.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -29,6 +29,7 @@
#if ENABLE(CONTEXT_MENUS)
+#include "WebPage.h"
#include <WebCore/NotImplemented.h>
namespace WebKit {
@@ -55,5 +56,10 @@
notImplemented();
}
+void WebContextMenuClient::insertEmoji(Frame& frame)
+{
+ m_page->showEmojiPicker(frame);
+}
+
} // namespace WebKit
#endif // ENABLE(CONTEXT_MENUS)
Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/gtk/WebEditorClientGtk.cpp (245459 => 245460)
--- trunk/Source/WebKit/WebProcess/WebCoreSupport/gtk/WebEditorClientGtk.cpp 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/gtk/WebEditorClientGtk.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -28,25 +28,48 @@
#include <WebCore/Pasteboard.h>
#include <WebCore/PlatformKeyboardEvent.h>
#include <WebCore/markup.h>
+#include <wtf/Variant.h>
#include <wtf/glib/GRefPtr.h>
namespace WebKit {
using namespace WebCore;
-bool WebEditorClient::executePendingEditorCommands(Frame* frame, const Vector<WTF::String>& pendingEditorCommands, bool allowTextInsertion)
+bool WebEditorClient::handleGtkEditorCommand(Frame& frame, const String& command, bool allowTextInsertion)
{
- Vector<Editor::Command> commands;
- for (auto& commandString : pendingEditorCommands) {
- Editor::Command command = frame->editor().command(commandString);
- if (command.isTextInsertion() && !allowTextInsertion)
+ if (command == "GtkInsertEmoji"_s) {
+ if (!allowTextInsertion)
return false;
+ m_page->showEmojiPicker(frame);
+ return true;
+ }
- commands.append(WTFMove(command));
+ return false;
+}
+
+bool WebEditorClient::executePendingEditorCommands(Frame& frame, const Vector<WTF::String>& pendingEditorCommands, bool allowTextInsertion)
+{
+ Vector<Variant<Editor::Command, String>> commands;
+ for (auto& commandString : pendingEditorCommands) {
+ if (commandString.startsWith("Gtk"))
+ commands.append(commandString);
+ else {
+ Editor::Command command = frame.editor().command(commandString);
+ if (command.isTextInsertion() && !allowTextInsertion)
+ return false;
+
+ commands.append(WTFMove(command));
+ }
}
- for (auto& command : commands) {
- if (!command.execute())
- return false;
+ for (auto& commandVariant : commands) {
+ if (WTF::holds_alternative<String>(commandVariant)) {
+ if (!handleGtkEditorCommand(frame, WTF::get<String>(commandVariant), allowTextInsertion))
+ return false;
+ } else {
+ auto& command = WTF::get<Editor::Command>(commandVariant);
+ if (!command.execute())
+ return false;
+ }
}
return true;
@@ -73,7 +96,7 @@
// the insertion until the keypress event. We want keydown to bubble up
// through the DOM first.
if (platformEvent->type() == PlatformEvent::RawKeyDown) {
- if (executePendingEditorCommands(frame, pendingEditorCommands, false))
+ if (executePendingEditorCommands(*frame, pendingEditorCommands, false))
event.setDefaultHandled();
return;
@@ -80,7 +103,7 @@
}
// Only allow text insertion commands if the current node is editable.
- if (executePendingEditorCommands(frame, pendingEditorCommands, frame->editor().canEdit())) {
+ if (executePendingEditorCommands(*frame, pendingEditorCommands, frame->editor().canEdit())) {
event.setDefaultHandled();
return;
}
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (245459 => 245460)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h 2019-05-17 12:39:30 UTC (rev 245460)
@@ -763,6 +763,7 @@
void cancelComposition();
void collapseSelectionInFrame(uint64_t frameID);
+ void showEmojiPicker(WebCore::Frame&);
#endif
#if PLATFORM (GTK) && HAVE(GTK_GESTURES)
Modified: trunk/Source/WebKit/WebProcess/WebPage/gtk/WebPageGtk.cpp (245459 => 245460)
--- trunk/Source/WebKit/WebProcess/WebPage/gtk/WebPageGtk.cpp 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Source/WebKit/WebProcess/WebPage/gtk/WebPageGtk.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -195,6 +195,15 @@
frame->coreFrame()->selection().setBase(selection.extent(), selection.affinity());
}
+void WebPage::showEmojiPicker(Frame& frame)
+{
+ CompletionHandler<void(String)> completionHandler = [frame = makeRef(frame)](String result) {
+ if (!result.isEmpty())
+ frame->editor().insertText(result, nullptr);
+ };
+ sendWithAsyncReply(Messages::WebPageProxy::ShowEmojiPicker(frame.selection().absoluteCaretBounds()), WTFMove(completionHandler));
+}
+
void WebPage::effectiveAppearanceDidChange(bool useDarkAppearance, bool useInactiveAppearance)
{
if (auto* settings = gtk_settings_get_default())
Modified: trunk/Tools/ChangeLog (245459 => 245460)
--- trunk/Tools/ChangeLog 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Tools/ChangeLog 2019-05-17 12:39:30 UTC (rev 245460)
@@ -1,3 +1,14 @@
+2019-05-16 Carlos Garcia Campos <[email protected]>
+
+ [GTK] Need WebKitContextMenuItemType to open emoji picker
+ https://bugs.webkit.org/show_bug.cgi?id=176760
+
+ Reviewed by Michael Catanzaro.
+
+ Update context menu test to check insert emoji action is included in default context menu for editable content.
+
+ * TestWebKitAPI/Tests/WebKitGtk/TestContextMenu.cpp:
+
2019-05-16 Aakash Jain <[email protected]>
[ews-build] Download archives from S3
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestContextMenu.cpp (245459 => 245460)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestContextMenu.cpp 2019-05-17 11:53:52 UTC (rev 245459)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestContextMenu.cpp 2019-05-17 12:39:30 UTC (rev 245460)
@@ -402,6 +402,7 @@
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DELETE, Visible);
iter = checkCurrentItemIsSeparatorAndGetNext(iter);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL, Visible | Enabled);
+ iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_INSERT_EMOJI, Visible | Enabled);
iter = checkCurrentItemIsSeparatorAndGetNext(iter);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_UNICODE, Visible | Enabled);
break;
_______________________________________________ webkit-changes mailing list [email protected] https://lists.webkit.org/mailman/listinfo/webkit-changes
