Home | History | Annotate | Download | only in gtk
      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