summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/gtk')
-rw-r--r--WebCore/platform/gtk/FileSystemGtk.cpp6
-rw-r--r--WebCore/platform/gtk/GtkVersioning.c10
-rw-r--r--WebCore/platform/gtk/GtkVersioning.h4
-rw-r--r--WebCore/platform/gtk/LocalizedStringsGtk.cpp30
-rw-r--r--WebCore/platform/gtk/PopupMenuGtk.cpp112
-rw-r--r--WebCore/platform/gtk/PopupMenuGtk.h11
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;
};
}