1 /* 2 * Copyright (C) 2007 Holger Hans Peter Freyther 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 #include "config.h" 20 #include "ContextMenu.h" 21 #include "ContextMenuItem.h" 22 #include "CString.h" 23 #include "NotImplemented.h" 24 25 #include <gtk/gtk.h> 26 27 #define WEBKIT_CONTEXT_MENU_ACTION "webkit-context-menu" 28 29 namespace WebCore { 30 31 static const char* gtkStockIDFromContextMenuAction(const ContextMenuAction& action) 32 { 33 switch (action) { 34 case ContextMenuItemTagCopyLinkToClipboard: 35 case ContextMenuItemTagCopyImageToClipboard: 36 case ContextMenuItemTagCopy: 37 return GTK_STOCK_COPY; 38 case ContextMenuItemTagOpenLinkInNewWindow: 39 case ContextMenuItemTagOpenImageInNewWindow: 40 case ContextMenuItemTagOpenFrameInNewWindow: 41 return GTK_STOCK_OPEN; 42 case ContextMenuItemTagDownloadLinkToDisk: 43 case ContextMenuItemTagDownloadImageToDisk: 44 return GTK_STOCK_SAVE; 45 case ContextMenuItemTagGoBack: 46 return GTK_STOCK_GO_BACK; 47 case ContextMenuItemTagGoForward: 48 return GTK_STOCK_GO_FORWARD; 49 case ContextMenuItemTagStop: 50 return GTK_STOCK_STOP; 51 case ContextMenuItemTagReload: 52 return GTK_STOCK_REFRESH; 53 case ContextMenuItemTagCut: 54 return GTK_STOCK_CUT; 55 case ContextMenuItemTagPaste: 56 return GTK_STOCK_PASTE; 57 case ContextMenuItemTagDelete: 58 return GTK_STOCK_DELETE; 59 case ContextMenuItemTagSelectAll: 60 return GTK_STOCK_SELECT_ALL; 61 case ContextMenuItemTagSpellingGuess: 62 return NULL; 63 case ContextMenuItemTagIgnoreSpelling: 64 return GTK_STOCK_NO; 65 case ContextMenuItemTagLearnSpelling: 66 return GTK_STOCK_OK; 67 case ContextMenuItemTagOther: 68 return GTK_STOCK_MISSING_IMAGE; 69 case ContextMenuItemTagSearchInSpotlight: 70 return GTK_STOCK_FIND; 71 case ContextMenuItemTagSearchWeb: 72 return GTK_STOCK_FIND; 73 case ContextMenuItemTagOpenWithDefaultApplication: 74 return GTK_STOCK_OPEN; 75 case ContextMenuItemPDFZoomIn: 76 return GTK_STOCK_ZOOM_IN; 77 case ContextMenuItemPDFZoomOut: 78 return GTK_STOCK_ZOOM_OUT; 79 case ContextMenuItemPDFAutoSize: 80 return GTK_STOCK_ZOOM_FIT; 81 case ContextMenuItemPDFNextPage: 82 return GTK_STOCK_GO_FORWARD; 83 case ContextMenuItemPDFPreviousPage: 84 return GTK_STOCK_GO_BACK; 85 // New tags, not part of API 86 case ContextMenuItemTagOpenLink: 87 return GTK_STOCK_OPEN; 88 case ContextMenuItemTagCheckSpelling: 89 return GTK_STOCK_SPELL_CHECK; 90 case ContextMenuItemTagFontMenu: 91 return GTK_STOCK_SELECT_FONT; 92 case ContextMenuItemTagShowFonts: 93 return GTK_STOCK_SELECT_FONT; 94 case ContextMenuItemTagBold: 95 return GTK_STOCK_BOLD; 96 case ContextMenuItemTagItalic: 97 return GTK_STOCK_ITALIC; 98 case ContextMenuItemTagUnderline: 99 return GTK_STOCK_UNDERLINE; 100 case ContextMenuItemTagShowColors: 101 return GTK_STOCK_SELECT_COLOR; 102 default: 103 return NULL; 104 } 105 } 106 107 // Extract the ActionType from the menu item 108 ContextMenuItem::ContextMenuItem(GtkMenuItem* item) 109 : m_platformDescription() 110 { 111 if (GTK_IS_SEPARATOR_MENU_ITEM(item)) 112 m_platformDescription.type = SeparatorType; 113 else if (gtk_menu_item_get_submenu(item)) 114 m_platformDescription.type = SubmenuType; 115 else if (GTK_IS_CHECK_MENU_ITEM(item)) { 116 m_platformDescription.type = CheckableActionType; 117 m_platformDescription.checked = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)); 118 } else 119 m_platformDescription.type = ActionType; 120 #if GTK_CHECK_VERSION (2, 16, 0) 121 m_platformDescription.title = String::fromUTF8(gtk_menu_item_get_label(GTK_MENU_ITEM(item))); 122 #else 123 GtkWidget* label = gtk_bin_get_child(GTK_BIN(item)); 124 m_platformDescription.title = String::fromUTF8(gtk_label_get_label(GTK_LABEL(label))); 125 #endif 126 127 m_platformDescription.action = *static_cast<ContextMenuAction*>(g_object_get_data(G_OBJECT(item), WEBKIT_CONTEXT_MENU_ACTION)); 128 129 m_platformDescription.subMenu = GTK_MENU(gtk_menu_item_get_submenu(item)); 130 if (m_platformDescription.subMenu) 131 g_object_ref(m_platformDescription.subMenu); 132 } 133 134 ContextMenuItem::ContextMenuItem(ContextMenu*) 135 { 136 notImplemented(); 137 } 138 139 ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu) 140 { 141 m_platformDescription.type = type; 142 m_platformDescription.action = action; 143 m_platformDescription.title = title; 144 145 setSubMenu(subMenu); 146 } 147 148 ContextMenuItem::~ContextMenuItem() 149 { 150 if (m_platformDescription.subMenu) 151 g_object_unref(m_platformDescription.subMenu); 152 } 153 154 GtkMenuItem* ContextMenuItem::createNativeMenuItem(const PlatformMenuItemDescription& menu) 155 { 156 GtkMenuItem* item = 0; 157 if (menu.type == SeparatorType) 158 item = GTK_MENU_ITEM(gtk_separator_menu_item_new()); 159 else { 160 if (menu.type == CheckableActionType) { 161 item = GTK_MENU_ITEM(gtk_check_menu_item_new_with_mnemonic(menu.title.utf8().data())); 162 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), menu.checked); 163 } else { 164 if (const gchar* stockID = gtkStockIDFromContextMenuAction(menu.action)) { 165 item = GTK_MENU_ITEM(gtk_image_menu_item_new_with_mnemonic(menu.title.utf8().data())); 166 GtkWidget* image = gtk_image_new_from_stock(stockID, GTK_ICON_SIZE_MENU); 167 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); 168 } else 169 item = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(menu.title.utf8().data())); 170 } 171 172 ContextMenuAction* menuAction = static_cast<ContextMenuAction*>(malloc(sizeof(ContextMenuAction*))); 173 *menuAction = menu.action; 174 g_object_set_data(G_OBJECT(item), WEBKIT_CONTEXT_MENU_ACTION, menuAction); 175 176 gtk_widget_set_sensitive(GTK_WIDGET(item), menu.enabled); 177 178 if (menu.subMenu) 179 gtk_menu_item_set_submenu(item, GTK_WIDGET(menu.subMenu)); 180 } 181 182 return item; 183 } 184 185 PlatformMenuItemDescription ContextMenuItem::releasePlatformDescription() 186 { 187 PlatformMenuItemDescription description = m_platformDescription; 188 m_platformDescription = PlatformMenuItemDescription(); 189 return description; 190 } 191 192 ContextMenuItemType ContextMenuItem::type() const 193 { 194 return m_platformDescription.type; 195 } 196 197 void ContextMenuItem::setType(ContextMenuItemType type) 198 { 199 m_platformDescription.type = type; 200 } 201 202 ContextMenuAction ContextMenuItem::action() const 203 { 204 return m_platformDescription.action; 205 } 206 207 void ContextMenuItem::setAction(ContextMenuAction action) 208 { 209 m_platformDescription.action = action; 210 } 211 212 String ContextMenuItem::title() const 213 { 214 return m_platformDescription.title; 215 } 216 217 void ContextMenuItem::setTitle(const String& title) 218 { 219 m_platformDescription.title = title; 220 } 221 222 PlatformMenuDescription ContextMenuItem::platformSubMenu() const 223 { 224 return m_platformDescription.subMenu; 225 } 226 227 void ContextMenuItem::setSubMenu(ContextMenu* menu) 228 { 229 if (m_platformDescription.subMenu) 230 g_object_unref(m_platformDescription.subMenu); 231 232 if (!menu) 233 return; 234 235 m_platformDescription.subMenu = menu->releasePlatformDescription(); 236 m_platformDescription.type = SubmenuType; 237 238 g_object_ref_sink(G_OBJECT(m_platformDescription.subMenu)); 239 } 240 241 void ContextMenuItem::setChecked(bool shouldCheck) 242 { 243 m_platformDescription.checked = shouldCheck; 244 } 245 246 void ContextMenuItem::setEnabled(bool shouldEnable) 247 { 248 m_platformDescription.enabled = shouldEnable; 249 } 250 251 } 252