Changeset 87930 in webkit


Ignore:
Timestamp:
Jun 2, 2011, 11:01:23 AM (14 years ago)
Author:
Carlos Garcia Campos
Message:

2011-06-02 Carlos Garcia Campos <cgarcia@igalia.com>

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 <cgarcia@igalia.com>

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):
Location:
trunk/Source
Files:
2 added
7 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r87926 r87930  
     12011-06-02  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        Reviewed by Martin Robinson.
     4
     5        [GTK] Implement popup menus in Webkit2
     6        https://bugs.webkit.org/show_bug.cgi?id=61854
     7
     8        Move common code into a new class to be used by both WebKit1 and
     9        WebKit2.
     10
     11        * GNUmakefile.list.am: Add new files to compilation.
     12        * platform/gtk/GtkPopupMenu.cpp: Copied from Source/WebCore/platform/gtk/PopupMenuGtk.cpp.
     13        (WebCore::GtkPopupMenu::GtkPopupMenu):
     14        (WebCore::GtkPopupMenu::~GtkPopupMenu):
     15        (WebCore::GtkPopupMenu::clear): Remove all menu items.
     16        (WebCore::GtkPopupMenu::appendSeparator): Add a new separator
     17        item to the menu.
     18        (WebCore::GtkPopupMenu::appendItem): Add a new item to the menu for
     19        the given action.
     20        (WebCore::GtkPopupMenu::popUp): Show the menu.
     21        (WebCore::GtkPopupMenu::popDown): Hide the menu.
     22        (WebCore::GtkPopupMenu::menuRemoveItem):
     23        (WebCore::GtkPopupMenu::menuPositionFunction):
     24        (WebCore::GtkPopupMenu::resetTypeAheadFindState):
     25        (WebCore::GtkPopupMenu::typeAheadFind):
     26        (WebCore::GtkPopupMenu::selectItemCallback):
     27        (WebCore::GtkPopupMenu::keyPressEventCallback):
     28        * platform/gtk/GtkPopupMenu.h: Copied from Source/WebCore/platform/gtk/PopupMenuGtk.h.
     29        (WebCore::GtkPopupMenu::create):
     30        (WebCore::GtkPopupMenu::platformMenu):
     31        * platform/gtk/PopupMenuGtk.cpp:
     32        (WebCore::PopupMenuGtk::PopupMenuGtk):
     33        (WebCore::PopupMenuGtk::~PopupMenuGtk):
     34        (WebCore::PopupMenuGtk::show): Use GtkPopupMenu.
     35        (WebCore::PopupMenuGtk::hide): Ditto.
     36        (WebCore::PopupMenuGtk::menuItemActivated):
     37        (WebCore::PopupMenuGtk::menuUnmapped):
     38        * platform/gtk/PopupMenuGtk.h:
     39
    1402011-05-21  Dimitri Glazkov  <dglazkov@chromium.org>
    241
  • trunk/Source/WebCore/GNUmakefile.list.am

    r87780 r87930  
    37973797        Source/WebCore/platform/gtk/GtkPluginWidget.cpp \
    37983798        Source/WebCore/platform/gtk/GtkPluginWidget.h \
     3799        Source/WebCore/platform/gtk/GtkPopupMenu.cpp \
     3800        Source/WebCore/platform/gtk/GtkPopupMenu.h \
    37993801        Source/WebCore/platform/gtk/GtkVersioning.c \
    38003802        Source/WebCore/platform/gtk/GtkVersioning.h \
  • trunk/Source/WebCore/platform/gtk/GtkPopupMenu.cpp

    r87929 r87930  
    66 * Copyright (C) 2008 Collabora Ltd.
    77 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
    8  * Copyright (C) 2010 Igalia S.L.
     8 * Copyright (C) 2010-2011 Igalia S.L.
    99 *
    1010 * This library is free software; you can redistribute it and/or
     
    2626
    2727#include "config.h"
    28 #include "PopupMenuGtk.h"
    29 
    30 #include "FrameView.h"
     28#include "GtkPopupMenu.h"
     29
    3130#include "GOwnPtr.h"
    3231#include "GtkVersioning.h"
    33 #include "HostWindow.h"
    34 #include "PlatformString.h"
    35 #include <gdk/gdk.h>
    3632#include <gtk/gtk.h>
    3733#include <wtf/text/CString.h>
     
    4137static const uint32_t gSearchTimeoutMs = 1000;
    4238
    43 PopupMenuGtk::PopupMenuGtk(PopupMenuClient* client)
    44     : m_popupClient(client)
     39GtkPopupMenu::GtkPopupMenu()
     40    : m_popup(gtk_menu_new())
    4541    , m_previousKeyEventCharacter(0)
    4642    , m_currentlySelectedMenuItem(0)
    4743{
    48 }
    49 
    50 PopupMenuGtk::~PopupMenuGtk()
    51 {
    52     if (m_popup) {
    53         g_signal_handlers_disconnect_matched(m_popup.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
    54         hide();
    55     }
    56 }
    57 
    58 void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index)
    59 {
    60     ASSERT(client());
    61 
    62     if (!m_popup) {
    63         m_popup = GTK_MENU(gtk_menu_new());
    64         g_signal_connect(m_popup.get(), "unmap", G_CALLBACK(PopupMenuGtk::menuUnmapped), this);
    65         g_signal_connect(m_popup.get(), "key-press-event", G_CALLBACK(PopupMenuGtk::keyPressEventCallback), this);
    66     } else
    67         gtk_container_foreach(GTK_CONTAINER(m_popup.get()), reinterpret_cast<GtkCallback>(menuRemoveItem), this);
    68 
    69     int x = 0;
    70     int y = 0;
    71     GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(view->hostWindow()->platformPageClient()));
    72     if (window)
    73         gdk_window_get_origin(window, &x, &y);
    74     m_menuPosition = view->contentsToWindow(rect.location());
    75     m_menuPosition = IntPoint(m_menuPosition.x() + x, m_menuPosition.y() + y + rect.height());
    76     m_indexMap.clear();
    77 
    78     const int size = client()->listSize();
    79     for (int i = 0; i < size; ++i) {
    80         GtkWidget* item;
    81         if (client()->itemIsSeparator(i))
    82             item = gtk_separator_menu_item_new();
    83         else
    84             item = gtk_menu_item_new_with_label(client()->itemText(i).utf8().data());
    85 
    86         m_indexMap.add(item, i);
    87         g_signal_connect(item, "activate", G_CALLBACK(PopupMenuGtk::menuItemActivated), this);
    88         g_signal_connect(item, "select", G_CALLBACK(PopupMenuGtk::selectItemCallback), this);
    89 
    90         // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i)
    91         gtk_widget_set_sensitive(item, client()->itemIsEnabled(i));
    92         gtk_menu_shell_append(GTK_MENU_SHELL(m_popup.get()), item);
    93         gtk_widget_show(item);
    94     }
    95 
    96     gtk_menu_set_active(m_popup.get(), index);
    97 
    98 
    99     // The size calls are directly copied from gtkcombobox.c which is LGPL
     44    m_keyPressHandlerID = g_signal_connect(m_popup.get(), "key-press-event", G_CALLBACK(GtkPopupMenu::keyPressEventCallback), this);
     45}
     46
     47GtkPopupMenu::~GtkPopupMenu()
     48{
     49    g_signal_handler_disconnect(m_popup.get(), m_keyPressHandlerID);
     50}
     51
     52void GtkPopupMenu::clear()
     53{
     54    gtk_container_foreach(GTK_CONTAINER(m_popup.get()), reinterpret_cast<GtkCallback>(menuRemoveItem), this);
     55}
     56
     57void GtkPopupMenu::appendSeparator()
     58{
     59    GtkWidget* menuItem = gtk_separator_menu_item_new();
     60    gtk_menu_shell_append(GTK_MENU_SHELL(m_popup.get()), menuItem);
     61    gtk_widget_show(menuItem);
     62}
     63
     64void GtkPopupMenu::appendItem(GtkAction* action)
     65{
     66    GtkWidget* menuItem = gtk_action_create_menu_item(action);
     67    g_signal_connect(menuItem, "select", G_CALLBACK(GtkPopupMenu::selectItemCallback), this);
     68    gtk_menu_shell_append(GTK_MENU_SHELL(m_popup.get()), menuItem);
     69    gtk_widget_show(menuItem);
     70}
     71
     72void GtkPopupMenu::popUp(const IntSize& menuSize, const IntPoint& menuPosition, int itemCount, int selectedItem, const GdkEvent* event)
     73{
     74    resetTypeAheadFindState();
     75    m_menuPosition = menuPosition;
     76    gtk_menu_set_active(GTK_MENU(m_popup.get()), selectedItem);
     77
     78    // This approach follows the one in gtkcombobox.c.
    10079    GtkRequisition requisition;
    101     gtk_widget_set_size_request(GTK_WIDGET(m_popup.get()), -1, -1);
     80    gtk_widget_set_size_request(m_popup.get(), -1, -1);
    10281#ifdef GTK_API_VERSION_2
    103     gtk_widget_size_request(GTK_WIDGET(m_popup.get()), &requisition);
     82    gtk_widget_size_request(m_popup.get(), &requisition);
    10483#else
    105     gtk_widget_get_preferred_size(GTK_WIDGET(m_popup.get()), &requisition, 0);
     84    gtk_widget_get_preferred_size(m_popup.get(), &requisition, 0);
    10685#endif
    10786
    108     gtk_widget_set_size_request(GTK_WIDGET(m_popup.get()), std::max(rect.width(), requisition.width), -1);
     87    gtk_widget_set_size_request(m_popup.get(), std::max(menuSize.width(), requisition.width), -1);
    10988
    11089    GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get()));
    11190    GList* p = children;
    112     if (size) {
    113         for (int i = 0; i < size; i++) {
    114             if (i > index)
    115               break;
     91    if (itemCount) {
     92        for (int i = 0; i < itemCount; i++) {
     93            if (i > selectedItem)
     94                break;
    11695
    11796            GtkWidget* item = reinterpret_cast<GtkWidget*>(p->data);
     
    127106        }
    128107    } else {
    129         // Center vertically the empty popup in the combo box area
    130         m_menuPosition.setY(m_menuPosition.y() - rect.height() / 2);
    131     }
    132 
     108        // Center vertically the empty popup in the combo box area.
     109        m_menuPosition.setY(m_menuPosition.y() - menuSize.height() / 2);
     110    }
    133111    g_list_free(children);
    134     gtk_menu_popup(m_popup.get(), 0, 0, reinterpret_cast<GtkMenuPositionFunc>(menuPositionFunction), this, 0, gtk_get_current_event_time());
    135 }
    136 
    137 void PopupMenuGtk::hide()
    138 {
    139     ASSERT(m_popup);
    140     gtk_menu_popdown(m_popup.get());
    141 }
    142 
    143 void PopupMenuGtk::updateFromElement()
    144 {
    145     client()->setTextFromItem(client()->selectedIndex());
    146 }
    147 
    148 void PopupMenuGtk::disconnectClient()
    149 {
    150     m_popupClient = 0;
    151 }
    152 
    153 bool PopupMenuGtk::typeAheadFind(GdkEventKey* event)
     112
     113    guint button;
     114    guint32 activateTime;
     115    if (event) {
     116        button = event->type == GDK_BUTTON_PRESS ? event->button.button : 1;
     117        activateTime = gdk_event_get_time(event);
     118    } else {
     119        button = 1;
     120        activateTime = GDK_CURRENT_TIME;
     121    }
     122
     123#ifdef GTK_API_VERSION_2
     124    gtk_menu_popup(GTK_MENU(m_popup.get()), 0, 0, reinterpret_cast<GtkMenuPositionFunc>(menuPositionFunction), this, button, activateTime);
     125#else
     126    gtk_menu_popup_for_device(GTK_MENU(m_popup.get()), event ? gdk_event_get_device(event) : 0, 0, 0,
     127                              reinterpret_cast<GtkMenuPositionFunc>(menuPositionFunction), this, 0, button, activateTime);
     128#endif
     129}
     130
     131void GtkPopupMenu::popDown()
     132{
     133    gtk_menu_popdown(GTK_MENU(m_popup.get()));
     134    resetTypeAheadFindState();
     135}
     136
     137void GtkPopupMenu::menuRemoveItem(GtkWidget* widget, GtkPopupMenu* popupMenu)
     138{
     139    ASSERT(popupMenu->m_popup);
     140    gtk_container_remove(GTK_CONTAINER(popupMenu->m_popup.get()), widget);
     141}
     142
     143void GtkPopupMenu::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pushIn, GtkPopupMenu* popupMenu)
     144{
     145    *x = popupMenu->m_menuPosition.x();
     146    *y = popupMenu->m_menuPosition.y();
     147    *pushIn = true;
     148}
     149
     150void GtkPopupMenu::resetTypeAheadFindState()
     151{
     152    m_currentlySelectedMenuItem = 0;
     153    m_previousKeyEventCharacter = 0;
     154    m_currentSearchString = "";
     155}
     156
     157bool GtkPopupMenu::typeAheadFind(GdkEventKey* event)
    154158{
    155159    // If we were given a non-printable character just skip it.
    156160    gunichar unicodeCharacter = gdk_keyval_to_unicode(event->keyval);
    157     if (!unicodeCharacter) {
     161    if (!g_unichar_isprint(unicodeCharacter)) {
    158162        resetTypeAheadFindState();
    159163        return false;
     
    215219        if (!strncmp(searchStringWithCaseFolded.get(), itemText.get(), prefixLength)) {
    216220            gtk_menu_shell_select_item(GTK_MENU_SHELL(m_popup.get()), GTK_WIDGET(currentChild->data));
    217             return true;
     221            break;
    218222        }
    219223    } while (currentChild != firstChild);
    220224
     225    g_list_free(children);
    221226    return true;
    222227}
    223228
    224 void PopupMenuGtk::menuItemActivated(GtkMenuItem* item, PopupMenuGtk* that)
    225 {
    226     ASSERT(that->client());
    227     ASSERT(that->m_indexMap.contains(GTK_WIDGET(item)));
    228     that->client()->valueChanged(that->m_indexMap.get(GTK_WIDGET(item)));
    229 }
    230 
    231 void PopupMenuGtk::menuUnmapped(GtkWidget*, PopupMenuGtk* that)
    232 {
    233     ASSERT(that->client());
    234     that->resetTypeAheadFindState();
    235     that->client()->popupDidHide();
    236 }
    237 
    238 void PopupMenuGtk::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pushIn, PopupMenuGtk* that)
    239 {
    240     *x = that->m_menuPosition.x();
    241     *y = that->m_menuPosition.y();
    242     *pushIn = true;
    243 }
    244 
    245 void PopupMenuGtk::resetTypeAheadFindState()
    246 {
    247     m_currentlySelectedMenuItem = 0;
    248     m_previousKeyEventCharacter = 0;
    249     m_currentSearchString = "";
    250 }
    251 
    252 void PopupMenuGtk::menuRemoveItem(GtkWidget* widget, PopupMenuGtk* that)
    253 {
    254     ASSERT(that->m_popup);
    255     gtk_container_remove(GTK_CONTAINER(that->m_popup.get()), widget);
    256 }
    257 
    258 int PopupMenuGtk::selectItemCallback(GtkMenuItem* item, PopupMenuGtk* that)
    259 {
    260     that->m_currentlySelectedMenuItem = GTK_WIDGET(item);
    261     return FALSE;
    262 }
    263 
    264 int PopupMenuGtk::keyPressEventCallback(GtkWidget* widget, GdkEventKey* event, PopupMenuGtk* that)
    265 {
    266     return that->typeAheadFind(event);
    267 }
    268 
    269 }
    270 
     229void GtkPopupMenu::selectItemCallback(GtkMenuItem* item, GtkPopupMenu* popupMenu)
     230{
     231    popupMenu->m_currentlySelectedMenuItem = GTK_WIDGET(item);
     232}
     233
     234gboolean GtkPopupMenu::keyPressEventCallback(GtkWidget* widget, GdkEventKey* event, GtkPopupMenu* popupMenu)
     235{
     236    return popupMenu->typeAheadFind(event);
     237}
     238
     239} // namespace WebCore
  • trunk/Source/WebCore/platform/gtk/GtkPopupMenu.h

    r87929 r87930  
    11/*
    22 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3 * Copyright (C) 2011 Igalia S.L.
    34 *
    45 * This library is free software; you can redistribute it and/or
     
    1819 */
    1920
    20 #ifndef PopupMenuGtk_h
    21 #define PopupMenuGtk_h
     21#ifndef GtkPopupMenu_h
     22#define GtkPopupMenu_h
    2223
    2324#include "GRefPtrGtk.h"
    24 #include "IntRect.h"
    25 #include "PopupMenu.h"
    26 #include "PopupMenuClient.h"
    27 #include <wtf/HashMap.h>
    28 #include <wtf/PassRefPtr.h>
    29 #include <wtf/RefCounted.h>
     25#include "IntPoint.h"
     26#include "IntSize.h"
     27#include "PlatformString.h"
     28#include <wtf/FastAllocBase.h>
     29#include <wtf/Noncopyable.h>
     30#include <wtf/PassOwnPtr.h>
    3031
    3132typedef struct _GdkEventKey GdkEventKey;
     
    3334namespace WebCore {
    3435
    35 class FrameView;
    36 class Scrollbar;
     36class GtkPopupMenu {
     37    WTF_MAKE_NONCOPYABLE(GtkPopupMenu);
     38    WTF_MAKE_FAST_ALLOCATED;
    3739
    38 class PopupMenuGtk : public PopupMenu {
    3940public:
    40     PopupMenuGtk(PopupMenuClient*);
    41     ~PopupMenuGtk();
     41    static PassOwnPtr<GtkPopupMenu> create()
     42    {
     43        return adoptPtr(new GtkPopupMenu());
     44    }
    4245
    43     virtual void show(const IntRect&, FrameView*, int index);
    44     virtual void hide();
    45     virtual void updateFromElement();
    46     virtual void disconnectClient();
     46    ~GtkPopupMenu();
     47
     48    GtkWidget* platformMenu() const { return m_popup.get(); }
     49    void clear();
     50    void appendSeparator();
     51    void appendItem(GtkAction*);
     52    void popUp(const IntSize&, const IntPoint&, int itemsCount, int selectedItem, const GdkEvent*);
     53    void popDown();
     54
     55private:
     56    GtkPopupMenu();
     57
     58    void resetTypeAheadFindState();
    4759    bool typeAheadFind(GdkEventKey*);
    4860
    49 private:
    50     PopupMenuClient* client() const { return m_popupClient; }
    51     void resetTypeAheadFindState();
     61    static void menuItemActivated(GtkMenuItem*, GtkPopupMenu*);
     62    static void menuPositionFunction(GtkMenu*, gint*, gint*, gboolean*, GtkPopupMenu*);
     63    static void menuRemoveItem(GtkWidget*, GtkPopupMenu*);
     64    static void selectItemCallback(GtkMenuItem*, GtkPopupMenu*);
     65    static gboolean keyPressEventCallback(GtkWidget*, GdkEventKey*, GtkPopupMenu*);
    5266
    53     static void menuItemActivated(GtkMenuItem* item, PopupMenuGtk*);
    54     static void menuUnmapped(GtkWidget*, PopupMenuGtk*);
    55     static void menuPositionFunction(GtkMenu*, gint*, gint*, gboolean*, PopupMenuGtk*);
    56     static void menuRemoveItem(GtkWidget*, PopupMenuGtk*);
    57     static int selectItemCallback(GtkMenuItem*, PopupMenuGtk*);
    58     static int keyPressEventCallback(GtkWidget*, GdkEventKey*, PopupMenuGtk*);
    59 
    60     PopupMenuClient* m_popupClient;
     67    GRefPtr<GtkWidget> m_popup;
    6168    IntPoint m_menuPosition;
    62     GRefPtr<GtkMenu> m_popup;
    63     HashMap<GtkWidget*, int> m_indexMap;
    6469    String m_currentSearchString;
    6570    uint32_t m_previousKeyEventTimestamp;
    6671    unsigned int m_previousKeyEventCharacter;
    6772    GtkWidget* m_currentlySelectedMenuItem;
     73    unsigned int m_keyPressHandlerID;
    6874};
    6975
    7076}
    7177
    72 #endif // PopupMenuGtk_h
     78#endif // GtkPopupMenu_h
  • trunk/Source/WebCore/platform/gtk/PopupMenuGtk.cpp

    r73030 r87930  
    3030#include "FrameView.h"
    3131#include "GOwnPtr.h"
    32 #include "GtkVersioning.h"
    3332#include "HostWindow.h"
    34 #include "PlatformString.h"
    35 #include <gdk/gdk.h>
    3633#include <gtk/gtk.h>
    3734#include <wtf/text/CString.h>
     
    4340PopupMenuGtk::PopupMenuGtk(PopupMenuClient* client)
    4441    : m_popupClient(client)
    45     , m_previousKeyEventCharacter(0)
    46     , m_currentlySelectedMenuItem(0)
    4742{
    4843}
     
    5146{
    5247    if (m_popup) {
    53         g_signal_handlers_disconnect_matched(m_popup.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
     48        g_signal_handlers_disconnect_matched(m_popup->platformMenu(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
    5449        hide();
    5550    }
     51}
     52
     53GtkAction* PopupMenuGtk::createGtkActionForMenuItem(int itemIndex)
     54{
     55    GOwnPtr<char> actionName(g_strdup_printf("popup-menu-action-%d", itemIndex));
     56    GtkAction* action = gtk_action_new(actionName.get(), client()->itemText(itemIndex).utf8().data(), 0, 0);
     57    g_object_set_data(G_OBJECT(action), "popup-menu-action-index", GINT_TO_POINTER(itemIndex));
     58    g_signal_connect(action, "activate", G_CALLBACK(menuItemActivated), this);
     59    // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i)
     60    gtk_action_set_sensitive(action, client()->itemIsEnabled(itemIndex));
     61
     62    return action;
    5663}
    5764
     
    6168
    6269    if (!m_popup) {
    63         m_popup = GTK_MENU(gtk_menu_new());
    64         g_signal_connect(m_popup.get(), "unmap", G_CALLBACK(PopupMenuGtk::menuUnmapped), this);
    65         g_signal_connect(m_popup.get(), "key-press-event", G_CALLBACK(PopupMenuGtk::keyPressEventCallback), this);
     70        m_popup = GtkPopupMenu::create();
     71        g_signal_connect(m_popup->platformMenu(), "unmap", G_CALLBACK(PopupMenuGtk::menuUnmapped), this);
    6672    } else
    67         gtk_container_foreach(GTK_CONTAINER(m_popup.get()), reinterpret_cast<GtkCallback>(menuRemoveItem), this);
     73        m_popup->clear();
     74
     75    const int size = client()->listSize();
     76    for (int i = 0; i < size; ++i) {
     77        if (client()->itemIsSeparator(i))
     78            m_popup->appendSeparator();
     79        else {
     80            GRefPtr<GtkAction> action = adoptGRef(createGtkActionForMenuItem(i));
     81            m_popup->appendItem(action.get());
     82        }
     83    }
    6884
    6985    int x = 0;
     
    7288    if (window)
    7389        gdk_window_get_origin(window, &x, &y);
    74     m_menuPosition = view->contentsToWindow(rect.location());
    75     m_menuPosition = IntPoint(m_menuPosition.x() + x, m_menuPosition.y() + y + rect.height());
    76     m_indexMap.clear();
     90    IntPoint menuPosition(view->contentsToWindow(rect.location()));
     91    menuPosition.move(x, y + rect.height());
    7792
    78     const int size = client()->listSize();
    79     for (int i = 0; i < size; ++i) {
    80         GtkWidget* item;
    81         if (client()->itemIsSeparator(i))
    82             item = gtk_separator_menu_item_new();
    83         else
    84             item = gtk_menu_item_new_with_label(client()->itemText(i).utf8().data());
    85 
    86         m_indexMap.add(item, i);
    87         g_signal_connect(item, "activate", G_CALLBACK(PopupMenuGtk::menuItemActivated), this);
    88         g_signal_connect(item, "select", G_CALLBACK(PopupMenuGtk::selectItemCallback), this);
    89 
    90         // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i)
    91         gtk_widget_set_sensitive(item, client()->itemIsEnabled(i));
    92         gtk_menu_shell_append(GTK_MENU_SHELL(m_popup.get()), item);
    93         gtk_widget_show(item);
    94     }
    95 
    96     gtk_menu_set_active(m_popup.get(), index);
    97 
    98 
    99     // The size calls are directly copied from gtkcombobox.c which is LGPL
    100     GtkRequisition requisition;
    101     gtk_widget_set_size_request(GTK_WIDGET(m_popup.get()), -1, -1);
    102 #ifdef GTK_API_VERSION_2
    103     gtk_widget_size_request(GTK_WIDGET(m_popup.get()), &requisition);
    104 #else
    105     gtk_widget_get_preferred_size(GTK_WIDGET(m_popup.get()), &requisition, 0);
    106 #endif
    107 
    108     gtk_widget_set_size_request(GTK_WIDGET(m_popup.get()), std::max(rect.width(), requisition.width), -1);
    109 
    110     GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get()));
    111     GList* p = children;
    112     if (size) {
    113         for (int i = 0; i < size; i++) {
    114             if (i > index)
    115               break;
    116 
    117             GtkWidget* item = reinterpret_cast<GtkWidget*>(p->data);
    118             GtkRequisition itemRequisition;
    119 #ifdef GTK_API_VERSION_2
    120             gtk_widget_get_child_requisition(item, &itemRequisition);
    121 #else
    122             gtk_widget_get_preferred_size(item, &itemRequisition, 0);
    123 #endif
    124             m_menuPosition.setY(m_menuPosition.y() - itemRequisition.height);
    125 
    126             p = g_list_next(p);
    127         }
    128     } else {
    129         // Center vertically the empty popup in the combo box area
    130         m_menuPosition.setY(m_menuPosition.y() - rect.height() / 2);
    131     }
    132 
    133     g_list_free(children);
    134     gtk_menu_popup(m_popup.get(), 0, 0, reinterpret_cast<GtkMenuPositionFunc>(menuPositionFunction), this, 0, gtk_get_current_event_time());
     93    m_popup->popUp(rect.size(), menuPosition, size, index, gtk_get_current_event());
    13594}
    13695
     
    13897{
    13998    ASSERT(m_popup);
    140     gtk_menu_popdown(m_popup.get());
     99    m_popup->popDown();
    141100}
    142101
     
    151110}
    152111
    153 bool PopupMenuGtk::typeAheadFind(GdkEventKey* event)
    154 {
    155     // If we were given a non-printable character just skip it.
    156     gunichar unicodeCharacter = gdk_keyval_to_unicode(event->keyval);
    157     if (!unicodeCharacter) {
    158         resetTypeAheadFindState();
    159         return false;
    160     }
    161 
    162     glong charactersWritten;
    163     GOwnPtr<gunichar2> utf16String(g_ucs4_to_utf16(&unicodeCharacter, 1, 0, &charactersWritten, 0));
    164     if (!utf16String) {
    165         resetTypeAheadFindState();
    166         return false;
    167     }
    168 
    169     // If the character is the same as the last character, the user is probably trying to
    170     // cycle through the menulist entries. This matches the WebCore behavior for collapsed
    171     // menulists.
    172     bool repeatingCharacter = unicodeCharacter != m_previousKeyEventCharacter;
    173     if (event->time - m_previousKeyEventTimestamp > gSearchTimeoutMs)
    174         m_currentSearchString = String(static_cast<UChar*>(utf16String.get()), charactersWritten);
    175     else if (repeatingCharacter)
    176         m_currentSearchString.append(String(static_cast<UChar*>(utf16String.get()), charactersWritten));
    177 
    178     m_previousKeyEventTimestamp = event->time;
    179     m_previousKeyEventCharacter = unicodeCharacter;
    180 
    181     // Like the Chromium port, we case fold before searching, because
    182     // strncmp does not handle non-ASCII characters.
    183     GOwnPtr<gchar> searchStringWithCaseFolded(g_utf8_casefold(m_currentSearchString.utf8().data(), -1));
    184     size_t prefixLength = strlen(searchStringWithCaseFolded.get());
    185 
    186     GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get()));
    187     if (!children)
    188         return true;
    189 
    190     // If a menu item has already been selected, start searching from the current
    191     // item down the list. This will make multiple key presses of the same character
    192     // advance the selection.
    193     GList* currentChild = children;
    194     if (m_currentlySelectedMenuItem) {
    195         currentChild = g_list_find(children, m_currentlySelectedMenuItem);
    196         if (!currentChild) {
    197             m_currentlySelectedMenuItem = 0;
    198             currentChild = children;
    199         }
    200 
    201         // Repeating characters should iterate.
    202         if (repeatingCharacter) {
    203             if (GList* nextChild = g_list_next(currentChild))
    204                 currentChild = nextChild;
    205         }
    206     }
    207 
    208     GList* firstChild = currentChild;
    209     do {
    210         currentChild = g_list_next(currentChild);
    211         if (!currentChild)
    212             currentChild = children;
    213 
    214         GOwnPtr<gchar> itemText(g_utf8_casefold(gtk_menu_item_get_label(GTK_MENU_ITEM(currentChild->data)), -1));
    215         if (!strncmp(searchStringWithCaseFolded.get(), itemText.get(), prefixLength)) {
    216             gtk_menu_shell_select_item(GTK_MENU_SHELL(m_popup.get()), GTK_WIDGET(currentChild->data));
    217             return true;
    218         }
    219     } while (currentChild != firstChild);
    220 
    221     return true;
    222 }
    223 
    224 void PopupMenuGtk::menuItemActivated(GtkMenuItem* item, PopupMenuGtk* that)
     112void PopupMenuGtk::menuItemActivated(GtkAction* action, PopupMenuGtk* that)
    225113{
    226114    ASSERT(that->client());
    227     ASSERT(that->m_indexMap.contains(GTK_WIDGET(item)));
    228     that->client()->valueChanged(that->m_indexMap.get(GTK_WIDGET(item)));
     115    that->client()->valueChanged(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "popup-menu-action-index")));
    229116}
    230117
     
    232119{
    233120    ASSERT(that->client());
    234     that->resetTypeAheadFindState();
    235121    that->client()->popupDidHide();
    236 }
    237 
    238 void PopupMenuGtk::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pushIn, PopupMenuGtk* that)
    239 {
    240     *x = that->m_menuPosition.x();
    241     *y = that->m_menuPosition.y();
    242     *pushIn = true;
    243 }
    244 
    245 void PopupMenuGtk::resetTypeAheadFindState()
    246 {
    247     m_currentlySelectedMenuItem = 0;
    248     m_previousKeyEventCharacter = 0;
    249     m_currentSearchString = "";
    250 }
    251 
    252 void PopupMenuGtk::menuRemoveItem(GtkWidget* widget, PopupMenuGtk* that)
    253 {
    254     ASSERT(that->m_popup);
    255     gtk_container_remove(GTK_CONTAINER(that->m_popup.get()), widget);
    256 }
    257 
    258 int PopupMenuGtk::selectItemCallback(GtkMenuItem* item, PopupMenuGtk* that)
    259 {
    260     that->m_currentlySelectedMenuItem = GTK_WIDGET(item);
    261     return FALSE;
    262 }
    263 
    264 int PopupMenuGtk::keyPressEventCallback(GtkWidget* widget, GdkEventKey* event, PopupMenuGtk* that)
    265 {
    266     return that->typeAheadFind(event);
    267122}
    268123
  • trunk/Source/WebCore/platform/gtk/PopupMenuGtk.h

    r75009 r87930  
    2121#define PopupMenuGtk_h
    2222
    23 #include "GRefPtrGtk.h"
     23#include "GtkPopupMenu.h"
    2424#include "IntRect.h"
    2525#include "PopupMenu.h"
    2626#include "PopupMenuClient.h"
    27 #include <wtf/HashMap.h>
    28 #include <wtf/PassRefPtr.h>
    29 #include <wtf/RefCounted.h>
    30 
    31 typedef struct _GdkEventKey GdkEventKey;
    3227
    3328namespace WebCore {
     
    4540    virtual void updateFromElement();
    4641    virtual void disconnectClient();
    47     bool typeAheadFind(GdkEventKey*);
    4842
    4943private:
    5044    PopupMenuClient* client() const { return m_popupClient; }
    51     void resetTypeAheadFindState();
     45    GtkAction* createGtkActionForMenuItem(int itemIndex);
    5246
    53     static void menuItemActivated(GtkMenuItem* item, PopupMenuGtk*);
    5447    static void menuUnmapped(GtkWidget*, PopupMenuGtk*);
    55     static void menuPositionFunction(GtkMenu*, gint*, gint*, gboolean*, PopupMenuGtk*);
    56     static void menuRemoveItem(GtkWidget*, PopupMenuGtk*);
    57     static int selectItemCallback(GtkMenuItem*, PopupMenuGtk*);
    58     static int keyPressEventCallback(GtkWidget*, GdkEventKey*, PopupMenuGtk*);
     48    static void menuItemActivated(GtkAction*, PopupMenuGtk*);
    5949
    6050    PopupMenuClient* m_popupClient;
    61     IntPoint m_menuPosition;
    62     GRefPtr<GtkMenu> m_popup;
    63     HashMap<GtkWidget*, int> m_indexMap;
    64     String m_currentSearchString;
    65     uint32_t m_previousKeyEventTimestamp;
    66     unsigned int m_previousKeyEventCharacter;
    67     GtkWidget* m_currentlySelectedMenuItem;
     51    OwnPtr<GtkPopupMenu> m_popup;
    6852};
    6953
  • trunk/Source/WebKit2/ChangeLog

    r87857 r87930  
     12011-06-02  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        Reviewed by Martin Robinson.
     4
     5        [GTK] Implement popup menus in Webkit2
     6        https://bugs.webkit.org/show_bug.cgi?id=61854
     7
     8        * GNUmakefile.am: Add new files to compilation.
     9        * UIProcess/API/gtk/PageClientImpl.cpp:
     10        (WebKit::PageClientImpl::createPopupMenuProxy): Create a new
     11        WebPopupMenuProxy.
     12        * UIProcess/gtk/WebPopupMenuProxyGtk.cpp: Added.
     13        (WebKit::WebPopupMenuProxyGtk::WebPopupMenuProxyGtk):
     14        (WebKit::WebPopupMenuProxyGtk::~WebPopupMenuProxyGtk):
     15        (WebKit::WebPopupMenuProxyGtk::showPopupMenu):
     16        (WebKit::WebPopupMenuProxyGtk::hidePopupMenu):
     17        (WebKit::WebPopupMenuProxyGtk::shutdownRunLoop):
     18        (WebKit::WebPopupMenuProxyGtk::menuItemActivated):
     19        (WebKit::WebPopupMenuProxyGtk::menuUnmapped):
     20        * UIProcess/gtk/WebPopupMenuProxyGtk.h: Added.
     21        (WebKit::WebPopupMenuProxyGtk::create):
     22        (WebKit::WebPopupMenuProxyGtk::setActiveItem):
     23
    1242011-06-01  Sam Weinig  <sam@webkit.org>
    225
  • trunk/Source/WebKit2/GNUmakefile.am

    r87058 r87930  
    395395        Source/WebKit2/UIProcess/gtk/WebInspectorGtk.cpp \
    396396        Source/WebKit2/UIProcess/gtk/WebPageProxyGtk.cpp \
     397        Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp \
     398        Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h \
    397399        Source/WebKit2/UIProcess/gtk/WebPreferencesGtk.cpp \
    398400        Source/WebKit2/UIProcess/Launcher/gtk/ProcessLauncherGtk.cpp \
  • trunk/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp

    r87689 r87930  
    3838#include "WebKitWebViewBasePrivate.h"
    3939#include "WebPageProxy.h"
     40#include "WebPopupMenuProxyGtk.h"
    4041#include <WebCore/GtkUtilities.h>
    4142#include <wtf/text/WTFString.h>
     
    205206}
    206207
    207 PassRefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy*)
    208 {
    209     notImplemented();
    210     return 0;
     208PassRefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy* page)
     209{
     210    return WebPopupMenuProxyGtk::create(m_viewWidget, page);
    211211}
    212212
Note: See TracChangeset for help on using the changeset viewer.