diff options
Diffstat (limited to 'WebCore/platform/gtk')
-rw-r--r-- | WebCore/platform/gtk/FileSystemGtk.cpp | 6 | ||||
-rw-r--r-- | WebCore/platform/gtk/GtkVersioning.c | 10 | ||||
-rw-r--r-- | WebCore/platform/gtk/GtkVersioning.h | 4 | ||||
-rw-r--r-- | WebCore/platform/gtk/LocalizedStringsGtk.cpp | 30 | ||||
-rw-r--r-- | WebCore/platform/gtk/PopupMenuGtk.cpp | 112 | ||||
-rw-r--r-- | WebCore/platform/gtk/PopupMenuGtk.h | 11 |
6 files changed, 167 insertions, 6 deletions
diff --git a/WebCore/platform/gtk/FileSystemGtk.cpp b/WebCore/platform/gtk/FileSystemGtk.cpp index 6f3fa19..4424f0a 100644 --- a/WebCore/platform/gtk/FileSystemGtk.cpp +++ b/WebCore/platform/gtk/FileSystemGtk.cpp @@ -257,6 +257,12 @@ void closeFile(PlatformFileHandle& handle) } } +long long seekFile(PlatformFileHandle handle, long long offset, FileSeekOrigin origin) +{ + // FIXME - Awaiting implementation, see https://bugs.webkit.org/show_bug.cgi?id=43878 + return -1; +} + int writeToFile(PlatformFileHandle handle, const char* data, int length) { int totalBytesWritten = 0; diff --git a/WebCore/platform/gtk/GtkVersioning.c b/WebCore/platform/gtk/GtkVersioning.c index 0776c10..c3407ea 100644 --- a/WebCore/platform/gtk/GtkVersioning.c +++ b/WebCore/platform/gtk/GtkVersioning.c @@ -260,4 +260,14 @@ gdk_pixbuf_get_from_surface(cairo_surface_t * surface, cairo_surface_destroy(surface); return dest; } + #endif // GTK_API_VERSION_2 + +#if !GLIB_CHECK_VERSION(2, 27, 1) +gboolean g_signal_accumulator_first_wins(GSignalInvocationHint *invocationHint, GValue *returnAccumulator, const GValue *handlerReturn, gpointer data) +{ + g_value_copy(handlerReturn, returnAccumulator); + return FALSE; +} +#endif + diff --git a/WebCore/platform/gtk/GtkVersioning.h b/WebCore/platform/gtk/GtkVersioning.h index b40e497..ea15a54 100644 --- a/WebCore/platform/gtk/GtkVersioning.h +++ b/WebCore/platform/gtk/GtkVersioning.h @@ -103,6 +103,10 @@ void gtk_adjustment_set_value(GtkAdjustment* adjusment, gdouble value); GdkDevice* getDefaultGDKPointerDevice(GdkWindow* window); GdkCursor* blankCursor(); +#if !GLIB_CHECK_VERSION(2, 27, 1) +gboolean g_signal_accumulator_first_wins(GSignalInvocationHint* invocationHint, GValue* returnAccumulator, const GValue* handlerReturn, gpointer data); +#endif + G_END_DECLS #endif // GtkVersioning_h diff --git a/WebCore/platform/gtk/LocalizedStringsGtk.cpp b/WebCore/platform/gtk/LocalizedStringsGtk.cpp index 68c1598..65e8852 100644 --- a/WebCore/platform/gtk/LocalizedStringsGtk.cpp +++ b/WebCore/platform/gtk/LocalizedStringsGtk.cpp @@ -553,6 +553,36 @@ String validationMessageValueMissingText() return String::fromUTF8(_("value missing")); } +String validationMessageValueMissingForCheckboxText() +{ + notImplemented(); + return validationMessageValueMissingText(); +} + +String validationMessageValueMissingForFileText() +{ + notImplemented(); + return validationMessageValueMissingText(); +} + +String validationMessageValueMissingForMultipleFileText() +{ + notImplemented(); + return validationMessageValueMissingText(); +} + +String validationMessageValueMissingForRadioText() +{ + notImplemented(); + return validationMessageValueMissingText(); +} + +String validationMessageValueMissingForSelectText() +{ + notImplemented(); + return validationMessageValueMissingText(); +} + String validationMessageTypeMismatchText() { notImplemented(); diff --git a/WebCore/platform/gtk/PopupMenuGtk.cpp b/WebCore/platform/gtk/PopupMenuGtk.cpp index e7ff78e..b2466c5 100644 --- a/WebCore/platform/gtk/PopupMenuGtk.cpp +++ b/WebCore/platform/gtk/PopupMenuGtk.cpp @@ -5,6 +5,7 @@ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com * Copyright (C) 2008 Collabora Ltd. * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2010 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 @@ -27,16 +28,22 @@ #include "PopupMenuGtk.h" #include "FrameView.h" +#include "GOwnPtr.h" #include "GtkVersioning.h" #include "HostWindow.h" #include "PlatformString.h" -#include <wtf/text/CString.h> +#include <gdk/gdk.h> #include <gtk/gtk.h> +#include <wtf/text/CString.h> namespace WebCore { +static const uint32_t gSearchTimeoutMs = 1000; + PopupMenuGtk::PopupMenuGtk(PopupMenuClient* client) : m_popupClient(client) + , m_previousKeyEventCharacter(0) + , m_currentlySelectedMenuItem(0) { } @@ -54,12 +61,16 @@ void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index) if (!m_popup) { m_popup = GTK_MENU(gtk_menu_new()); - g_signal_connect(m_popup.get(), "unmap", G_CALLBACK(menuUnmapped), this); + 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); } else gtk_container_foreach(GTK_CONTAINER(m_popup.get()), reinterpret_cast<GtkCallback>(menuRemoveItem), this); - int x, y; - gdk_window_get_origin(gtk_widget_get_window(GTK_WIDGET(view->hostWindow()->platformPageClient())), &x, &y); + 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(); @@ -73,7 +84,8 @@ void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index) item = gtk_menu_item_new_with_label(client()->itemText(i).utf8().data()); m_indexMap.add(item, i); - g_signal_connect(item, "activate", G_CALLBACK(menuItemActivated), this); + 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)); @@ -138,6 +150,77 @@ void PopupMenuGtk::disconnectClient() m_popupClient = 0; } +bool PopupMenuGtk::typeAheadFind(GdkEventKey* event) +{ + // 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()); @@ -148,6 +231,7 @@ void PopupMenuGtk::menuItemActivated(GtkMenuItem* item, PopupMenuGtk* that) void PopupMenuGtk::menuUnmapped(GtkWidget*, PopupMenuGtk* that) { ASSERT(that->client()); + that->resetTypeAheadFindState(); that->client()->popupDidHide(); } @@ -158,11 +242,29 @@ void PopupMenuGtk::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pu *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); +} + } diff --git a/WebCore/platform/gtk/PopupMenuGtk.h b/WebCore/platform/gtk/PopupMenuGtk.h index 8848e06..e47fda6 100644 --- a/WebCore/platform/gtk/PopupMenuGtk.h +++ b/WebCore/platform/gtk/PopupMenuGtk.h @@ -24,11 +24,12 @@ #include "IntRect.h" #include "PopupMenu.h" #include "PopupMenuClient.h" -#include <glib.h> #include <wtf/HashMap.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> +typedef struct _GdkEventKey GdkEventKey; + namespace WebCore { class FrameView; @@ -43,19 +44,27 @@ public: virtual void hide(); virtual void updateFromElement(); virtual void disconnectClient(); + bool typeAheadFind(GdkEventKey*); private: PopupMenuClient* client() const { return m_popupClient; } + void resetTypeAheadFindState(); 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*); PopupMenuClient* m_popupClient; IntPoint m_menuPosition; PlatformRefPtr<GtkMenu> m_popup; HashMap<GtkWidget*, int> m_indexMap; + String m_currentSearchString; + uint32_t m_previousKeyEventTimestamp; + unsigned int m_previousKeyEventCharacter; + GtkWidget* m_currentlySelectedMenuItem; }; } |