I've started to work (mainly think about) on the context menu client for webkit2. Current wk1 API provides a web setting to disable the default context menu and a populate-popup signal that is emitted right before the default context menu is shown. This API is good enough for simple cases when you just want to add some custom actions to the default context menu and you are sure they are not already in the menu. The signal passes a GtkMenu as a parameter, that you can use to add items. The main problem of this approach is that it's difficult to know what actions are already in the menu, because menu item labels are not actually part of the API so you shouldn't rely on them.
So, I think the minimum requirements of the API would be: - It should be a single signal that allows you to disable the default context menu without using a setting. - It should be easy to add/remove and reorder menu items. - It should be possible to identify the actions included in the default context menu - It should allow the following 4 use cases: + Apps that don't want to show any context menu at all. + Apps that just want to show the default context menu + Apps that want to customize the default context menu + Apps that want to build their own context menu So the idea is to provide a single signal WebKitWebView::context-menu that passes a Menu and a WebKitHitTestResult. We should probably need to pass the GdkEvent, because this is now asynchronous, so that when the context menu is shown, the button press callback has returned already, and gtk_get_current_event() return NULL. That event is cached by the web page proxy for that reason, so we could get the event and pass it as part of the signal. The signal would be true_handled, so that returning TRUE means the default context menu won't be shown, and FALSE that the menu will be shown. The 4 uses cases would be: + Apps that don't want to show any context menu at all. Connect to the context-menu signal and simply return TRUE. + Apps that just want to show the default context menu. That's the default behaviour so apps don't need to do anything. + Apps that want to customize the default context menu. Connect to context-menu signal, use the Menu object to add/remove/reorder/whatever and return FALSE. + Apps that want to build their own context menu. Connect to context-menu signal, build your own menu using the HitTestResult to decide what items to add, and the return TRUE. Depending on what Menu object we use, this could be implemented also removing all items from the menu passed, adding your own items and returning FALSE. This option probably makes more sense taking into account how context menu works in WebKit2. In WebKit2, a context menu is a Vector of WebContextMenuItemData. The context menu client has a callback getContextMenuFromProposedMenu, called right before the context menu is shown, so that you can customize the menu. To show the menu, a WebContextMenuProxy object is created, that creates a GtkMenu from the Vector using the WebCore API and calls gtk_menu_popup to show the menu. In order to customize the menu it's important to be able to easily identify the items in the default context menu, or even group of items/actions (navigation actions, editing actions, link actions, etc.). So, the key point is what to pass as Menu object to the signal. A GtkMenu is not enough, because of the reasons I mentioned before, mainly that we can't rely on menu item labels to identify menu items. However, if the menu item has been created from a GtkAction, we could use the action name to identify the item. We have, at least, the following options: a) Use a GtkMenu and use GtkMenuShell api to add/remove items. Items in the default context menu have a GtkAction associated with a name that allows us to identify it. This is the approach we decided to follow in webkit1, see bug https://bugs.webkit.org/show_bug.cgi?id=67660 b) Use a GtkUIManager. The default context menu would define a XML using placeholders for the different action groups (navigation actions, editing actions, etc.). The user can add new items to the menu by merging their own xml, and adding actions and action groups to the ui manager. c) Use new GMenu API. We would pass a GMenuModel so that user can add/remove items using the GMenu API. Default menu would contain GActions with a name that allows us to identify it. We could have actions groups using GActionGroup. d) Use our thing. Add WebKitContexMenu and WebKitContextMenuIem objects with the API needed to meet all the requirements. Option a) is probably the simplest one, we would need to add api to get the well-known name for the action associated with a menu item, and also api to add an item to the menu using a well known name, so that users can also add items to the menu that are known by WebKit without having to create them manually. Those methods would be global (not belonging to any WebKit object). This wouldn't allow to use action groups. The main problem I see with this is that getContextMenuFromProposedMenu callback should return an array of items, so we would need to convert the GtkMenu to an array of items, and then the WebContextMenuProxy converts the array again into a GtkMenu, creating new menu items and actions, so the GtkMenu passed to the signal is not the one that it will be popped up. A possible solution might be to create the GtkMenu in getContextMenuFromProposedMenu and pass that menu to the WebContextMenuProxy, then when WebContextMenuProxy::showContextMenu() is called, we just ignore the items Vector and just show the cached GtkMenu. Option b) requires to write XML which is convenient for static menus, but maybe not so convenient for this kind of dynamic menus. Also, it seems UIManager API will be deprecated sooner or later in GTK+. Option c) was my original idea when GMenu API was added to GLib and GTK +. GMenuModel API provides everything we need (and probably more that we don't need). The problem is that it's not easy to create a GtkMenu from a GMenu. There's gtk_menu_new_from_model() in GTK+ but GMenu API is designed to work with GtkApplication and GtkApplicationWindow, so that method only populates the menu it's attached to a widget inside a GtkApplicationWindow. I've talked to gtk+ devs and it seems GAction and GMenu might be used for other use cases like popup menus in the future, but it's not still clear how at this point, so it seems to me that is unlikely to happen in a near future. GtkAction and GtkActionGroup provides everything we need, so we don't really need GAction and GMenu API. So, option d) could be based on GtkAction and GtkActionGroup API. Current WebCore context menu API is already based on GtkAction indeed. If we don't really need action groups, this could be very similar to option a), but with the API to get the well known name of a menu item in WebKitContextMenuItem and the API to add a predefined item in WebKitContextMenu. If actions are created by the user, we have the same problem than with a), the menu is converted to Vector of items and then converted to a GtkMenu again, in this case, since we are not exposing GtkMenu nor GtkMenuItem, we just need to make sure that the GtkActions used to build the new menu in WebContextMenuProxy::showContextMenu() are the same. We could add specific API to WebContextMenuProxy and use it directly to store the new menu, so that in WebContextMenuProxy::showContextMenu() we can ignore the given Vector and just popup the current menu. Opinions? what option do you think it's better? -- Carlos Garcia Campos http://pgp.rediris.es:11371/pks/lookup?op=get&search=0xF3D322D0EC4582C3
signature.asc
Description: This is a digitally signed message part
_______________________________________________ webkit-gtk mailing list [email protected] http://lists.webkit.org/mailman/listinfo.cgi/webkit-gtk
