Name all the GLib timeout sources
[WebKit-https.git] / Source / WebCore / platform / gtk / PopupMenuGtk.cpp
1 /*
2  * This file is part of the popup menu implementation for <select> elements in WebCore.
3  *
4  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
5  * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
6  * Copyright (C) 2008 Collabora Ltd.
7  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
8  * Copyright (C) 2010 Igalia S.L.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  *
25  */
26
27 #include "config.h"
28 #include "PopupMenuGtk.h"
29
30 #include "FrameView.h"
31 #include "GOwnPtrGtk.h"
32 #include "GtkUtilities.h"
33 #include "HostWindow.h"
34 #include <gtk/gtk.h>
35 #include <wtf/gobject/GOwnPtr.h>
36 #include <wtf/text/CString.h>
37
38 namespace WebCore {
39
40 static const uint32_t gSearchTimeoutMs = 1000;
41
42 PopupMenuGtk::PopupMenuGtk(PopupMenuClient* client)
43     : m_popupClient(client)
44 {
45 }
46
47 PopupMenuGtk::~PopupMenuGtk()
48 {
49     if (m_popup) {
50         g_signal_handlers_disconnect_matched(m_popup->platformMenu(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
51         hide();
52     }
53 }
54
55 GtkAction* PopupMenuGtk::createGtkActionForMenuItem(int itemIndex)
56 {
57     GOwnPtr<char> actionName(g_strdup_printf("popup-menu-action-%d", itemIndex));
58     GtkAction* action = gtk_action_new(actionName.get(), client()->itemText(itemIndex).utf8().data(), client()->itemToolTip(itemIndex).utf8().data(), 0);
59     g_object_set_data(G_OBJECT(action), "popup-menu-action-index", GINT_TO_POINTER(itemIndex));
60     g_signal_connect(action, "activate", G_CALLBACK(menuItemActivated), this);
61     // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i)
62     gtk_action_set_visible(action, !client()->itemStyle(itemIndex).isDisplayNone());
63     gtk_action_set_sensitive(action, client()->itemIsEnabled(itemIndex));
64
65     return action;
66 }
67
68 void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index)
69 {
70     ASSERT(client());
71
72     if (!m_popup) {
73         m_popup = GtkPopupMenu::create();
74         g_signal_connect(m_popup->platformMenu(), "unmap", G_CALLBACK(PopupMenuGtk::menuUnmapped), this);
75     } else
76         m_popup->clear();
77
78     const int size = client()->listSize();
79     for (int i = 0; i < size; ++i) {
80         if (client()->itemIsSeparator(i))
81             m_popup->appendSeparator();
82         else {
83             GRefPtr<GtkAction> action = adoptGRef(createGtkActionForMenuItem(i));
84             m_popup->appendItem(action.get());
85         }
86     }
87
88     IntPoint menuPosition = convertWidgetPointToScreenPoint(GTK_WIDGET(view->hostWindow()->platformPageClient()), view->contentsToWindow(rect.location()));
89     menuPosition.move(0, rect.height());
90
91     GOwnPtr<GdkEvent> currentEvent(gtk_get_current_event());
92     m_popup->popUp(rect.size(), menuPosition, size, index, currentEvent.get());
93
94     // GTK can refuse to actually open the menu when mouse grabs fails.
95     // Ensure WebCore does not go into some pesky state.
96     if (!gtk_widget_get_visible(m_popup->platformMenu()))
97         client()->popupDidHide();
98 }
99
100 void PopupMenuGtk::hide()
101 {
102     ASSERT(m_popup);
103     m_popup->popDown();
104 }
105
106 void PopupMenuGtk::updateFromElement()
107 {
108     client()->setTextFromItem(client()->selectedIndex());
109 }
110
111 void PopupMenuGtk::disconnectClient()
112 {
113     m_popupClient = 0;
114 }
115
116 void PopupMenuGtk::menuItemActivated(GtkAction* action, PopupMenuGtk* that)
117 {
118     ASSERT(that->client());
119     that->client()->valueChanged(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "popup-menu-action-index")));
120 }
121
122 void PopupMenuGtk::menuUnmapped(GtkWidget*, PopupMenuGtk* that)
123 {
124     ASSERT(that->client());
125     that->client()->popupDidHide();
126 }
127
128 }
129