Changeset 73025 in webkit


Ignore:
Timestamp:
Dec 1, 2010 8:46:39 AM (13 years ago)
Author:
Martin Robinson
Message:

2010-12-01 Martin Robinson <mrobinson@igalia.com>

Reviewed by Xan Lopez.

[Gtk] Open menulists should support typeahead find
https://bugs.webkit.org/show_bug.cgi?id=27443

Added a GTK+-specific layout test to track typeahead find state.

  • platform/gtk/fast/forms/menulist-typeahead-find-expected.txt: Added.
  • platform/gtk/fast/forms/menulist-typeahead-find.html: Added.

2010-12-01 Apelete Seketeli <apelete@seketeli.org> and Martin Robinson <mrobinson@igalia.com>

Reviewed by Xan Lopez.

[Gtk] Open menulists should support typeahead find
https://bugs.webkit.org/show_bug.cgi?id=27443

Added typeahead find support for open GTK+ menulists.

Test: platform/gtk/fast/forms/menulist-typeahead-find.html

  • platform/gtk/PopupMenuGtk.cpp: (WebCore::PopupMenuGtk::PopupMenuGtk): Initialize new members. (WebCore::PopupMenuGtk::show): Track currently selected menu item via a signal handler. (WebCore::PopupMenuGtk::typeAheadFind): Added. (WebCore::PopupMenuGtk::menuUnmapped): Reset typeahead find state when menu is unmapped. (WebCore::PopupMenuGtk::resetTypeAheadFindState): Added. (WebCore::PopupMenuGtk::selectItemCallback): Added. (WebCore::PopupMenuGtk::keyPressEventCallback): Added.
  • platform/gtk/PopupMenuGtk.h: Added new members to track typeahead find state.
Location:
trunk
Files:
2 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r73022 r73025  
     12010-12-01  Martin Robinson  <mrobinson@igalia.com>
     2
     3        Reviewed by Xan Lopez.
     4
     5        [Gtk] Open menulists should support typeahead find
     6        https://bugs.webkit.org/show_bug.cgi?id=27443
     7
     8        Added a GTK+-specific layout test to track typeahead find state.
     9
     10        * platform/gtk/fast/forms/menulist-typeahead-find-expected.txt: Added.
     11        * platform/gtk/fast/forms/menulist-typeahead-find.html: Added.
     12
    1132010-12-01  Martin Robinson  <mrobinson@igalia.com>
    214
  • trunk/WebCore/ChangeLog

    r73024 r73025  
     12010-12-01  Apelete Seketeli  <apelete@seketeli.org> and Martin Robinson  <mrobinson@igalia.com>
     2
     3        Reviewed by Xan Lopez.
     4
     5        [Gtk] Open menulists should support typeahead find
     6        https://bugs.webkit.org/show_bug.cgi?id=27443
     7
     8        Added typeahead find support for open GTK+ menulists.
     9
     10        Test: platform/gtk/fast/forms/menulist-typeahead-find.html
     11
     12        * platform/gtk/PopupMenuGtk.cpp:
     13        (WebCore::PopupMenuGtk::PopupMenuGtk): Initialize new members.
     14        (WebCore::PopupMenuGtk::show): Track currently selected menu item
     15        via a signal handler.
     16        (WebCore::PopupMenuGtk::typeAheadFind): Added.
     17        (WebCore::PopupMenuGtk::menuUnmapped): Reset typeahead find state
     18        when menu is unmapped.
     19        (WebCore::PopupMenuGtk::resetTypeAheadFindState): Added.
     20        (WebCore::PopupMenuGtk::selectItemCallback): Added.
     21        (WebCore::PopupMenuGtk::keyPressEventCallback): Added.
     22        * platform/gtk/PopupMenuGtk.h: Added new members to track typeahead
     23        find state.
     24
    1252010-12-01  Nikolas Zimmermann  <nzimmermann@rim.com>
    226
  • trunk/WebCore/platform/gtk/PopupMenuGtk.cpp

    r72958 r73025  
    66 * Copyright (C) 2008 Collabora Ltd.
    77 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     8 * Copyright (C) 2010 Igalia S.L.
    89 *
    910 * This library is free software; you can redistribute it and/or
     
    2829
    2930#include "FrameView.h"
     31#include "GOwnPtr.h"
    3032#include "GtkVersioning.h"
    3133#include "HostWindow.h"
    3234#include "PlatformString.h"
     35#include <gdk/gdk.h>
     36#include <gtk/gtk.h>
    3337#include <wtf/text/CString.h>
    34 #include <gtk/gtk.h>
    3538
    3639namespace WebCore {
     40
     41static const uint32_t gSearchTimeoutMs = 1000;
    3742
    3843PopupMenuGtk::PopupMenuGtk(PopupMenuClient* client)
    3944    : m_popupClient(client)
     45    , m_previousKeyEventCharacter(0)
     46    , m_currentlySelectedMenuItem(0)
    4047{
    4148}
     
    5562    if (!m_popup) {
    5663        m_popup = GTK_MENU(gtk_menu_new());
    57         g_signal_connect(m_popup.get(), "unmap", G_CALLBACK(menuUnmapped), this);
     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);
    5866    } else
    5967        gtk_container_foreach(GTK_CONTAINER(m_popup.get()), reinterpret_cast<GtkCallback>(menuRemoveItem), this);
     
    7785
    7886        m_indexMap.add(item, i);
    79         g_signal_connect(item, "activate", G_CALLBACK(menuItemActivated), this);
     87        g_signal_connect(item, "activate", G_CALLBACK(PopupMenuGtk::menuItemActivated), this);
     88        g_signal_connect(item, "select", G_CALLBACK(PopupMenuGtk::selectItemCallback), this);
    8089
    8190        // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i)
     
    142151}
    143152
     153bool 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.     GList* currentChild = children;
     193    if (m_currentlySelectedMenuItem) {
     194        currentChild = g_list_find(children, m_currentlySelectedMenuItem);
     195        if (!currentChild) {
     196            m_currentlySelectedMenuItem = 0;
     197            currentChild = children;
     198        }
     199
     200        // Repeating characters should iterate.
     201        if (repeatingCharacter) {
     202            if (GList* nextChild = g_list_next(currentChild))
     203                currentChild = nextChild;
     204        }
     205    }
     206
     207    GList* firstChild = currentChild;
     208    do {
     209        currentChild = g_list_next(currentChild);
     210        if (!currentChild)
     211            currentChild = children;
     212
     213        GOwnPtr<gchar> itemText(g_utf8_casefold(gtk_menu_item_get_label(GTK_MENU_ITEM(currentChild->data)), -1));
     214        if (!strncmp(searchStringWithCaseFolded.get(), itemText.get(), prefixLength)) {
     215            gtk_menu_shell_select_item(GTK_MENU_SHELL(m_popup.get()), GTK_WIDGET(currentChild->data));
     216            return true;
     217        }
     218    } while (currentChild != firstChild);
     219
     220    return true;
     221}
     222
    144223void PopupMenuGtk::menuItemActivated(GtkMenuItem* item, PopupMenuGtk* that)
    145224{
     
    152231{
    153232    ASSERT(that->client());
     233    that->resetTypeAheadFindState();
    154234    that->client()->popupDidHide();
    155235}
     
    162242}
    163243
     244void PopupMenuGtk::resetTypeAheadFindState()
     245{
     246    m_currentlySelectedMenuItem = 0;
     247    m_previousKeyEventCharacter = 0;
     248    m_currentSearchString = "";
     249}
     250
    164251void PopupMenuGtk::menuRemoveItem(GtkWidget* widget, PopupMenuGtk* that)
    165252{
     
    168255}
    169256
    170 }
    171 
     257int PopupMenuGtk::selectItemCallback(GtkMenuItem* item, PopupMenuGtk* that)
     258{
     259    that->m_currentlySelectedMenuItem = GTK_WIDGET(item);
     260    return FALSE;
     261}
     262
     263int PopupMenuGtk::keyPressEventCallback(GtkWidget* widget, GdkEventKey* event, PopupMenuGtk* that)
     264{
     265    return that->typeAheadFind(event);
     266}
     267
     268}
     269
  • trunk/WebCore/platform/gtk/PopupMenuGtk.h

    r66531 r73025  
    2525#include "PopupMenu.h"
    2626#include "PopupMenuClient.h"
    27 #include <glib.h>
    2827#include <wtf/HashMap.h>
    2928#include <wtf/PassRefPtr.h>
    3029#include <wtf/RefCounted.h>
     30
     31typedef struct _GdkEventKey GdkEventKey;
    3132
    3233namespace WebCore {
     
    4445    virtual void updateFromElement();
    4546    virtual void disconnectClient();
     47    bool typeAheadFind(GdkEventKey*);
    4648
    4749private:
    4850    PopupMenuClient* client() const { return m_popupClient; }
     51    void resetTypeAheadFindState();
    4952
    5053    static void menuItemActivated(GtkMenuItem* item, PopupMenuGtk*);
     
    5255    static void menuPositionFunction(GtkMenu*, gint*, gint*, gboolean*, PopupMenuGtk*);
    5356    static void menuRemoveItem(GtkWidget*, PopupMenuGtk*);
     57    static int selectItemCallback(GtkMenuItem*, PopupMenuGtk*);
     58    static int keyPressEventCallback(GtkWidget*, GdkEventKey*, PopupMenuGtk*);
    5459
    5560    PopupMenuClient* m_popupClient;
     
    5762    PlatformRefPtr<GtkMenu> m_popup;
    5863    HashMap<GtkWidget*, int> m_indexMap;
     64    String m_currentSearchString;
     65    uint32_t m_previousKeyEventTimestamp;
     66    unsigned int m_previousKeyEventCharacter;
     67    GtkWidget* m_currentlySelectedMenuItem;
    5968};
    6069
Note: See TracChangeset for help on using the changeset viewer.