Changeset 87930 in webkit
- Timestamp:
- Jun 2, 2011, 11:01:23 AM (14 years ago)
- Location:
- trunk/Source
- Files:
-
- 2 added
- 7 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r87926 r87930 1 2011-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 1 40 2011-05-21 Dimitri Glazkov <dglazkov@chromium.org> 2 41 -
trunk/Source/WebCore/GNUmakefile.list.am
r87780 r87930 3797 3797 Source/WebCore/platform/gtk/GtkPluginWidget.cpp \ 3798 3798 Source/WebCore/platform/gtk/GtkPluginWidget.h \ 3799 Source/WebCore/platform/gtk/GtkPopupMenu.cpp \ 3800 Source/WebCore/platform/gtk/GtkPopupMenu.h \ 3799 3801 Source/WebCore/platform/gtk/GtkVersioning.c \ 3800 3802 Source/WebCore/platform/gtk/GtkVersioning.h \ -
trunk/Source/WebCore/platform/gtk/GtkPopupMenu.cpp
r87929 r87930 6 6 * Copyright (C) 2008 Collabora Ltd. 7 7 * 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. 9 9 * 10 10 * This library is free software; you can redistribute it and/or … … 26 26 27 27 #include "config.h" 28 #include "PopupMenuGtk.h" 29 30 #include "FrameView.h" 28 #include "GtkPopupMenu.h" 29 31 30 #include "GOwnPtr.h" 32 31 #include "GtkVersioning.h" 33 #include "HostWindow.h"34 #include "PlatformString.h"35 #include <gdk/gdk.h>36 32 #include <gtk/gtk.h> 37 33 #include <wtf/text/CString.h> … … 41 37 static const uint32_t gSearchTimeoutMs = 1000; 42 38 43 PopupMenuGtk::PopupMenuGtk(PopupMenuClient* client)44 : m_popup Client(client)39 GtkPopupMenu::GtkPopupMenu() 40 : m_popup(gtk_menu_new()) 45 41 , m_previousKeyEventCharacter(0) 46 42 , m_currentlySelectedMenuItem(0) 47 43 { 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 47 GtkPopupMenu::~GtkPopupMenu() 48 { 49 g_signal_handler_disconnect(m_popup.get(), m_keyPressHandlerID); 50 } 51 52 void GtkPopupMenu::clear() 53 { 54 gtk_container_foreach(GTK_CONTAINER(m_popup.get()), reinterpret_cast<GtkCallback>(menuRemoveItem), this); 55 } 56 57 void 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 64 void 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 72 void 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. 100 79 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); 102 81 #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); 104 83 #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); 106 85 #endif 107 86 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); 109 88 110 89 GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get())); 111 90 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; 116 95 117 96 GtkWidget* item = reinterpret_cast<GtkWidget*>(p->data); … … 127 106 } 128 107 } 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 } 133 111 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 131 void GtkPopupMenu::popDown() 132 { 133 gtk_menu_popdown(GTK_MENU(m_popup.get())); 134 resetTypeAheadFindState(); 135 } 136 137 void 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 143 void 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 150 void GtkPopupMenu::resetTypeAheadFindState() 151 { 152 m_currentlySelectedMenuItem = 0; 153 m_previousKeyEventCharacter = 0; 154 m_currentSearchString = ""; 155 } 156 157 bool GtkPopupMenu::typeAheadFind(GdkEventKey* event) 154 158 { 155 159 // If we were given a non-printable character just skip it. 156 160 gunichar unicodeCharacter = gdk_keyval_to_unicode(event->keyval); 157 if (! unicodeCharacter) {161 if (!g_unichar_isprint(unicodeCharacter)) { 158 162 resetTypeAheadFindState(); 159 163 return false; … … 215 219 if (!strncmp(searchStringWithCaseFolded.get(), itemText.get(), prefixLength)) { 216 220 gtk_menu_shell_select_item(GTK_MENU_SHELL(m_popup.get()), GTK_WIDGET(currentChild->data)); 217 return true;221 break; 218 222 } 219 223 } while (currentChild != firstChild); 220 224 225 g_list_free(children); 221 226 return true; 222 227 } 223 228 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 229 void GtkPopupMenu::selectItemCallback(GtkMenuItem* item, GtkPopupMenu* popupMenu) 230 { 231 popupMenu->m_currentlySelectedMenuItem = GTK_WIDGET(item); 232 } 233 234 gboolean 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 1 1 /* 2 2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 3 * Copyright (C) 2011 Igalia S.L. 3 4 * 4 5 * This library is free software; you can redistribute it and/or … … 18 19 */ 19 20 20 #ifndef PopupMenuGtk_h21 #define PopupMenuGtk_h21 #ifndef GtkPopupMenu_h 22 #define GtkPopupMenu_h 22 23 23 24 #include "GRefPtrGtk.h" 24 #include "Int Rect.h"25 #include " PopupMenu.h"26 #include "P opupMenuClient.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> 30 31 31 32 typedef struct _GdkEventKey GdkEventKey; … … 33 34 namespace WebCore { 34 35 35 class FrameView; 36 class Scrollbar; 36 class GtkPopupMenu { 37 WTF_MAKE_NONCOPYABLE(GtkPopupMenu); 38 WTF_MAKE_FAST_ALLOCATED; 37 39 38 class PopupMenuGtk : public PopupMenu {39 40 public: 40 PopupMenuGtk(PopupMenuClient*); 41 ~PopupMenuGtk(); 41 static PassOwnPtr<GtkPopupMenu> create() 42 { 43 return adoptPtr(new GtkPopupMenu()); 44 } 42 45 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 55 private: 56 GtkPopupMenu(); 57 58 void resetTypeAheadFindState(); 47 59 bool typeAheadFind(GdkEventKey*); 48 60 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*); 52 66 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; 61 68 IntPoint m_menuPosition; 62 GRefPtr<GtkMenu> m_popup;63 HashMap<GtkWidget*, int> m_indexMap;64 69 String m_currentSearchString; 65 70 uint32_t m_previousKeyEventTimestamp; 66 71 unsigned int m_previousKeyEventCharacter; 67 72 GtkWidget* m_currentlySelectedMenuItem; 73 unsigned int m_keyPressHandlerID; 68 74 }; 69 75 70 76 } 71 77 72 #endif // PopupMenuGtk_h78 #endif // GtkPopupMenu_h -
trunk/Source/WebCore/platform/gtk/PopupMenuGtk.cpp
r73030 r87930 30 30 #include "FrameView.h" 31 31 #include "GOwnPtr.h" 32 #include "GtkVersioning.h"33 32 #include "HostWindow.h" 34 #include "PlatformString.h"35 #include <gdk/gdk.h>36 33 #include <gtk/gtk.h> 37 34 #include <wtf/text/CString.h> … … 43 40 PopupMenuGtk::PopupMenuGtk(PopupMenuClient* client) 44 41 : m_popupClient(client) 45 , m_previousKeyEventCharacter(0)46 , m_currentlySelectedMenuItem(0)47 42 { 48 43 } … … 51 46 { 52 47 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); 54 49 hide(); 55 50 } 51 } 52 53 GtkAction* 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; 56 63 } 57 64 … … 61 68 62 69 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); 66 72 } 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 } 68 84 69 85 int x = 0; … … 72 88 if (window) 73 89 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()); 77 92 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()); 135 94 } 136 95 … … 138 97 { 139 98 ASSERT(m_popup); 140 gtk_menu_popdown(m_popup.get());99 m_popup->popDown(); 141 100 } 142 101 … … 151 110 } 152 111 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) 112 void PopupMenuGtk::menuItemActivated(GtkAction* action, PopupMenuGtk* that) 225 113 { 226 114 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"))); 229 116 } 230 117 … … 232 119 { 233 120 ASSERT(that->client()); 234 that->resetTypeAheadFindState();235 121 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 122 } 268 123 -
trunk/Source/WebCore/platform/gtk/PopupMenuGtk.h
r75009 r87930 21 21 #define PopupMenuGtk_h 22 22 23 #include "G RefPtrGtk.h"23 #include "GtkPopupMenu.h" 24 24 #include "IntRect.h" 25 25 #include "PopupMenu.h" 26 26 #include "PopupMenuClient.h" 27 #include <wtf/HashMap.h>28 #include <wtf/PassRefPtr.h>29 #include <wtf/RefCounted.h>30 31 typedef struct _GdkEventKey GdkEventKey;32 27 33 28 namespace WebCore { … … 45 40 virtual void updateFromElement(); 46 41 virtual void disconnectClient(); 47 bool typeAheadFind(GdkEventKey*);48 42 49 43 private: 50 44 PopupMenuClient* client() const { return m_popupClient; } 51 void resetTypeAheadFindState();45 GtkAction* createGtkActionForMenuItem(int itemIndex); 52 46 53 static void menuItemActivated(GtkMenuItem* item, PopupMenuGtk*);54 47 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*); 59 49 60 50 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; 68 52 }; 69 53 -
trunk/Source/WebKit2/ChangeLog
r87857 r87930 1 2011-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 1 24 2011-06-01 Sam Weinig <sam@webkit.org> 2 25 -
trunk/Source/WebKit2/GNUmakefile.am
r87058 r87930 395 395 Source/WebKit2/UIProcess/gtk/WebInspectorGtk.cpp \ 396 396 Source/WebKit2/UIProcess/gtk/WebPageProxyGtk.cpp \ 397 Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp \ 398 Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h \ 397 399 Source/WebKit2/UIProcess/gtk/WebPreferencesGtk.cpp \ 398 400 Source/WebKit2/UIProcess/Launcher/gtk/ProcessLauncherGtk.cpp \ -
trunk/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp
r87689 r87930 38 38 #include "WebKitWebViewBasePrivate.h" 39 39 #include "WebPageProxy.h" 40 #include "WebPopupMenuProxyGtk.h" 40 41 #include <WebCore/GtkUtilities.h> 41 42 #include <wtf/text/WTFString.h> … … 205 206 } 206 207 207 PassRefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy*) 208 { 209 notImplemented(); 210 return 0; 208 PassRefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy* page) 209 { 210 return WebPopupMenuProxyGtk::create(m_viewWidget, page); 211 211 } 212 212
Note:
See TracChangeset
for help on using the changeset viewer.