Title: [87930] trunk/Source
Revision
87930
Author
[email protected]
Date
2011-06-02 11:01:23 -0700 (Thu, 02 Jun 2011)

Log Message

2011-06-02  Carlos Garcia Campos  <[email protected]>

        Reviewed by Martin Robinson.

        [GTK] Implement popup menus in Webkit2
        https://bugs.webkit.org/show_bug.cgi?id=61854

        Move common code into a new class to be used by both WebKit1 and
        WebKit2.

        * GNUmakefile.list.am: Add new files to compilation.
        * platform/gtk/GtkPopupMenu.cpp: Copied from Source/WebCore/platform/gtk/PopupMenuGtk.cpp.
        (WebCore::GtkPopupMenu::GtkPopupMenu):
        (WebCore::GtkPopupMenu::~GtkPopupMenu):
        (WebCore::GtkPopupMenu::clear): Remove all menu items.
        (WebCore::GtkPopupMenu::appendSeparator): Add a new separator
        item to the menu.
        (WebCore::GtkPopupMenu::appendItem): Add a new item to the menu for
        the given action.
        (WebCore::GtkPopupMenu::popUp): Show the menu.
        (WebCore::GtkPopupMenu::popDown): Hide the menu.
        (WebCore::GtkPopupMenu::menuRemoveItem):
        (WebCore::GtkPopupMenu::menuPositionFunction):
        (WebCore::GtkPopupMenu::resetTypeAheadFindState):
        (WebCore::GtkPopupMenu::typeAheadFind):
        (WebCore::GtkPopupMenu::selectItemCallback):
        (WebCore::GtkPopupMenu::keyPressEventCallback):
        * platform/gtk/GtkPopupMenu.h: Copied from Source/WebCore/platform/gtk/PopupMenuGtk.h.
        (WebCore::GtkPopupMenu::create):
        (WebCore::GtkPopupMenu::platformMenu):
        * platform/gtk/PopupMenuGtk.cpp:
        (WebCore::PopupMenuGtk::PopupMenuGtk):
        (WebCore::PopupMenuGtk::~PopupMenuGtk):
        (WebCore::PopupMenuGtk::show): Use GtkPopupMenu.
        (WebCore::PopupMenuGtk::hide): Ditto.
        (WebCore::PopupMenuGtk::menuItemActivated):
        (WebCore::PopupMenuGtk::menuUnmapped):
        * platform/gtk/PopupMenuGtk.h:
2011-06-02  Carlos Garcia Campos  <[email protected]>

        Reviewed by Martin Robinson.

        [GTK] Implement popup menus in Webkit2
        https://bugs.webkit.org/show_bug.cgi?id=61854

        * GNUmakefile.am: Add new files to compilation.
        * UIProcess/API/gtk/PageClientImpl.cpp:
        (WebKit::PageClientImpl::createPopupMenuProxy): Create a new
        WebPopupMenuProxy.
        * UIProcess/gtk/WebPopupMenuProxyGtk.cpp: Added.
        (WebKit::WebPopupMenuProxyGtk::WebPopupMenuProxyGtk):
        (WebKit::WebPopupMenuProxyGtk::~WebPopupMenuProxyGtk):
        (WebKit::WebPopupMenuProxyGtk::showPopupMenu):
        (WebKit::WebPopupMenuProxyGtk::hidePopupMenu):
        (WebKit::WebPopupMenuProxyGtk::shutdownRunLoop):
        (WebKit::WebPopupMenuProxyGtk::menuItemActivated):
        (WebKit::WebPopupMenuProxyGtk::menuUnmapped):
        * UIProcess/gtk/WebPopupMenuProxyGtk.h: Added.
        (WebKit::WebPopupMenuProxyGtk::create):
        (WebKit::WebPopupMenuProxyGtk::setActiveItem):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (87929 => 87930)


--- trunk/Source/WebCore/ChangeLog	2011-06-02 17:50:48 UTC (rev 87929)
+++ trunk/Source/WebCore/ChangeLog	2011-06-02 18:01:23 UTC (rev 87930)
@@ -1,3 +1,42 @@
+2011-06-02  Carlos Garcia Campos  <[email protected]>
+
+        Reviewed by Martin Robinson.
+
+        [GTK] Implement popup menus in Webkit2
+        https://bugs.webkit.org/show_bug.cgi?id=61854
+
+        Move common code into a new class to be used by both WebKit1 and
+        WebKit2.
+
+        * GNUmakefile.list.am: Add new files to compilation.
+        * platform/gtk/GtkPopupMenu.cpp: Copied from Source/WebCore/platform/gtk/PopupMenuGtk.cpp.
+        (WebCore::GtkPopupMenu::GtkPopupMenu):
+        (WebCore::GtkPopupMenu::~GtkPopupMenu):
+        (WebCore::GtkPopupMenu::clear): Remove all menu items.
+        (WebCore::GtkPopupMenu::appendSeparator): Add a new separator
+        item to the menu.
+        (WebCore::GtkPopupMenu::appendItem): Add a new item to the menu for
+        the given action.
+        (WebCore::GtkPopupMenu::popUp): Show the menu.
+        (WebCore::GtkPopupMenu::popDown): Hide the menu.
+        (WebCore::GtkPopupMenu::menuRemoveItem):
+        (WebCore::GtkPopupMenu::menuPositionFunction):
+        (WebCore::GtkPopupMenu::resetTypeAheadFindState):
+        (WebCore::GtkPopupMenu::typeAheadFind):
+        (WebCore::GtkPopupMenu::selectItemCallback):
+        (WebCore::GtkPopupMenu::keyPressEventCallback):
+        * platform/gtk/GtkPopupMenu.h: Copied from Source/WebCore/platform/gtk/PopupMenuGtk.h.
+        (WebCore::GtkPopupMenu::create):
+        (WebCore::GtkPopupMenu::platformMenu):
+        * platform/gtk/PopupMenuGtk.cpp:
+        (WebCore::PopupMenuGtk::PopupMenuGtk):
+        (WebCore::PopupMenuGtk::~PopupMenuGtk):
+        (WebCore::PopupMenuGtk::show): Use GtkPopupMenu.
+        (WebCore::PopupMenuGtk::hide): Ditto.
+        (WebCore::PopupMenuGtk::menuItemActivated):
+        (WebCore::PopupMenuGtk::menuUnmapped):
+        * platform/gtk/PopupMenuGtk.h:
+
 2011-05-21  Dimitri Glazkov  <[email protected]>
 
         Reviewed by Darin Adler.

Modified: trunk/Source/WebCore/GNUmakefile.list.am (87929 => 87930)


--- trunk/Source/WebCore/GNUmakefile.list.am	2011-06-02 17:50:48 UTC (rev 87929)
+++ trunk/Source/WebCore/GNUmakefile.list.am	2011-06-02 18:01:23 UTC (rev 87930)
@@ -3796,6 +3796,8 @@
 	Source/WebCore/platform/gtk/GRefPtrGtk.h \
 	Source/WebCore/platform/gtk/GtkPluginWidget.cpp \
 	Source/WebCore/platform/gtk/GtkPluginWidget.h \
+	Source/WebCore/platform/gtk/GtkPopupMenu.cpp \
+	Source/WebCore/platform/gtk/GtkPopupMenu.h \
 	Source/WebCore/platform/gtk/GtkVersioning.c \
 	Source/WebCore/platform/gtk/GtkVersioning.h \
 	Source/WebCore/platform/gtk/KeyBindingTranslator.cpp \

Copied: trunk/Source/WebCore/platform/gtk/GtkPopupMenu.cpp (from rev 87929, trunk/Source/WebCore/platform/gtk/PopupMenuGtk.cpp) (0 => 87930)


--- trunk/Source/WebCore/platform/gtk/GtkPopupMenu.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/gtk/GtkPopupMenu.cpp	2011-06-02 18:01:23 UTC (rev 87930)
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the popup menu implementation for <select> elements in WebCore.
+ *
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel [email protected]
+ * 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 "config.h"
+#include "GtkPopupMenu.h"
+
+#include "GOwnPtr.h"
+#include "GtkVersioning.h"
+#include <gtk/gtk.h>
+#include <wtf/text/CString.h>
+
+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(), "key-press-event", 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<GtkCallback>(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);
+    g_signal_connect(menuItem, "select", G_CALLBACK(GtkPopupMenu::selectItemCallback), this);
+    gtk_menu_shell_append(GTK_MENU_SHELL(m_popup.get()), menuItem);
+    gtk_widget_show(menuItem);
+}
+
+void GtkPopupMenu::popUp(const IntSize& menuSize, const IntPoint& 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(), &requisition);
+#else
+    gtk_widget_get_preferred_size(m_popup.get(), &requisition, 0);
+#endif
+
+    gtk_widget_set_size_request(m_popup.get(), std::max(menuSize.width(), requisition.width), -1);
+
+    GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get()));
+    GList* p = children;
+    if (itemCount) {
+        for (int i = 0; i < itemCount; i++) {
+            if (i > selectedItem)
+                break;
+
+            GtkWidget* item = reinterpret_cast<GtkWidget*>(p->data);
+            GtkRequisition itemRequisition;
+#ifdef GTK_API_VERSION_2
+            gtk_widget_get_child_requisition(item, &itemRequisition);
+#else
+            gtk_widget_get_preferred_size(item, &itemRequisition, 0);
+#endif
+            m_menuPosition.setY(m_menuPosition.y() - itemRequisition.height);
+
+            p = g_list_next(p);
+        }
+    } else {
+        // Center vertically the empty popup in the combo box area.
+        m_menuPosition.setY(m_menuPosition.y() - menuSize.height() / 2);
+    }
+    g_list_free(children);
+
+    guint button;
+    guint32 activateTime;
+    if (event) {
+        button = event->type == GDK_BUTTON_PRESS ? event->button.button : 1;
+        activateTime = gdk_event_get_time(event);
+    } else {
+        button = 1;
+        activateTime = GDK_CURRENT_TIME;
+    }
+
+#ifdef GTK_API_VERSION_2
+    gtk_menu_popup(GTK_MENU(m_popup.get()), 0, 0, reinterpret_cast<GtkMenuPositionFunc>(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<GtkMenuPositionFunc>(menuPositionFunction), this, 0, button, activateTime);
+#endif
+}
+
+void GtkPopupMenu::popDown()
+{
+    gtk_menu_popdown(GTK_MENU(m_popup.get()));
+    resetTypeAheadFindState();
+}
+
+void GtkPopupMenu::menuRemoveItem(GtkWidget* widget, GtkPopupMenu* popupMenu)
+{
+    ASSERT(popupMenu->m_popup);
+    gtk_container_remove(GTK_CONTAINER(popupMenu->m_popup.get()), widget);
+}
+
+void GtkPopupMenu::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pushIn, GtkPopupMenu* popupMenu)
+{
+    *x = popupMenu->m_menuPosition.x();
+    *y = popupMenu->m_menuPosition.y();
+    *pushIn = true;
+}
+
+void GtkPopupMenu::resetTypeAheadFindState()
+{
+    m_currentlySelectedMenuItem = 0;
+    m_previousKeyEventCharacter = 0;
+    m_currentSearchString = "";
+}
+
+bool GtkPopupMenu::typeAheadFind(GdkEventKey* event)
+{
+    // If we were given a non-printable character just skip it.
+    gunichar unicodeCharacter = gdk_keyval_to_unicode(event->keyval);
+    if (!g_unichar_isprint(unicodeCharacter)) {
+        resetTypeAheadFindState();
+        return false;
+    }
+
+    glong charactersWritten;
+    GOwnPtr<gunichar2> utf16String(g_ucs4_to_utf16(&unicodeCharacter, 1, 0, &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->time - m_previousKeyEventTimestamp > gSearchTimeoutMs)
+        m_currentSearchString = String(static_cast<UChar*>(utf16String.get()), charactersWritten);
+    else if (repeatingCharacter)
+        m_currentSearchString.append(String(static_cast<UChar*>(utf16String.get()), charactersWritten));
+
+    m_previousKeyEventTimestamp = event->time;
+    m_previousKeyEventCharacter = unicodeCharacter;
+
+    // Like the Chromium port, we case fold before searching, because 
+    // strncmp does not handle non-ASCII characters.
+    GOwnPtr<gchar> 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;
+
+        GOwnPtr<gchar> itemText(g_utf8_casefold(gtk_menu_item_get_label(GTK_MENU_ITEM(currentChild->data)), -1));
+        if (!strncmp(searchStringWithCaseFolded.get(), itemText.get(), prefixLength)) {
+            gtk_menu_shell_select_item(GTK_MENU_SHELL(m_popup.get()), GTK_WIDGET(currentChild->data));
+            break;
+        }
+    } while (currentChild != firstChild);
+
+    g_list_free(children);
+    return true;
+}
+
+void GtkPopupMenu::selectItemCallback(GtkMenuItem* item, GtkPopupMenu* popupMenu)
+{
+    popupMenu->m_currentlySelectedMenuItem = GTK_WIDGET(item);
+}
+
+gboolean GtkPopupMenu::keyPressEventCallback(GtkWidget* widget, GdkEventKey* event, GtkPopupMenu* popupMenu)
+{
+    return popupMenu->typeAheadFind(event);
+}
+
+} // namespace WebCore

Copied: trunk/Source/WebCore/platform/gtk/GtkPopupMenu.h (from rev 87929, trunk/Source/WebCore/platform/gtk/PopupMenuGtk.h) (0 => 87930)


--- trunk/Source/WebCore/platform/gtk/GtkPopupMenu.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/gtk/GtkPopupMenu.h	2011-06-02 18:01:23 UTC (rev 87930)
@@ -0,0 +1,78 @@
+/*
+ * 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 "GRefPtrGtk.h"
+#include "IntPoint.h"
+#include "IntSize.h"
+#include "PlatformString.h"
+#include <wtf/FastAllocBase.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+
+typedef struct _GdkEventKey GdkEventKey;
+
+namespace WebCore {
+
+class GtkPopupMenu {
+    WTF_MAKE_NONCOPYABLE(GtkPopupMenu);
+    WTF_MAKE_FAST_ALLOCATED;
+
+public:
+    static PassOwnPtr<GtkPopupMenu> create()
+    {
+        return adoptPtr(new GtkPopupMenu());
+    }
+
+    ~GtkPopupMenu();
+
+    GtkWidget* platformMenu() const { return m_popup.get(); }
+    void clear();
+    void appendSeparator();
+    void appendItem(GtkAction*);
+    void popUp(const IntSize&, const IntPoint&, 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<GtkWidget> 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

Modified: trunk/Source/WebCore/platform/gtk/PopupMenuGtk.cpp (87929 => 87930)


--- trunk/Source/WebCore/platform/gtk/PopupMenuGtk.cpp	2011-06-02 17:50:48 UTC (rev 87929)
+++ trunk/Source/WebCore/platform/gtk/PopupMenuGtk.cpp	2011-06-02 18:01:23 UTC (rev 87930)
@@ -29,10 +29,7 @@
 
 #include "FrameView.h"
 #include "GOwnPtr.h"
-#include "GtkVersioning.h"
 #include "HostWindow.h"
-#include "PlatformString.h"
-#include <gdk/gdk.h>
 #include <gtk/gtk.h>
 #include <wtf/text/CString.h>
 
@@ -42,102 +39,64 @@
 
 PopupMenuGtk::PopupMenuGtk(PopupMenuClient* client)
     : m_popupClient(client)
-    , m_previousKeyEventCharacter(0)
-    , m_currentlySelectedMenuItem(0)
 {
 }
 
 PopupMenuGtk::~PopupMenuGtk()
 {
     if (m_popup) {
-        g_signal_handlers_disconnect_matched(m_popup.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+        g_signal_handlers_disconnect_matched(m_popup->platformMenu(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
         hide();
     }
 }
 
+GtkAction* PopupMenuGtk::createGtkActionForMenuItem(int itemIndex)
+{
+    GOwnPtr<char> actionName(g_strdup_printf("popup-menu-action-%d", itemIndex));
+    GtkAction* action = "" client()->itemText(itemIndex).utf8().data(), 0, 0);
+    g_object_set_data(G_OBJECT(action), "popup-menu-action-index", GINT_TO_POINTER(itemIndex));
+    g_signal_connect(action, "activate", G_CALLBACK(menuItemActivated), this);
+    // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i)
+    gtk_action_set_sensitive(action, client()->itemIsEnabled(itemIndex));
+
+    return action;
+}
+
 void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index)
 {
     ASSERT(client());
 
     if (!m_popup) {
-        m_popup = GTK_MENU(gtk_menu_new());
-        g_signal_connect(m_popup.get(), "unmap", G_CALLBACK(PopupMenuGtk::menuUnmapped), this);
-        g_signal_connect(m_popup.get(), "key-press-event", G_CALLBACK(PopupMenuGtk::keyPressEventCallback), this);
+        m_popup = GtkPopupMenu::create();
+        g_signal_connect(m_popup->platformMenu(), "unmap", G_CALLBACK(PopupMenuGtk::menuUnmapped), this);
     } else
-        gtk_container_foreach(GTK_CONTAINER(m_popup.get()), reinterpret_cast<GtkCallback>(menuRemoveItem), this);
+        m_popup->clear();
 
-    int x = 0;
-    int y = 0;
-    GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(view->hostWindow()->platformPageClient()));
-    if (window)
-        gdk_window_get_origin(window, &x, &y);
-    m_menuPosition = view->contentsToWindow(rect.location());
-    m_menuPosition = IntPoint(m_menuPosition.x() + x, m_menuPosition.y() + y + rect.height());
-    m_indexMap.clear();
-
     const int size = client()->listSize();
     for (int i = 0; i < size; ++i) {
-        GtkWidget* item;
         if (client()->itemIsSeparator(i))
-            item = gtk_separator_menu_item_new();
-        else
-            item = gtk_menu_item_new_with_label(client()->itemText(i).utf8().data());
-
-        m_indexMap.add(item, i);
-        g_signal_connect(item, "activate", G_CALLBACK(PopupMenuGtk::menuItemActivated), this);
-        g_signal_connect(item, "select", G_CALLBACK(PopupMenuGtk::selectItemCallback), this);
-
-        // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i)
-        gtk_widget_set_sensitive(item, client()->itemIsEnabled(i));
-        gtk_menu_shell_append(GTK_MENU_SHELL(m_popup.get()), item);
-        gtk_widget_show(item);
-    }
-
-    gtk_menu_set_active(m_popup.get(), index);
-
-
-    // The size calls are directly copied from gtkcombobox.c which is LGPL
-    GtkRequisition requisition;
-    gtk_widget_set_size_request(GTK_WIDGET(m_popup.get()), -1, -1);
-#ifdef GTK_API_VERSION_2
-    gtk_widget_size_request(GTK_WIDGET(m_popup.get()), &requisition);
-#else
-    gtk_widget_get_preferred_size(GTK_WIDGET(m_popup.get()), &requisition, 0);
-#endif
-
-    gtk_widget_set_size_request(GTK_WIDGET(m_popup.get()), std::max(rect.width(), requisition.width), -1);
-
-    GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get()));
-    GList* p = children;
-    if (size) {
-        for (int i = 0; i < size; i++) {
-            if (i > index)
-              break;
-
-            GtkWidget* item = reinterpret_cast<GtkWidget*>(p->data);
-            GtkRequisition itemRequisition;
-#ifdef GTK_API_VERSION_2
-            gtk_widget_get_child_requisition(item, &itemRequisition);
-#else
-            gtk_widget_get_preferred_size(item, &itemRequisition, 0);
-#endif
-            m_menuPosition.setY(m_menuPosition.y() - itemRequisition.height);
-
-            p = g_list_next(p);
+            m_popup->appendSeparator();
+        else {
+            GRefPtr<GtkAction> action = ""
+            m_popup->appendItem(action.get());
         }
-    } else {
-        // Center vertically the empty popup in the combo box area
-        m_menuPosition.setY(m_menuPosition.y() - rect.height() / 2);
     }
 
-    g_list_free(children);
-    gtk_menu_popup(m_popup.get(), 0, 0, reinterpret_cast<GtkMenuPositionFunc>(menuPositionFunction), this, 0, gtk_get_current_event_time());
+    int x = 0;
+    int y = 0;
+    GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(view->hostWindow()->platformPageClient()));
+    if (window)
+        gdk_window_get_origin(window, &x, &y);
+    IntPoint menuPosition(view->contentsToWindow(rect.location()));
+    menuPosition.move(x, y + rect.height());
+
+    m_popup->popUp(rect.size(), menuPosition, size, index, gtk_get_current_event());
 }
 
 void PopupMenuGtk::hide()
 {
     ASSERT(m_popup);
-    gtk_menu_popdown(m_popup.get());
+    m_popup->popDown();
 }
 
 void PopupMenuGtk::updateFromElement()
@@ -150,121 +109,17 @@
     m_popupClient = 0;
 }
 
-bool PopupMenuGtk::typeAheadFind(GdkEventKey* event)
+void PopupMenuGtk::menuItemActivated(GtkAction* action, PopupMenuGtk* that)
 {
-    // If we were given a non-printable character just skip it.
-    gunichar unicodeCharacter = gdk_keyval_to_unicode(event->keyval);
-    if (!unicodeCharacter) {
-        resetTypeAheadFindState();
-        return false;
-    }
-
-    glong charactersWritten;
-    GOwnPtr<gunichar2> utf16String(g_ucs4_to_utf16(&unicodeCharacter, 1, 0, &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->time - m_previousKeyEventTimestamp > gSearchTimeoutMs)
-        m_currentSearchString = String(static_cast<UChar*>(utf16String.get()), charactersWritten);
-    else if (repeatingCharacter)
-        m_currentSearchString.append(String(static_cast<UChar*>(utf16String.get()), charactersWritten));
-
-    m_previousKeyEventTimestamp = event->time;
-    m_previousKeyEventCharacter = unicodeCharacter;
-
-    // Like the Chromium port, we case fold before searching, because 
-    // strncmp does not handle non-ASCII characters.
-    GOwnPtr<gchar> 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;
-
-        GOwnPtr<gchar> itemText(g_utf8_casefold(gtk_menu_item_get_label(GTK_MENU_ITEM(currentChild->data)), -1));
-        if (!strncmp(searchStringWithCaseFolded.get(), itemText.get(), prefixLength)) {
-            gtk_menu_shell_select_item(GTK_MENU_SHELL(m_popup.get()), GTK_WIDGET(currentChild->data));
-            return true;
-        }
-    } while (currentChild != firstChild);
-
-    return true;
-}
-
-void PopupMenuGtk::menuItemActivated(GtkMenuItem* item, PopupMenuGtk* that)
-{
     ASSERT(that->client());
-    ASSERT(that->m_indexMap.contains(GTK_WIDGET(item)));
-    that->client()->valueChanged(that->m_indexMap.get(GTK_WIDGET(item)));
+    that->client()->valueChanged(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "popup-menu-action-index")));
 }
 
 void PopupMenuGtk::menuUnmapped(GtkWidget*, PopupMenuGtk* that)
 {
     ASSERT(that->client());
-    that->resetTypeAheadFindState();
     that->client()->popupDidHide();
 }
 
-void PopupMenuGtk::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pushIn, PopupMenuGtk* that)
-{
-    *x = that->m_menuPosition.x();
-    *y = that->m_menuPosition.y();
-    *pushIn = true;
 }
 
-void PopupMenuGtk::resetTypeAheadFindState()
-{
-    m_currentlySelectedMenuItem = 0;
-    m_previousKeyEventCharacter = 0;
-    m_currentSearchString = "";
-}
-
-void PopupMenuGtk::menuRemoveItem(GtkWidget* widget, PopupMenuGtk* that)
-{
-    ASSERT(that->m_popup);
-    gtk_container_remove(GTK_CONTAINER(that->m_popup.get()), widget);
-}
-
-int PopupMenuGtk::selectItemCallback(GtkMenuItem* item, PopupMenuGtk* that)
-{
-    that->m_currentlySelectedMenuItem = GTK_WIDGET(item);
-    return FALSE;
-}
-
-int PopupMenuGtk::keyPressEventCallback(GtkWidget* widget, GdkEventKey* event, PopupMenuGtk* that)
-{
-    return that->typeAheadFind(event);
-}
-
-}
-

Modified: trunk/Source/WebCore/platform/gtk/PopupMenuGtk.h (87929 => 87930)


--- trunk/Source/WebCore/platform/gtk/PopupMenuGtk.h	2011-06-02 17:50:48 UTC (rev 87929)
+++ trunk/Source/WebCore/platform/gtk/PopupMenuGtk.h	2011-06-02 18:01:23 UTC (rev 87930)
@@ -20,16 +20,11 @@
 #ifndef PopupMenuGtk_h
 #define PopupMenuGtk_h
 
-#include "GRefPtrGtk.h"
+#include "GtkPopupMenu.h"
 #include "IntRect.h"
 #include "PopupMenu.h"
 #include "PopupMenuClient.h"
-#include <wtf/HashMap.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
 
-typedef struct _GdkEventKey GdkEventKey;
-
 namespace WebCore {
 
 class FrameView;
@@ -44,27 +39,16 @@
     virtual void hide();
     virtual void updateFromElement();
     virtual void disconnectClient();
-    bool typeAheadFind(GdkEventKey*);
 
 private:
     PopupMenuClient* client() const { return m_popupClient; }
-    void resetTypeAheadFindState();
+    GtkAction* createGtkActionForMenuItem(int itemIndex);
 
-    static void menuItemActivated(GtkMenuItem* item, PopupMenuGtk*);
     static void menuUnmapped(GtkWidget*, PopupMenuGtk*);
-    static void menuPositionFunction(GtkMenu*, gint*, gint*, gboolean*, PopupMenuGtk*);
-    static void menuRemoveItem(GtkWidget*, PopupMenuGtk*);
-    static int selectItemCallback(GtkMenuItem*, PopupMenuGtk*);
-    static int keyPressEventCallback(GtkWidget*, GdkEventKey*, PopupMenuGtk*);
+    static void menuItemActivated(GtkAction*, PopupMenuGtk*);
 
     PopupMenuClient* m_popupClient;
-    IntPoint m_menuPosition;
-    GRefPtr<GtkMenu> m_popup;
-    HashMap<GtkWidget*, int> m_indexMap;
-    String m_currentSearchString;
-    uint32_t m_previousKeyEventTimestamp;
-    unsigned int m_previousKeyEventCharacter;
-    GtkWidget* m_currentlySelectedMenuItem;
+    OwnPtr<GtkPopupMenu> m_popup;
 };
 
 }

Modified: trunk/Source/WebKit2/ChangeLog (87929 => 87930)


--- trunk/Source/WebKit2/ChangeLog	2011-06-02 17:50:48 UTC (rev 87929)
+++ trunk/Source/WebKit2/ChangeLog	2011-06-02 18:01:23 UTC (rev 87930)
@@ -1,3 +1,26 @@
+2011-06-02  Carlos Garcia Campos  <[email protected]>
+
+        Reviewed by Martin Robinson.
+
+        [GTK] Implement popup menus in Webkit2
+        https://bugs.webkit.org/show_bug.cgi?id=61854
+
+        * GNUmakefile.am: Add new files to compilation.
+        * UIProcess/API/gtk/PageClientImpl.cpp:
+        (WebKit::PageClientImpl::createPopupMenuProxy): Create a new
+        WebPopupMenuProxy.
+        * UIProcess/gtk/WebPopupMenuProxyGtk.cpp: Added.
+        (WebKit::WebPopupMenuProxyGtk::WebPopupMenuProxyGtk):
+        (WebKit::WebPopupMenuProxyGtk::~WebPopupMenuProxyGtk):
+        (WebKit::WebPopupMenuProxyGtk::showPopupMenu):
+        (WebKit::WebPopupMenuProxyGtk::hidePopupMenu):
+        (WebKit::WebPopupMenuProxyGtk::shutdownRunLoop):
+        (WebKit::WebPopupMenuProxyGtk::menuItemActivated):
+        (WebKit::WebPopupMenuProxyGtk::menuUnmapped):
+        * UIProcess/gtk/WebPopupMenuProxyGtk.h: Added.
+        (WebKit::WebPopupMenuProxyGtk::create):
+        (WebKit::WebPopupMenuProxyGtk::setActiveItem):
+
 2011-06-01  Sam Weinig  <[email protected]>
 
         Reviewed by Anders Carlsson.

Modified: trunk/Source/WebKit2/GNUmakefile.am (87929 => 87930)


--- trunk/Source/WebKit2/GNUmakefile.am	2011-06-02 17:50:48 UTC (rev 87929)
+++ trunk/Source/WebKit2/GNUmakefile.am	2011-06-02 18:01:23 UTC (rev 87930)
@@ -394,6 +394,8 @@
 	Source/WebKit2/UIProcess/gtk/WebFullScreenManagerProxyGtk.cpp \
 	Source/WebKit2/UIProcess/gtk/WebInspectorGtk.cpp \
 	Source/WebKit2/UIProcess/gtk/WebPageProxyGtk.cpp \
+	Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp \
+	Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h \
 	Source/WebKit2/UIProcess/gtk/WebPreferencesGtk.cpp \
 	Source/WebKit2/UIProcess/Launcher/gtk/ProcessLauncherGtk.cpp \
 	Source/WebKit2/UIProcess/Launcher/gtk/ThreadLauncherGtk.cpp \

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp (87929 => 87930)


--- trunk/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp	2011-06-02 17:50:48 UTC (rev 87929)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp	2011-06-02 18:01:23 UTC (rev 87930)
@@ -37,6 +37,7 @@
 #include "WebEventFactory.h"
 #include "WebKitWebViewBasePrivate.h"
 #include "WebPageProxy.h"
+#include "WebPopupMenuProxyGtk.h"
 #include <WebCore/GtkUtilities.h>
 #include <wtf/text/WTFString.h>
 
@@ -204,10 +205,9 @@
     notImplemented();
 }
 
-PassRefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy*)
+PassRefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy* page)
 {
-    notImplemented();
-    return 0;
+    return WebPopupMenuProxyGtk::create(m_viewWidget, page);
 }
 
 PassRefPtr<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPageProxy*)

Added: trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp (0 => 87930)


--- trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp	2011-06-02 18:01:23 UTC (rev 87930)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebPopupMenuProxyGtk.h"
+
+#include "NativeWebMouseEvent.h"
+#include "WebPopupItem.h"
+#include <gtk/gtk.h>
+#include <wtf/gobject/GOwnPtr.h>
+#include <wtf/text/CString.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+WebPopupMenuProxyGtk::WebPopupMenuProxyGtk(GtkWidget* webView, WebPopupMenuProxy::Client* client)
+    : WebPopupMenuProxy(client)
+    , m_webView(webView)
+    , m_activeItem(-1)
+    , m_runLoop(0)
+{
+}
+
+WebPopupMenuProxyGtk::~WebPopupMenuProxyGtk()
+{
+    if (m_popup) {
+        g_signal_handlers_disconnect_matched(m_popup->platformMenu(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+        hidePopupMenu();
+    }
+}
+
+GtkAction* WebPopupMenuProxyGtk::createGtkActionForMenuItem(const WebPopupItem& item, int itemIndex)
+{
+    GOwnPtr<char> actionName(g_strdup_printf("popup-menu-action-%d", itemIndex));
+    GtkAction* action = "" item.m_text.utf8().data(), item.m_toolTip.utf8().data(), 0);
+    g_object_set_data(G_OBJECT(action), "popup-menu-action-index", GINT_TO_POINTER(itemIndex));
+    g_signal_connect(action, "activate", G_CALLBACK(menuItemActivated), this);
+    gtk_action_set_sensitive(action, item.m_isEnabled);
+
+    return action;
+}
+
+void WebPopupMenuProxyGtk::showPopupMenu(const IntRect& rect, TextDirection textDirection, double scaleFactor, const Vector<WebPopupItem>& items, const PlatformPopupMenuData& data, int32_t selectedIndex)
+{
+    if (m_popup)
+        m_popup->clear();
+    else
+        m_popup = GtkPopupMenu::create();
+
+    const int size = items.size();
+    for (int i = 0; i < size; i++) {
+        if (items[i].m_type == WebPopupItem::Separator)
+            m_popup->appendSeparator();
+        else {
+            GRefPtr<GtkAction> action = "" i));
+            m_popup->appendItem(action.get());
+        }
+    }
+
+    int x = 0;
+    int y = 0;
+    if (GdkWindow* window = gtk_widget_get_window(m_webView))
+        gdk_window_get_origin(window, &x, &y);
+    IntPoint menuPosition(rect.x() + x, rect.y() + y + rect.height());
+
+    gulong unmapHandler = g_signal_connect(m_popup->platformMenu(), "unmap", G_CALLBACK(menuUnmapped), this);
+    m_popup->popUp(rect.size(), menuPosition, size, selectedIndex, m_client->currentlyProcessedMouseDownEvent() ? m_client->currentlyProcessedMouseDownEvent()->nativeEvent() : 0);
+
+    // WebPageProxy expects the menu to run in a nested run loop, since it invalidates the
+    // menu right after calling WebPopupMenuProxy::showPopupMenu().
+    m_runLoop = g_main_loop_new(0, FALSE);
+
+    GDK_THREADS_LEAVE();
+    g_main_loop_run(m_runLoop);
+    GDK_THREADS_ENTER();
+
+    g_main_loop_unref(m_runLoop);
+    m_runLoop = 0;
+
+    g_signal_handler_disconnect(m_popup->platformMenu(), unmapHandler);
+
+    if (!m_client)
+        return;
+
+    m_client->valueChangedForPopupMenu(this, m_activeItem);
+}
+
+void WebPopupMenuProxyGtk::hidePopupMenu()
+{
+    m_popup->popDown();
+}
+
+void WebPopupMenuProxyGtk::shutdownRunLoop()
+{
+    if (g_main_loop_is_running(m_runLoop))
+        g_main_loop_quit(m_runLoop);
+}
+
+void WebPopupMenuProxyGtk::menuItemActivated(GtkAction* action, WebPopupMenuProxyGtk* popupMenu)
+{
+    popupMenu->setActiveItem(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "popup-menu-action-index")));
+    popupMenu->shutdownRunLoop();
+}
+
+void WebPopupMenuProxyGtk::menuUnmapped(GtkWidget*, WebPopupMenuProxyGtk* popupMenu)
+{
+    popupMenu->shutdownRunLoop();
+}
+
+} // namespace WebKit

Added: trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h (0 => 87930)


--- trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h	2011-06-02 18:01:23 UTC (rev 87930)
@@ -0,0 +1,62 @@
+/*
+ * 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 WebPopupMenuProxyGtk_h
+#define WebPopupMenuProxyGtk_h
+
+#include "WebPopupMenuProxy.h"
+#include <WebCore/GtkPopupMenu.h>
+#include <WebCore/IntRect.h>
+
+typedef struct _GMainLoop GMainLoop;
+
+namespace WebKit {
+
+class WebPageProxy;
+
+class WebPopupMenuProxyGtk : public WebPopupMenuProxy {
+public:
+    static PassRefPtr<WebPopupMenuProxyGtk> create(GtkWidget* webView, WebPopupMenuProxy::Client* client)
+    {
+        return adoptRef(new WebPopupMenuProxyGtk(webView, client));
+    }
+    ~WebPopupMenuProxyGtk();
+
+    virtual void showPopupMenu(const WebCore::IntRect&, WebCore::TextDirection, double scaleFactor, const Vector<WebPopupItem>&, const PlatformPopupMenuData&, int32_t selectedIndex);
+    virtual void hidePopupMenu();
+
+private:
+    WebPopupMenuProxyGtk(GtkWidget*, WebPopupMenuProxy::Client*);
+    void shutdownRunLoop();
+    void setActiveItem(int activeItem) { m_activeItem = activeItem; }
+    GtkAction* createGtkActionForMenuItem(const WebPopupItem&, int itemIndex);
+
+    static void menuItemActivated(GtkAction*, WebPopupMenuProxyGtk*);
+    static void menuUnmapped(GtkWidget*, WebPopupMenuProxyGtk*);
+
+    GtkWidget* m_webView;
+    OwnPtr<WebCore::GtkPopupMenu> m_popup;
+    int m_activeItem;
+    GMainLoop* m_runLoop;
+};
+
+} // namespace WebKit
+
+
+#endif // WebPopupMenuProxyGtk_h
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to