<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[174103] trunk/Source</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/174103">174103</a></dd>
<dt>Author</dt> <dd>carlosgc@webkit.org</dd>
<dt>Date</dt> <dd>2014-09-30 06:28:07 -0700 (Tue, 30 Sep 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[GTK] Move GtkPopupMenu implementation to WebPopupMenuProxyGtk
https://bugs.webkit.org/show_bug.cgi?id=137193

Reviewed by Gustavo Noronha Silva.

Source/WebCore:

Remove GtkPopupMenu from platform.

* PlatformGTK.cmake:
* platform/gtk/GtkPopupMenu.cpp: Removed.
* platform/gtk/GtkPopupMenu.h: Removed.

Source/WebKit2:

GtkPopupMenu was in platform only to have a common implementation to
be shared with WebKit1. Now that it's only used by
WebPopupMenuProxyGtk in WebKit2, we can simplify the code by
merging the implementation directly into WebPopupMenuProxyGtk.

* UIProcess/gtk/WebPopupMenuProxyGtk.cpp:
(WebKit::WebPopupMenuProxyGtk::WebPopupMenuProxyGtk):
(WebKit::WebPopupMenuProxyGtk::~WebPopupMenuProxyGtk):
(WebKit::WebPopupMenuProxyGtk::populatePopupMenu):
(WebKit::WebPopupMenuProxyGtk::showPopupMenu):
(WebKit::WebPopupMenuProxyGtk::hidePopupMenu):
(WebKit::WebPopupMenuProxyGtk::typeAheadFind):
(WebKit::WebPopupMenuProxyGtk::resetTypeAheadFindState):
(WebKit::WebPopupMenuProxyGtk::selectItemCallback):
(WebKit::WebPopupMenuProxyGtk::keyPressEventCallback):
* UIProcess/gtk/WebPopupMenuProxyGtk.h:
(WebKit::WebPopupMenuProxyGtk::setCurrentlySelectedMenuItem):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorePlatformGTKcmake">trunk/Source/WebCore/PlatformGTK.cmake</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessgtkWebPopupMenuProxyGtkcpp">trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp</a></li>
<li><a href="#trunkSourceWebKit2UIProcessgtkWebPopupMenuProxyGtkh">trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreplatformgtkGtkPopupMenucpp">trunk/Source/WebCore/platform/gtk/GtkPopupMenu.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgtkGtkPopupMenuh">trunk/Source/WebCore/platform/gtk/GtkPopupMenu.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (174102 => 174103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-09-30 12:50:48 UTC (rev 174102)
+++ trunk/Source/WebCore/ChangeLog        2014-09-30 13:28:07 UTC (rev 174103)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2014-09-30  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
+
+        [GTK] Move GtkPopupMenu implementation to WebPopupMenuProxyGtk
+        https://bugs.webkit.org/show_bug.cgi?id=137193
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Remove GtkPopupMenu from platform.
+
+        * PlatformGTK.cmake:
+        * platform/gtk/GtkPopupMenu.cpp: Removed.
+        * platform/gtk/GtkPopupMenu.h: Removed.
+
</ins><span class="cx"> 2014-09-30  Zan Dobersek  &lt;zdobersek@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Avoid copying the iterated-over items in range-based for-loops in RenderGrid
</span></span></pre></div>
<a id="trunkSourceWebCorePlatformGTKcmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/PlatformGTK.cmake (174102 => 174103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/PlatformGTK.cmake        2014-09-30 12:50:48 UTC (rev 174102)
+++ trunk/Source/WebCore/PlatformGTK.cmake        2014-09-30 13:28:07 UTC (rev 174103)
</span><span class="lines">@@ -225,7 +225,6 @@
</span><span class="cx">     platform/gtk/GtkClickCounter.cpp
</span><span class="cx">     platform/gtk/GtkDragAndDropHelper.cpp
</span><span class="cx">     platform/gtk/GtkInputMethodFilter.cpp
</span><del>-    platform/gtk/GtkPopupMenu.cpp
</del><span class="cx">     platform/gtk/GtkTouchContextHelper.cpp
</span><span class="cx">     platform/gtk/GtkUtilities.cpp
</span><span class="cx">     platform/gtk/GtkVersioning.c
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgtkGtkPopupMenucpp"></a>
<div class="delfile"><h4>Deleted: trunk/Source/WebCore/platform/gtk/GtkPopupMenu.cpp (174102 => 174103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/gtk/GtkPopupMenu.cpp        2014-09-30 12:50:48 UTC (rev 174102)
+++ trunk/Source/WebCore/platform/gtk/GtkPopupMenu.cpp        2014-09-30 13:28:07 UTC (rev 174103)
</span><span class="lines">@@ -1,234 +0,0 @@
</span><del>-/*
- * This file is part of the popup menu implementation for &lt;select&gt; elements in WebCore.
- *
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
- * Copyright (C) 2008 Collabora Ltd.
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (C) 2010-2011 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.
- *
- */
-
-#include &quot;config.h&quot;
-#include &quot;GtkPopupMenu.h&quot;
-
-#include &quot;GtkVersioning.h&quot;
-#include &lt;gtk/gtk.h&gt;
-#include &lt;wtf/gobject/GUniquePtr.h&gt;
-#include &lt;wtf/text/CString.h&gt;
-
-namespace WebCore {
-
-static const uint32_t gSearchTimeoutMs = 1000;
-
-GtkPopupMenu::GtkPopupMenu()
-    : m_popup(gtk_menu_new())
-    , m_previousKeyEventCharacter(0)
-    , m_currentlySelectedMenuItem(0)
-{
-    m_keyPressHandlerID = g_signal_connect(m_popup.get(), &quot;key-press-event&quot;, G_CALLBACK(GtkPopupMenu::keyPressEventCallback), this);
-}
-
-GtkPopupMenu::~GtkPopupMenu()
-{
-    g_signal_handler_disconnect(m_popup.get(), m_keyPressHandlerID);
-}
-
-void GtkPopupMenu::clear()
-{
-    gtk_container_foreach(GTK_CONTAINER(m_popup.get()), reinterpret_cast&lt;GtkCallback&gt;(menuRemoveItem), this);
-}
-
-void GtkPopupMenu::appendSeparator()
-{
-    GtkWidget* menuItem = gtk_separator_menu_item_new();
-    gtk_menu_shell_append(GTK_MENU_SHELL(m_popup.get()), menuItem);
-    gtk_widget_show(menuItem);
-}
-
-void GtkPopupMenu::appendItem(GtkAction* action)
-{
-    GtkWidget* menuItem = gtk_action_create_menu_item(action);
-    gtk_widget_set_tooltip_text(menuItem, gtk_action_get_tooltip(action));
-    g_signal_connect(menuItem, &quot;select&quot;, G_CALLBACK(GtkPopupMenu::selectItemCallback), this);
-    gtk_menu_shell_append(GTK_MENU_SHELL(m_popup.get()), menuItem);
-
-    if (gtk_action_is_visible(action))
-        gtk_widget_show(menuItem);
-}
-
-void GtkPopupMenu::popUp(const IntSize&amp; menuSize, const IntPoint&amp; menuPosition, int itemCount, int selectedItem, const GdkEvent* event)
-{
-    resetTypeAheadFindState();
-    m_menuPosition = menuPosition;
-    gtk_menu_set_active(GTK_MENU(m_popup.get()), selectedItem);
-
-    // This approach follows the one in gtkcombobox.c.
-    GtkRequisition requisition;
-    gtk_widget_set_size_request(m_popup.get(), -1, -1);
-#ifdef GTK_API_VERSION_2
-    gtk_widget_size_request(m_popup.get(), &amp;requisition);
-#else
-    gtk_widget_get_preferred_size(m_popup.get(), &amp;requisition, 0);
-#endif
-    gtk_widget_set_size_request(m_popup.get(), std::max(menuSize.width(), requisition.width), -1);
-
-    if (itemCount) {
-        GUniquePtr&lt;GList&gt; children(gtk_container_get_children(GTK_CONTAINER(m_popup.get())));
-        int i;
-        GList* child;
-        for (i = 0, child = children.get(); i &lt; itemCount; i++, child = g_list_next(child)) {
-            if (i &gt; selectedItem)
-                break;
-
-            GtkWidget* item = GTK_WIDGET(child-&gt;data);
-            GtkRequisition itemRequisition;
-#ifdef GTK_API_VERSION_2
-            gtk_widget_get_child_requisition(item, &amp;itemRequisition);
-#else
-            gtk_widget_get_preferred_size(item, &amp;itemRequisition, 0);
-#endif
-            m_menuPosition.setY(m_menuPosition.y() - itemRequisition.height);
-        }
-    } else {
-        // Center vertically the empty popup in the combo box area.
-        m_menuPosition.setY(m_menuPosition.y() - menuSize.height() / 2);
-    }
-
-    guint button = event &amp;&amp; event-&gt;type == GDK_BUTTON_PRESS ? event-&gt;button.button : 1;
-    guint32 activateTime = event ? gdk_event_get_time(event) : GDK_CURRENT_TIME;
-#ifdef GTK_API_VERSION_2
-    gtk_menu_popup(GTK_MENU(m_popup.get()), 0, 0, reinterpret_cast&lt;GtkMenuPositionFunc&gt;(menuPositionFunction), this, button, activateTime);
-#else
-    gtk_menu_popup_for_device(GTK_MENU(m_popup.get()), event ? gdk_event_get_device(event) : 0, 0, 0,
-        reinterpret_cast&lt;GtkMenuPositionFunc&gt;(menuPositionFunction), this, 0, button, activateTime);
-#endif
-
-    // Now that the menu has a position, schedule a resize to make sure it's resized to fit vertically in the work area.
-    gtk_widget_queue_resize(m_popup.get());
-}
-
-void GtkPopupMenu::popDown()
-{
-    gtk_menu_popdown(GTK_MENU(m_popup.get()));
-    resetTypeAheadFindState();
-}
-
-void GtkPopupMenu::menuRemoveItem(GtkWidget* widget, GtkPopupMenu* popupMenu)
-{
-    ASSERT(popupMenu-&gt;m_popup);
-    gtk_container_remove(GTK_CONTAINER(popupMenu-&gt;m_popup.get()), widget);
-}
-
-void GtkPopupMenu::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pushIn, GtkPopupMenu* popupMenu)
-{
-    *x = popupMenu-&gt;m_menuPosition.x();
-    *y = popupMenu-&gt;m_menuPosition.y();
-    *pushIn = true;
-}
-
-void GtkPopupMenu::resetTypeAheadFindState()
-{
-    m_currentlySelectedMenuItem = 0;
-    m_previousKeyEventCharacter = 0;
-    m_currentSearchString = &quot;&quot;;
-}
-
-bool GtkPopupMenu::typeAheadFind(GdkEventKey* event)
-{
-    // If we were given a non-printable character just skip it.
-    gunichar unicodeCharacter = gdk_keyval_to_unicode(event-&gt;keyval);
-    if (!g_unichar_isprint(unicodeCharacter)) {
-        resetTypeAheadFindState();
-        return false;
-    }
-
-    glong charactersWritten;
-    GUniquePtr&lt;gunichar2&gt; utf16String(g_ucs4_to_utf16(&amp;unicodeCharacter, 1, 0, &amp;charactersWritten, 0));
-    if (!utf16String) {
-        resetTypeAheadFindState();
-        return false;
-    }
-
-    // If the character is the same as the last character, the user is probably trying to
-    // cycle through the menulist entries. This matches the WebCore behavior for collapsed
-    // menulists.
-    bool repeatingCharacter = unicodeCharacter != m_previousKeyEventCharacter;
-    if (event-&gt;time - m_previousKeyEventTimestamp &gt; gSearchTimeoutMs)
-        m_currentSearchString = String(reinterpret_cast&lt;UChar*&gt;(utf16String.get()), charactersWritten);
-    else if (repeatingCharacter)
-        m_currentSearchString.append(String(reinterpret_cast&lt;UChar*&gt;(utf16String.get()), charactersWritten));
-
-    m_previousKeyEventTimestamp = event-&gt;time;
-    m_previousKeyEventCharacter = unicodeCharacter;
-
-    // Like the Chromium port, we case fold before searching, because 
-    // strncmp does not handle non-ASCII characters.
-    GUniquePtr&lt;gchar&gt; searchStringWithCaseFolded(g_utf8_casefold(m_currentSearchString.utf8().data(), -1));
-    size_t prefixLength = strlen(searchStringWithCaseFolded.get());
-
-    GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get()));
-    if (!children)
-        return true;
-
-    // If a menu item has already been selected, start searching from the current
-    // item down the list. This will make multiple key presses of the same character
-    // advance the selection.
-    GList* currentChild = children;
-    if (m_currentlySelectedMenuItem) {
-        currentChild = g_list_find(children, m_currentlySelectedMenuItem);
-        if (!currentChild) {
-            m_currentlySelectedMenuItem = 0;
-            currentChild = children;
-        }
-
-        // Repeating characters should iterate.
-        if (repeatingCharacter) {
-            if (GList* nextChild = g_list_next(currentChild))
-                currentChild = nextChild;
-        }
-    }
-
-    GList* firstChild = currentChild;
-    do {
-        currentChild = g_list_next(currentChild);
-        if (!currentChild)
-            currentChild = children;
-
-        GUniquePtr&lt;gchar&gt; itemText(g_utf8_casefold(gtk_menu_item_get_label(GTK_MENU_ITEM(currentChild-&gt;data)), -1));
-        if (!strncmp(searchStringWithCaseFolded.get(), itemText.get(), prefixLength)) {
-            gtk_menu_shell_select_item(GTK_MENU_SHELL(m_popup.get()), GTK_WIDGET(currentChild-&gt;data));
-            break;
-        }
-    } while (currentChild != firstChild);
-
-    g_list_free(children);
-    return true;
-}
-
-void GtkPopupMenu::selectItemCallback(GtkMenuItem* item, GtkPopupMenu* popupMenu)
-{
-    popupMenu-&gt;m_currentlySelectedMenuItem = GTK_WIDGET(item);
-}
-
-gboolean GtkPopupMenu::keyPressEventCallback(GtkWidget*, GdkEventKey* event, GtkPopupMenu* popupMenu)
-{
-    return popupMenu-&gt;typeAheadFind(event);
-}
-
-} // namespace WebCore
</del></span></pre></div>
<a id="trunkSourceWebCoreplatformgtkGtkPopupMenuh"></a>
<div class="delfile"><h4>Deleted: trunk/Source/WebCore/platform/gtk/GtkPopupMenu.h (174102 => 174103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/gtk/GtkPopupMenu.h        2014-09-30 12:50:48 UTC (rev 174102)
+++ trunk/Source/WebCore/platform/gtk/GtkPopupMenu.h        2014-09-30 13:28:07 UTC (rev 174103)
</span><span class="lines">@@ -1,78 +0,0 @@
</span><del>-/*
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (C) 2011 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.
- */
-
-#ifndef GtkPopupMenu_h
-#define GtkPopupMenu_h
-
-#include &quot;GRefPtrGtk.h&quot;
-#include &quot;IntPoint.h&quot;
-#include &quot;IntSize.h&quot;
-#include &lt;wtf/FastMalloc.h&gt;
-#include &lt;wtf/Noncopyable.h&gt;
-#include &lt;wtf/PassOwnPtr.h&gt;
-#include &lt;wtf/text/WTFString.h&gt;
-
-typedef struct _GdkEventKey GdkEventKey;
-
-namespace WebCore {
-
-class GtkPopupMenu {
-    WTF_MAKE_NONCOPYABLE(GtkPopupMenu);
-    WTF_MAKE_FAST_ALLOCATED;
-
-public:
-    static PassOwnPtr&lt;GtkPopupMenu&gt; create()
-    {
-        return adoptPtr(new GtkPopupMenu());
-    }
-
-    ~GtkPopupMenu();
-
-    GtkWidget* platformMenu() const { return m_popup.get(); }
-    void clear();
-    void appendSeparator();
-    void appendItem(GtkAction*);
-    void popUp(const IntSize&amp;, const IntPoint&amp;, int itemsCount, int selectedItem, const GdkEvent*);
-    void popDown();
-
-private:
-    GtkPopupMenu();
-
-    void resetTypeAheadFindState();
-    bool typeAheadFind(GdkEventKey*);
-
-    static void menuItemActivated(GtkMenuItem*, GtkPopupMenu*);
-    static void menuPositionFunction(GtkMenu*, gint*, gint*, gboolean*, GtkPopupMenu*);
-    static void menuRemoveItem(GtkWidget*, GtkPopupMenu*);
-    static void selectItemCallback(GtkMenuItem*, GtkPopupMenu*);
-    static gboolean keyPressEventCallback(GtkWidget*, GdkEventKey*, GtkPopupMenu*);
-
-    GRefPtr&lt;GtkWidget&gt; m_popup;
-    IntPoint m_menuPosition;
-    String m_currentSearchString;
-    uint32_t m_previousKeyEventTimestamp;
-    unsigned int m_previousKeyEventCharacter;
-    GtkWidget* m_currentlySelectedMenuItem;
-    unsigned int m_keyPressHandlerID;
-};
-
-}
-
-#endif // GtkPopupMenu_h
</del></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (174102 => 174103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2014-09-30 12:50:48 UTC (rev 174102)
+++ trunk/Source/WebKit2/ChangeLog        2014-09-30 13:28:07 UTC (rev 174103)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2014-09-30  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
+
+        [GTK] Move GtkPopupMenu implementation to WebPopupMenuProxyGtk
+        https://bugs.webkit.org/show_bug.cgi?id=137193
+
+        Reviewed by Gustavo Noronha Silva.
+
+        GtkPopupMenu was in platform only to have a common implementation to
+        be shared with WebKit1. Now that it's only used by
+        WebPopupMenuProxyGtk in WebKit2, we can simplify the code by
+        merging the implementation directly into WebPopupMenuProxyGtk.
+
+        * UIProcess/gtk/WebPopupMenuProxyGtk.cpp:
+        (WebKit::WebPopupMenuProxyGtk::WebPopupMenuProxyGtk):
+        (WebKit::WebPopupMenuProxyGtk::~WebPopupMenuProxyGtk):
+        (WebKit::WebPopupMenuProxyGtk::populatePopupMenu):
+        (WebKit::WebPopupMenuProxyGtk::showPopupMenu):
+        (WebKit::WebPopupMenuProxyGtk::hidePopupMenu):
+        (WebKit::WebPopupMenuProxyGtk::typeAheadFind):
+        (WebKit::WebPopupMenuProxyGtk::resetTypeAheadFindState):
+        (WebKit::WebPopupMenuProxyGtk::selectItemCallback):
+        (WebKit::WebPopupMenuProxyGtk::keyPressEventCallback):
+        * UIProcess/gtk/WebPopupMenuProxyGtk.h:
+        (WebKit::WebPopupMenuProxyGtk::setCurrentlySelectedMenuItem):
+
</ins><span class="cx"> 2014-09-29  Christophe Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Use is&lt;&gt;() / downcast&lt;&gt;() for Document
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessgtkWebPopupMenuProxyGtkcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp (174102 => 174103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp        2014-09-30 12:50:48 UTC (rev 174102)
+++ trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp        2014-09-30 13:28:07 UTC (rev 174103)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #include &quot;NativeWebMouseEvent.h&quot;
</span><span class="cx"> #include &quot;WebPopupItem.h&quot;
</span><span class="cx"> #include &lt;WebCore/GtkUtilities.h&gt;
</span><ins>+#include &lt;WebCore/IntRect.h&gt;
</ins><span class="cx"> #include &lt;gtk/gtk.h&gt;
</span><span class="cx"> #include &lt;wtf/gobject/GUniquePtr.h&gt;
</span><span class="cx"> #include &lt;wtf/text/CString.h&gt;
</span><span class="lines">@@ -40,15 +41,21 @@
</span><span class="cx"> WebPopupMenuProxyGtk::WebPopupMenuProxyGtk(GtkWidget* webView, WebPopupMenuProxy::Client* client)
</span><span class="cx">     : WebPopupMenuProxy(client)
</span><span class="cx">     , m_webView(webView)
</span><ins>+    , m_popup(gtk_menu_new())
</ins><span class="cx">     , m_activeItem(-1)
</span><ins>+    , m_previousKeyEventCharacter(0)
+    , m_previousKeyEventTimestamp(0)
+    , m_currentlySelectedMenuItem(nullptr)
</ins><span class="cx"> {
</span><ins>+    g_signal_connect(m_popup, &quot;key-press-event&quot;, G_CALLBACK(keyPressEventCallback), this);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> WebPopupMenuProxyGtk::~WebPopupMenuProxyGtk()
</span><span class="cx"> {
</span><span class="cx">     if (m_popup) {
</span><del>-        g_signal_handlers_disconnect_matched(m_popup-&gt;platformMenu(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
</del><ins>+        g_signal_handlers_disconnect_matched(m_popup, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
</ins><span class="cx">         hidePopupMenu();
</span><ins>+        gtk_widget_destroy(m_popup);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -63,39 +70,89 @@
</span><span class="cx">     return action;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebPopupMenuProxyGtk::showPopupMenu(const IntRect&amp; rect, TextDirection, double /* pageScaleFactor */, const Vector&lt;WebPopupItem&gt;&amp; items, const PlatformPopupMenuData&amp;, int32_t selectedIndex)
</del><ins>+void WebPopupMenuProxyGtk::populatePopupMenu(const Vector&lt;WebPopupItem&gt;&amp; items)
</ins><span class="cx"> {
</span><del>-    if (m_popup)
-        m_popup-&gt;clear();
-    else
-        m_popup = GtkPopupMenu::create();
</del><ins>+    int itemIndex = 0;
+    for (const auto&amp; item : items) {
+        if (item.m_type == WebPopupItem::Separator) {
+            GtkWidget* menuItem = gtk_separator_menu_item_new();
+            gtk_menu_shell_append(GTK_MENU_SHELL(m_popup), menuItem);
+            gtk_widget_show(menuItem);
+        } else {
+            GRefPtr&lt;GtkAction&gt; action = adoptGRef(createGtkActionForMenuItem(item, itemIndex));
+            GtkWidget* menuItem = gtk_action_create_menu_item(action.get());
+            gtk_widget_set_tooltip_text(menuItem, gtk_action_get_tooltip(action.get()));
+            g_signal_connect(menuItem, &quot;select&quot;, G_CALLBACK(selectItemCallback), this);
+            gtk_menu_shell_append(GTK_MENU_SHELL(m_popup), menuItem);
</ins><span class="cx"> 
</span><del>-    const int size = items.size();
-    for (int i = 0; i &lt; size; i++) {
-        if (items[i].m_type == WebPopupItem::Separator)
-            m_popup-&gt;appendSeparator();
-        else {
-            GRefPtr&lt;GtkAction&gt; action = adoptGRef(createGtkActionForMenuItem(items[i], i));
-            m_popup-&gt;appendItem(action.get());
</del><ins>+            if (gtk_action_is_visible(action.get()))
+                gtk_widget_show(menuItem);
</ins><span class="cx">         }
</span><ins>+        itemIndex++;
</ins><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><ins>+void WebPopupMenuProxyGtk::showPopupMenu(const IntRect&amp; rect, TextDirection, double /* pageScaleFactor */, const Vector&lt;WebPopupItem&gt;&amp; items, const PlatformPopupMenuData&amp;, int32_t selectedIndex)
+{
+    populatePopupMenu(items);
+    gtk_menu_set_active(GTK_MENU(m_popup), selectedIndex);
+
+    resetTypeAheadFindState();
+
+
</ins><span class="cx">     IntPoint menuPosition = convertWidgetPointToScreenPoint(m_webView, rect.location());
</span><span class="cx">     menuPosition.move(0, rect.height());
</span><span class="cx"> 
</span><del>-    gulong unmapHandler = g_signal_connect(m_popup-&gt;platformMenu(), &quot;unmap&quot;, G_CALLBACK(menuUnmapped), this);
-    m_popup-&gt;popUp(rect.size(), menuPosition, size, selectedIndex, m_client-&gt;currentlyProcessedMouseDownEvent() ? m_client-&gt;currentlyProcessedMouseDownEvent()-&gt;nativeEvent() : 0);
</del><ins>+    // This approach follows the one in gtkcombobox.c.
+    GtkRequisition requisition;
+    gtk_widget_set_size_request(m_popup, -1, -1);
+    gtk_widget_get_preferred_size(m_popup, &amp;requisition, nullptr);
+    gtk_widget_set_size_request(m_popup, std::max(rect.width(), requisition.width), -1);
</ins><span class="cx"> 
</span><ins>+    if (int itemCount = items.size()) {
+        GUniquePtr&lt;GList&gt; children(gtk_container_get_children(GTK_CONTAINER(m_popup)));
+        int i;
+        GList* child;
+        for (i = 0, child = children.get(); i &lt; itemCount; i++, child = g_list_next(child)) {
+            if (i &gt; selectedIndex)
+                break;
+
+            GtkWidget* item = GTK_WIDGET(child-&gt;data);
+            GtkRequisition itemRequisition;
+            gtk_widget_get_preferred_size(item, &amp;itemRequisition, nullptr);
+            menuPosition.setY(menuPosition.y() - itemRequisition.height);
+        }
+    } else {
+        // Center vertically the empty popup in the combo box area.
+        menuPosition.setY(menuPosition.y() - rect.height() / 2);
+    }
+
+    gulong unmapHandler = g_signal_connect(m_popup, &quot;unmap&quot;, G_CALLBACK(menuUnmapped), this);
+
+    const GdkEvent* event = m_client-&gt;currentlyProcessedMouseDownEvent() ? m_client-&gt;currentlyProcessedMouseDownEvent()-&gt;nativeEvent() : nullptr;
+    gtk_menu_popup_for_device(GTK_MENU(m_popup), event ? gdk_event_get_device(event) : nullptr, nullptr, nullptr,
+        [](GtkMenu*, gint* x, gint* y, gboolean* pushIn, gpointer userData) {
+            // We can pass a pointer to the menuPosition local variable because the nested main loop ensures this is called in the function context.
+            IntPoint* menuPosition = static_cast&lt;IntPoint*&gt;(userData);
+            *x = menuPosition-&gt;x();
+            *y = menuPosition-&gt;y();
+            *pushIn = TRUE;
+        }, &amp;menuPosition, nullptr, event &amp;&amp; event-&gt;type == GDK_BUTTON_PRESS ? event-&gt;button.button : 1,
+        event ? gdk_event_get_time(event) : GDK_CURRENT_TIME);
+
+    // Now that the menu has a position, schedule a resize to make sure it's resized to fit vertically in the work area.
+    gtk_widget_queue_resize(m_popup);
+
</ins><span class="cx">     // PopupMenu can fail to open when there is no mouse grab.
</span><span class="cx">     // Ensure WebCore does not go into some pesky state.
</span><del>-    if (!gtk_widget_get_visible(m_popup-&gt;platformMenu())) {
</del><ins>+    if (!gtk_widget_get_visible(m_popup)) {
</ins><span class="cx">        m_client-&gt;failedToShowPopupMenu();
</span><span class="cx">        return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // WebPageProxy expects the menu to run in a nested run loop, since it invalidates the
</span><span class="cx">     // menu right after calling WebPopupMenuProxy::showPopupMenu().
</span><del>-    m_runLoop = adoptGRef(g_main_loop_new(0, FALSE));
</del><ins>+    m_runLoop = adoptGRef(g_main_loop_new(nullptr, FALSE));
</ins><span class="cx"> 
</span><span class="cx"> // This is to suppress warnings about gdk_threads_leave and gdk_threads_enter.
</span><span class="cx"> #pragma GCC diagnostic push
</span><span class="lines">@@ -107,7 +164,7 @@
</span><span class="cx"> 
</span><span class="cx">     m_runLoop.clear();
</span><span class="cx"> 
</span><del>-    g_signal_handler_disconnect(m_popup-&gt;platformMenu(), unmapHandler);
</del><ins>+    g_signal_handler_disconnect(m_popup, unmapHandler);
</ins><span class="cx"> 
</span><span class="cx">     if (!m_client)
</span><span class="cx">         return;
</span><span class="lines">@@ -117,9 +174,88 @@
</span><span class="cx"> 
</span><span class="cx"> void WebPopupMenuProxyGtk::hidePopupMenu()
</span><span class="cx"> {
</span><del>-    m_popup-&gt;popDown();
</del><ins>+    gtk_menu_popdown(GTK_MENU(m_popup));
+    resetTypeAheadFindState();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool WebPopupMenuProxyGtk::typeAheadFind(GdkEventKey* event)
+{
+    // If we were given a non-printable character just skip it.
+    gunichar unicodeCharacter = gdk_keyval_to_unicode(event-&gt;keyval);
+    if (!g_unichar_isprint(unicodeCharacter)) {
+        resetTypeAheadFindState();
+        return false;
+    }
+
+    glong charactersWritten;
+    GUniquePtr&lt;gunichar2&gt; utf16String(g_ucs4_to_utf16(&amp;unicodeCharacter, 1, nullptr, &amp;charactersWritten, nullptr));
+    if (!utf16String) {
+        resetTypeAheadFindState();
+        return false;
+    }
+
+    // If the character is the same as the last character, the user is probably trying to
+    // cycle through the menulist entries. This matches the WebCore behavior for collapsed menulists.
+    static const uint32_t searchTimeoutMs = 1000;
+    bool repeatingCharacter = unicodeCharacter != m_previousKeyEventCharacter;
+    if (event-&gt;time - m_previousKeyEventTimestamp &gt; searchTimeoutMs)
+        m_currentSearchString = String(reinterpret_cast&lt;UChar*&gt;(utf16String.get()), charactersWritten);
+    else if (repeatingCharacter)
+        m_currentSearchString.append(String(reinterpret_cast&lt;UChar*&gt;(utf16String.get()), charactersWritten));
+
+    m_previousKeyEventTimestamp = event-&gt;time;
+    m_previousKeyEventCharacter = unicodeCharacter;
+
+    GUniquePtr&lt;GList&gt; children(gtk_container_get_children(GTK_CONTAINER(m_popup)));
+    if (!children)
+        return true;
+
+    // We case fold before searching, because strncmp does not handle non-ASCII characters.
+    GUniquePtr&lt;gchar&gt; searchStringWithCaseFolded(g_utf8_casefold(m_currentSearchString.utf8().data(), -1));
+    size_t prefixLength = strlen(searchStringWithCaseFolded.get());
+
+    // If a menu item has already been selected, start searching from the current
+    // item down the list. This will make multiple key presses of the same character
+    // advance the selection.
+    GList* currentChild = children.get();
+    if (m_currentlySelectedMenuItem) {
+        currentChild = g_list_find(children.get(), m_currentlySelectedMenuItem);
+        if (!currentChild) {
+            m_currentlySelectedMenuItem = nullptr;
+            currentChild = children.get();
+        }
+
+        // Repeating characters should iterate.
+        if (repeatingCharacter) {
+            if (GList* nextChild = g_list_next(currentChild))
+                currentChild = nextChild;
+        }
+    }
+
+    GList* firstChild = currentChild;
+    do {
+        currentChild = g_list_next(currentChild);
+        if (!currentChild)
+            currentChild = children.get();
+
+        GUniquePtr&lt;gchar&gt; itemText(g_utf8_casefold(gtk_menu_item_get_label(GTK_MENU_ITEM(currentChild-&gt;data)), -1));
+        if (!strncmp(searchStringWithCaseFolded.get(), itemText.get(), prefixLength)) {
+            gtk_menu_shell_select_item(GTK_MENU_SHELL(m_popup), GTK_WIDGET(currentChild-&gt;data));
+            break;
+        }
+    } while (currentChild != firstChild);
+
+    return true;
+}
+
+void WebPopupMenuProxyGtk::resetTypeAheadFindState()
+{
+    m_currentlySelectedMenuItem = nullptr;
+    m_previousKeyEventCharacter = 0;
+    m_previousKeyEventTimestamp = 0;
+    m_currentSearchString = emptyString();
+}
+
</ins><span class="cx"> void WebPopupMenuProxyGtk::shutdownRunLoop()
</span><span class="cx"> {
</span><span class="cx">     if (g_main_loop_is_running(m_runLoop.get()))
</span><span class="lines">@@ -137,4 +273,14 @@
</span><span class="cx">     popupMenu-&gt;shutdownRunLoop();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebPopupMenuProxyGtk::selectItemCallback(GtkWidget* item, WebPopupMenuProxyGtk* popupMenu)
+{
+    popupMenu-&gt;setCurrentlySelectedMenuItem(item);
+}
+
+gboolean WebPopupMenuProxyGtk::keyPressEventCallback(GtkWidget*, GdkEventKey* event, WebPopupMenuProxyGtk* popupMenu)
+{
+    return popupMenu-&gt;typeAheadFind(event);
+}
+
</ins><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessgtkWebPopupMenuProxyGtkh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h (174102 => 174103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h        2014-09-30 12:50:48 UTC (rev 174102)
+++ trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h        2014-09-30 13:28:07 UTC (rev 174103)
</span><span class="lines">@@ -21,12 +21,16 @@
</span><span class="cx"> #define WebPopupMenuProxyGtk_h
</span><span class="cx"> 
</span><span class="cx"> #include &quot;WebPopupMenuProxy.h&quot;
</span><del>-#include &lt;WebCore/GtkPopupMenu.h&gt;
-#include &lt;WebCore/IntRect.h&gt;
</del><span class="cx"> #include &lt;wtf/gobject/GRefPtr.h&gt;
</span><ins>+#include &lt;wtf/text/WTFString.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> typedef struct _GMainLoop GMainLoop;
</span><ins>+typedef struct _GdkEventKey GdkEventKey;
</ins><span class="cx"> 
</span><ins>+namespace WebCore {
+class IntRect;
+}
+
</ins><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="cx"> class WebPageProxy;
</span><span class="lines">@@ -46,15 +50,28 @@
</span><span class="cx">     WebPopupMenuProxyGtk(GtkWidget*, WebPopupMenuProxy::Client*);
</span><span class="cx">     void shutdownRunLoop();
</span><span class="cx">     void setActiveItem(int activeItem) { m_activeItem = activeItem; }
</span><ins>+    void setCurrentlySelectedMenuItem(GtkWidget* item) { m_currentlySelectedMenuItem = item; }
</ins><span class="cx">     GtkAction* createGtkActionForMenuItem(const WebPopupItem&amp;, int itemIndex);
</span><ins>+    void populatePopupMenu(const Vector&lt;WebPopupItem&gt;&amp;);
</ins><span class="cx"> 
</span><ins>+    bool typeAheadFind(GdkEventKey*);
+    void resetTypeAheadFindState();
+
</ins><span class="cx">     static void menuItemActivated(GtkAction*, WebPopupMenuProxyGtk*);
</span><span class="cx">     static void menuUnmapped(GtkWidget*, WebPopupMenuProxyGtk*);
</span><ins>+    static void selectItemCallback(GtkWidget*, WebPopupMenuProxyGtk*);
+    static gboolean keyPressEventCallback(GtkWidget*, GdkEventKey*, WebPopupMenuProxyGtk*);
</ins><span class="cx"> 
</span><span class="cx">     GtkWidget* m_webView;
</span><del>-    OwnPtr&lt;WebCore::GtkPopupMenu&gt; m_popup;
</del><ins>+    GtkWidget* m_popup;
</ins><span class="cx">     int m_activeItem;
</span><span class="cx">     GRefPtr&lt;GMainLoop&gt; m_runLoop;
</span><ins>+
+    // Typeahead find.
+    unsigned m_previousKeyEventCharacter;
+    uint32_t m_previousKeyEventTimestamp;
+    GtkWidget* m_currentlySelectedMenuItem;
+    String m_currentSearchString;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebKit
</span></span></pre>
</div>
</div>

</body>
</html>