• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24 
25 #include "config.h"
26 #include "PopupMenu.h"
27 
28 #include "CString.h"
29 #include "FrameView.h"
30 #include "HostWindow.h"
31 #include "NotImplemented.h"
32 #include "PlatformString.h"
33 #include <gtk/gtk.h>
34 
35 namespace WebCore {
36 
PopupMenu(PopupMenuClient * client)37 PopupMenu::PopupMenu(PopupMenuClient* client)
38     : m_popupClient(client)
39     , m_popup(0)
40 {
41 }
42 
~PopupMenu()43 PopupMenu::~PopupMenu()
44 {
45     if (m_popup)
46         g_object_unref(m_popup);
47 }
48 
show(const IntRect & rect,FrameView * view,int index)49 void PopupMenu::show(const IntRect& rect, FrameView* view, int index)
50 {
51     ASSERT(client());
52 
53     if (!m_popup) {
54         m_popup = GTK_MENU(gtk_menu_new());
55 #if GLIB_CHECK_VERSION(2,10,0)
56         g_object_ref_sink(G_OBJECT(m_popup));
57 #else
58         g_object_ref(G_OBJECT(m_popup));
59         gtk_object_sink(GTK_OBJECT(m_popup));
60 #endif
61         g_signal_connect(m_popup, "unmap", G_CALLBACK(menuUnmapped), this);
62     } else
63         gtk_container_foreach(GTK_CONTAINER(m_popup), reinterpret_cast<GtkCallback>(menuRemoveItem), this);
64 
65     int x, y;
66     gdk_window_get_origin(GTK_WIDGET(view->hostWindow()->platformWindow())->window, &x, &y);
67     m_menuPosition = view->contentsToWindow(rect.location());
68     m_menuPosition = IntPoint(m_menuPosition.x() + x, m_menuPosition.y() + y + rect.height());
69     m_indexMap.clear();
70 
71     const int size = client()->listSize();
72     for (int i = 0; i < size; ++i) {
73         GtkWidget* item;
74         if (client()->itemIsSeparator(i))
75             item = gtk_separator_menu_item_new();
76         else
77             item = gtk_menu_item_new_with_label(client()->itemText(i).utf8().data());
78 
79         m_indexMap.add(item, i);
80         g_signal_connect(item, "activate", G_CALLBACK(menuItemActivated), this);
81 
82         // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i)
83         gtk_widget_set_sensitive(item, client()->itemIsEnabled(i));
84         gtk_menu_shell_append(GTK_MENU_SHELL(m_popup), item);
85         gtk_widget_show(item);
86     }
87 
88     gtk_menu_set_active(m_popup, index);
89 
90 
91     // The size calls are directly copied from gtkcombobox.c which is LGPL
92     GtkRequisition requisition;
93     gtk_widget_set_size_request(GTK_WIDGET(m_popup), -1, -1);
94     gtk_widget_size_request(GTK_WIDGET(m_popup), &requisition);
95     gtk_widget_set_size_request(GTK_WIDGET(m_popup), MAX(rect.width(), requisition.width), -1);
96 
97     GList* children = GTK_MENU_SHELL(m_popup)->children;
98     if (size)
99         for (int i = 0; i < size; i++) {
100             if (i > index)
101               break;
102 
103             GtkWidget* item = reinterpret_cast<GtkWidget*>(children->data);
104             GtkRequisition itemRequisition;
105             gtk_widget_get_child_requisition(item, &itemRequisition);
106             m_menuPosition.setY(m_menuPosition.y() - itemRequisition.height);
107 
108             children = g_list_next(children);
109         }
110     else
111         // Center vertically the empty popup in the combo box area
112         m_menuPosition.setY(m_menuPosition.y() - rect.height() / 2);
113 
114     gtk_menu_popup(m_popup, NULL, NULL, reinterpret_cast<GtkMenuPositionFunc>(menuPositionFunction), this, 0, gtk_get_current_event_time());
115 }
116 
hide()117 void PopupMenu::hide()
118 {
119     ASSERT(m_popup);
120     gtk_menu_popdown(m_popup);
121 }
122 
updateFromElement()123 void PopupMenu::updateFromElement()
124 {
125     client()->setTextFromItem(client()->selectedIndex());
126 }
127 
itemWritingDirectionIsNatural()128 bool PopupMenu::itemWritingDirectionIsNatural()
129 {
130     return true;
131 }
132 
menuItemActivated(GtkMenuItem * item,PopupMenu * that)133 void PopupMenu::menuItemActivated(GtkMenuItem* item, PopupMenu* that)
134 {
135     ASSERT(that->client());
136     ASSERT(that->m_indexMap.contains(GTK_WIDGET(item)));
137     that->client()->valueChanged(that->m_indexMap.get(GTK_WIDGET(item)));
138 }
139 
menuUnmapped(GtkWidget *,PopupMenu * that)140 void PopupMenu::menuUnmapped(GtkWidget*, PopupMenu* that)
141 {
142     ASSERT(that->client());
143     that->client()->hidePopup();
144 }
145 
menuPositionFunction(GtkMenu *,gint * x,gint * y,gboolean * pushIn,PopupMenu * that)146 void PopupMenu::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pushIn, PopupMenu* that)
147 {
148     *x = that->m_menuPosition.x();
149     *y = that->m_menuPosition.y();
150     *pushIn = true;
151 }
152 
menuRemoveItem(GtkWidget * widget,PopupMenu * that)153 void PopupMenu::menuRemoveItem(GtkWidget* widget, PopupMenu* that)
154 {
155     ASSERT(that->m_popup);
156     gtk_container_remove(GTK_CONTAINER(that->m_popup), widget);
157 }
158 
159 }
160 
161