18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * This file is part of the popup menu implementation for <select> elements in WebCore.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2008 Collabora Ltd.
7db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
8f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch * Copyright (C) 2010 Igalia S.L.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * This library is free software; you can redistribute it and/or
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modify it under the terms of the GNU Library General Public
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * License as published by the Free Software Foundation; either
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * version 2 of the License, or (at your option) any later version.
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * This library is distributed in the hope that it will be useful,
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * but WITHOUT ANY WARRANTY; without even the implied warranty of
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Library General Public License for more details.
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * You should have received a copy of the GNU Library General Public License
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * along with this library; see the file COPYING.LIB.  If not, write to
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Boston, MA 02110-1301, USA.
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
28db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block#include "PopupMenuGtk.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FrameView.h"
31f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include "GOwnPtr.h"
32545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch#include "GtkVersioning.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HostWindow.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "PlatformString.h"
35f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include <gdk/gdk.h>
36d06194330da2bb8da887d2e1adeacb3a5c1504b2Steve Block#include <gtk/gtk.h>
37f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include <wtf/text/CString.h>
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
41f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochstatic const uint32_t gSearchTimeoutMs = 1000;
42f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
43db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve BlockPopupMenuGtk::PopupMenuGtk(PopupMenuClient* client)
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    : m_popupClient(client)
45f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    , m_previousKeyEventCharacter(0)
46f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    , m_currentlySelectedMenuItem(0)
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
50db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve BlockPopupMenuGtk::~PopupMenuGtk()
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (m_popup) {
53d0825bca7fe65beaee391d30da42e937db621564Steve Block        g_signal_handlers_disconnect_matched(m_popup.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        hide();
555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
58db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockvoid PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index)
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(client());
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_popup) {
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_popup = GTK_MENU(gtk_menu_new());
64f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        g_signal_connect(m_popup.get(), "unmap", G_CALLBACK(PopupMenuGtk::menuUnmapped), this);
65f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        g_signal_connect(m_popup.get(), "key-press-event", G_CALLBACK(PopupMenuGtk::keyPressEventCallback), this);
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else
67d0825bca7fe65beaee391d30da42e937db621564Steve Block        gtk_container_foreach(GTK_CONTAINER(m_popup.get()), reinterpret_cast<GtkCallback>(menuRemoveItem), this);
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
69f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    int x = 0;
70f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    int y = 0;
71f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(view->hostWindow()->platformPageClient()));
72f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (window)
73f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        gdk_window_get_origin(window, &x, &y);
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_menuPosition = view->contentsToWindow(rect.location());
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_menuPosition = IntPoint(m_menuPosition.x() + x, m_menuPosition.y() + y + rect.height());
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_indexMap.clear();
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const int size = client()->listSize();
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 0; i < size; ++i) {
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        GtkWidget* item;
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (client()->itemIsSeparator(i))
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            item = gtk_separator_menu_item_new();
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            item = gtk_menu_item_new_with_label(client()->itemText(i).utf8().data());
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_indexMap.add(item, i);
87f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        g_signal_connect(item, "activate", G_CALLBACK(PopupMenuGtk::menuItemActivated), this);
88f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        g_signal_connect(item, "select", G_CALLBACK(PopupMenuGtk::selectItemCallback), this);
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i)
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        gtk_widget_set_sensitive(item, client()->itemIsEnabled(i));
92d0825bca7fe65beaee391d30da42e937db621564Steve Block        gtk_menu_shell_append(GTK_MENU_SHELL(m_popup.get()), item);
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        gtk_widget_show(item);
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
96d0825bca7fe65beaee391d30da42e937db621564Steve Block    gtk_menu_set_active(m_popup.get(), index);
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // The size calls are directly copied from gtkcombobox.c which is LGPL
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    GtkRequisition requisition;
101d0825bca7fe65beaee391d30da42e937db621564Steve Block    gtk_widget_set_size_request(GTK_WIDGET(m_popup.get()), -1, -1);
10268513a70bcd92384395513322f1b801e7bf9c729Steve Block#ifdef GTK_API_VERSION_2
103d0825bca7fe65beaee391d30da42e937db621564Steve Block    gtk_widget_size_request(GTK_WIDGET(m_popup.get()), &requisition);
10468513a70bcd92384395513322f1b801e7bf9c729Steve Block#else
105a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    gtk_widget_get_preferred_size(GTK_WIDGET(m_popup.get()), &requisition, 0);
10668513a70bcd92384395513322f1b801e7bf9c729Steve Block#endif
10768513a70bcd92384395513322f1b801e7bf9c729Steve Block
108d0825bca7fe65beaee391d30da42e937db621564Steve Block    gtk_widget_set_size_request(GTK_WIDGET(m_popup.get()), std::max(rect.width(), requisition.width), -1);
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get()));
11106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    GList* p = children;
11228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (size) {
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        for (int i = 0; i < size; i++) {
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (i > index)
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project              break;
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            GtkWidget* item = reinterpret_cast<GtkWidget*>(p->data);
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            GtkRequisition itemRequisition;
11968513a70bcd92384395513322f1b801e7bf9c729Steve Block#ifdef GTK_API_VERSION_2
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            gtk_widget_get_child_requisition(item, &itemRequisition);
12168513a70bcd92384395513322f1b801e7bf9c729Steve Block#else
122a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            gtk_widget_get_preferred_size(item, &itemRequisition, 0);
12368513a70bcd92384395513322f1b801e7bf9c729Steve Block#endif
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_menuPosition.setY(m_menuPosition.y() - itemRequisition.height);
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            p = g_list_next(p);
12728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        }
12828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    } else {
12928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        // Center vertically the empty popup in the combo box area
13028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        m_menuPosition.setY(m_menuPosition.y() - rect.height() / 2);
13128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    }
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    g_list_free(children);
134d0825bca7fe65beaee391d30da42e937db621564Steve Block    gtk_menu_popup(m_popup.get(), 0, 0, reinterpret_cast<GtkMenuPositionFunc>(menuPositionFunction), this, 0, gtk_get_current_event_time());
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
137db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockvoid PopupMenuGtk::hide()
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(m_popup);
140d0825bca7fe65beaee391d30da42e937db621564Steve Block    gtk_menu_popdown(m_popup.get());
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
143db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockvoid PopupMenuGtk::updateFromElement()
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    client()->setTextFromItem(client()->selectedIndex());
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
148db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockvoid PopupMenuGtk::disconnectClient()
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
150db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    m_popupClient = 0;
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
153f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochbool PopupMenuGtk::typeAheadFind(GdkEventKey* event)
154f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{
155f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    // If we were given a non-printable character just skip it.
156f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    gunichar unicodeCharacter = gdk_keyval_to_unicode(event->keyval);
157f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (!unicodeCharacter) {
158f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        resetTypeAheadFindState();
159f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        return false;
160f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    }
161f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
162f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    glong charactersWritten;
163f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    GOwnPtr<gunichar2> utf16String(g_ucs4_to_utf16(&unicodeCharacter, 1, 0, &charactersWritten, 0));
164f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (!utf16String) {
165f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        resetTypeAheadFindState();
166f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        return false;
167f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    }
168f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
169f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    // If the character is the same as the last character, the user is probably trying to
170f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    // cycle through the menulist entries. This matches the WebCore behavior for collapsed
171f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    // menulists.
172f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    bool repeatingCharacter = unicodeCharacter != m_previousKeyEventCharacter;
173f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (event->time - m_previousKeyEventTimestamp > gSearchTimeoutMs)
174f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        m_currentSearchString = String(static_cast<UChar*>(utf16String.get()), charactersWritten);
175f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    else if (repeatingCharacter)
176f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        m_currentSearchString.append(String(static_cast<UChar*>(utf16String.get()), charactersWritten));
177f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
178f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    m_previousKeyEventTimestamp = event->time;
179f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    m_previousKeyEventCharacter = unicodeCharacter;
180f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
181f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    // Like the Chromium port, we case fold before searching, because
182f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    // strncmp does not handle non-ASCII characters.
183f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    GOwnPtr<gchar> searchStringWithCaseFolded(g_utf8_casefold(m_currentSearchString.utf8().data(), -1));
184f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    size_t prefixLength = strlen(searchStringWithCaseFolded.get());
185f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
186f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get()));
187f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (!children)
188f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        return true;
189f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
190f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    // If a menu item has already been selected, start searching from the current
191f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    // item down the list. This will make multiple key presses of the same character
192f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    // advance the selection.
193f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    GList* currentChild = children;
194f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (m_currentlySelectedMenuItem) {
195f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        currentChild = g_list_find(children, m_currentlySelectedMenuItem);
196f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if (!currentChild) {
197f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            m_currentlySelectedMenuItem = 0;
198f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            currentChild = children;
199f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        }
200f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
201f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        // Repeating characters should iterate.
202f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if (repeatingCharacter) {
203f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            if (GList* nextChild = g_list_next(currentChild))
204f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                currentChild = nextChild;
205f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        }
206f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    }
207f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
208f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    GList* firstChild = currentChild;
209f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    do {
210f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        currentChild = g_list_next(currentChild);
211f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if (!currentChild)
212f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            currentChild = children;
213f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
214f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        GOwnPtr<gchar> itemText(g_utf8_casefold(gtk_menu_item_get_label(GTK_MENU_ITEM(currentChild->data)), -1));
215f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if (!strncmp(searchStringWithCaseFolded.get(), itemText.get(), prefixLength)) {
216f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            gtk_menu_shell_select_item(GTK_MENU_SHELL(m_popup.get()), GTK_WIDGET(currentChild->data));
217f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            return true;
218f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        }
219f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    } while (currentChild != firstChild);
220f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
221f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    return true;
222f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch}
223f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
224db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockvoid PopupMenuGtk::menuItemActivated(GtkMenuItem* item, PopupMenuGtk* that)
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(that->client());
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(that->m_indexMap.contains(GTK_WIDGET(item)));
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    that->client()->valueChanged(that->m_indexMap.get(GTK_WIDGET(item)));
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
231db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockvoid PopupMenuGtk::menuUnmapped(GtkWidget*, PopupMenuGtk* that)
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(that->client());
234f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    that->resetTypeAheadFindState();
235231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    that->client()->popupDidHide();
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
238db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockvoid PopupMenuGtk::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pushIn, PopupMenuGtk* that)
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *x = that->m_menuPosition.x();
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *y = that->m_menuPosition.y();
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *pushIn = true;
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
245f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid PopupMenuGtk::resetTypeAheadFindState()
246f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{
247f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    m_currentlySelectedMenuItem = 0;
248f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    m_previousKeyEventCharacter = 0;
249f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    m_currentSearchString = "";
250f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch}
251f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
252db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockvoid PopupMenuGtk::menuRemoveItem(GtkWidget* widget, PopupMenuGtk* that)
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(that->m_popup);
255d0825bca7fe65beaee391d30da42e937db621564Steve Block    gtk_container_remove(GTK_CONTAINER(that->m_popup.get()), widget);
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
258f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochint PopupMenuGtk::selectItemCallback(GtkMenuItem* item, PopupMenuGtk* that)
259f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{
260f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    that->m_currentlySelectedMenuItem = GTK_WIDGET(item);
261f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    return FALSE;
262f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch}
263f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
264f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochint PopupMenuGtk::keyPressEventCallback(GtkWidget* widget, GdkEventKey* event, PopupMenuGtk* that)
265f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{
266f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    return that->typeAheadFind(event);
267f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch}
268f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
271