| /* |
| * Copyright (C) 2012 Igalia S.L. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2,1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "config.h" |
| #include "WebKitWebInspector.h" |
| |
| #include "WebInspectorProxy.h" |
| #include "WebInspectorProxyClient.h" |
| #include "WebKitWebInspectorPrivate.h" |
| #include <glib/gi18n-lib.h> |
| #include <wtf/glib/GRefPtr.h> |
| #include <wtf/text/CString.h> |
| |
| using namespace WebKit; |
| |
| /** |
| * SECTION: WebKitWebInspector |
| * @Short_description: Access to the WebKit inspector |
| * @Title: WebKitWebInspector |
| * |
| * The WebKit Inspector is a graphical tool to inspect and change the |
| * content of a #WebKitWebView. It also includes an interactive |
| * JavaScript debugger. Using this class one can get a #GtkWidget |
| * which can be embedded into an application to show the inspector. |
| * |
| * The inspector is available when the #WebKitSettings of the |
| * #WebKitWebView has set the #WebKitSettings:enable-developer-extras |
| * to true, otherwise no inspector is available. |
| * |
| * <informalexample><programlisting> |
| * /<!-- -->* Enable the developer extras *<!-- -->/ |
| * WebKitSettings *setting = webkit_web_view_get_settings (WEBKIT_WEB_VIEW(my_webview)); |
| * g_object_set (G_OBJECT(settings), "enable-developer-extras", TRUE, NULL); |
| * |
| * /<!-- -->* Load some data or reload to be able to inspect the page*<!-- -->/ |
| * webkit_web_load_uri (WEBKIT_WEB_VIEW(my_webview), "http://www.gnome.org"); |
| * |
| * /<!-- -->* Show the inspector *<!-- -->/ |
| * WebKitWebInspector *inspector = webkit_web_view_get_inspector (WEBKIT_WEB_VIEW(my_webview)); |
| * webkit_web_inspector_show (WEBKIT_WEB_INSPECTOR(inspector)); |
| * </programlisting></informalexample> |
| * |
| */ |
| |
| enum { |
| OPEN_WINDOW, |
| BRING_TO_FRONT, |
| CLOSED, |
| ATTACH, |
| DETACH, |
| |
| LAST_SIGNAL |
| }; |
| |
| enum { |
| PROP_0, |
| |
| PROP_INSPECTED_URI, |
| PROP_ATTACHED_HEIGHT, |
| PROP_CAN_ATTACH |
| }; |
| |
| struct _WebKitWebInspectorPrivate { |
| ~_WebKitWebInspectorPrivate() |
| { |
| webInspector->setClient(nullptr); |
| } |
| |
| RefPtr<WebInspectorProxy> webInspector; |
| CString inspectedURI; |
| unsigned attachedHeight; |
| bool canAttach; |
| }; |
| |
| WEBKIT_DEFINE_TYPE(WebKitWebInspector, webkit_web_inspector, G_TYPE_OBJECT) |
| |
| static guint signals[LAST_SIGNAL] = { 0, }; |
| |
| static void webkitWebInspectorGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec) |
| { |
| WebKitWebInspector* inspector = WEBKIT_WEB_INSPECTOR(object); |
| |
| switch (propId) { |
| case PROP_INSPECTED_URI: |
| g_value_set_string(value, webkit_web_inspector_get_inspected_uri(inspector)); |
| break; |
| case PROP_ATTACHED_HEIGHT: |
| g_value_set_uint(value, webkit_web_inspector_get_attached_height(inspector)); |
| break; |
| case PROP_CAN_ATTACH: |
| g_value_set_boolean(value, webkit_web_inspector_get_can_attach(inspector)); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); |
| } |
| } |
| |
| static void webkit_web_inspector_class_init(WebKitWebInspectorClass* findClass) |
| { |
| GObjectClass* gObjectClass = G_OBJECT_CLASS(findClass); |
| gObjectClass->get_property = webkitWebInspectorGetProperty; |
| |
| /** |
| * WebKitWebInspector:inspected-uri: |
| * |
| * The URI that is currently being inspected. |
| */ |
| g_object_class_install_property(gObjectClass, |
| PROP_INSPECTED_URI, |
| g_param_spec_string("inspected-uri", |
| _("Inspected URI"), |
| _("The URI that is currently being inspected"), |
| 0, |
| WEBKIT_PARAM_READABLE)); |
| /** |
| * WebKitWebInspector:attached-height: |
| * |
| * The height that the inspector view should have when it is attached. |
| */ |
| g_object_class_install_property(gObjectClass, |
| PROP_ATTACHED_HEIGHT, |
| g_param_spec_uint("attached-height", |
| _("Attached Height"), |
| _("The height that the inspector view should have when it is attached"), |
| 0, G_MAXUINT, 0, |
| WEBKIT_PARAM_READABLE)); |
| |
| /** |
| * WebKitWebInspector:can-attach: |
| * |
| * Whether the @inspector can be attached to the same window that contains |
| * the inspected view. |
| * |
| * Since: 2.8 |
| */ |
| g_object_class_install_property( |
| gObjectClass, |
| PROP_CAN_ATTACH, |
| g_param_spec_boolean( |
| "can-attach", |
| _("Can Attach"), |
| _("Whether the inspector can be attached to the same window that contains the inspected view"), |
| FALSE, |
| WEBKIT_PARAM_READABLE)); |
| |
| /** |
| * WebKitWebInspector::open-window: |
| * @inspector: the #WebKitWebInspector on which the signal is emitted |
| * |
| * Emitted when the inspector is requested to open in a separate window. |
| * If this signal is not handled, a #GtkWindow with the inspector will be |
| * created and shown, so you only need to handle this signal if you want |
| * to use your own window. |
| * This signal is emitted after #WebKitWebInspector::detach to show |
| * the inspector in a separate window after being detached. |
| * |
| * To prevent the inspector from being shown you can connect to this |
| * signal and simply return %TRUE |
| * |
| * Returns: %TRUE to stop other handlers from being invoked for the event. |
| * %FALSE to propagate the event further. |
| */ |
| signals[OPEN_WINDOW] = g_signal_new( |
| "open-window", |
| G_TYPE_FROM_CLASS(gObjectClass), |
| G_SIGNAL_RUN_LAST, |
| 0, |
| g_signal_accumulator_true_handled, nullptr, |
| g_cclosure_marshal_generic, |
| G_TYPE_BOOLEAN, 0); |
| |
| /** |
| * WebKitWebInspector::bring-to-front: |
| * @inspector: the #WebKitWebInspector on which the signal is emitted |
| * |
| * Emitted when the inspector should be shown. |
| * |
| * If the inspector is not attached the inspector window should be shown |
| * on top of any other windows. |
| * If the inspector is attached the inspector view should be made visible. |
| * For example, if the inspector view is attached using a tab in a browser |
| * window, the browser window should be raised and the tab containing the |
| * inspector view should be the active one. |
| * In both cases, if this signal is not handled, the default implementation |
| * calls gtk_window_present() on the current toplevel #GtkWindow of the |
| * inspector view. |
| * |
| * Returns: %TRUE to stop other handlers from being invoked for the event. |
| * %FALSE to propagate the event further. |
| */ |
| signals[BRING_TO_FRONT] = g_signal_new( |
| "bring-to-front", |
| G_TYPE_FROM_CLASS(gObjectClass), |
| G_SIGNAL_RUN_LAST, |
| 0, |
| g_signal_accumulator_true_handled, nullptr, |
| g_cclosure_marshal_generic, |
| G_TYPE_BOOLEAN, 0); |
| |
| /** |
| * WebKitWebInspector::closed: |
| * @inspector: the #WebKitWebInspector on which the signal is emitted |
| * |
| * Emitted when the inspector page is closed. If you are using your own |
| * inspector window, you should connect to this signal and destroy your |
| * window. |
| */ |
| signals[CLOSED] = |
| g_signal_new("closed", |
| G_TYPE_FROM_CLASS(gObjectClass), |
| G_SIGNAL_RUN_LAST, |
| 0, 0, 0, |
| g_cclosure_marshal_VOID__VOID, |
| G_TYPE_NONE, 0); |
| |
| /** |
| * WebKitWebInspector::attach: |
| * @inspector: the #WebKitWebInspector on which the signal is emitted |
| * |
| * Emitted when the inspector is requested to be attached to the window |
| * where the inspected web view is. |
| * If this signal is not handled the inspector view will be automatically |
| * attached to the inspected view, so you only need to handle this signal |
| * if you want to attach the inspector view yourself (for example, to add |
| * the inspector view to a browser tab). |
| * |
| * To prevent the inspector view from being attached you can connect to this |
| * signal and simply return %TRUE. |
| * |
| * Returns: %TRUE to stop other handlers from being invoked for the event. |
| * %FALSE to propagate the event further. |
| */ |
| signals[ATTACH] = g_signal_new( |
| "attach", |
| G_TYPE_FROM_CLASS(gObjectClass), |
| G_SIGNAL_RUN_LAST, |
| 0, |
| g_signal_accumulator_true_handled, nullptr, |
| g_cclosure_marshal_generic, |
| G_TYPE_BOOLEAN, 0); |
| |
| /** |
| * WebKitWebInspector::detach: |
| * @inspector: the #WebKitWebInspector on which the signal is emitted |
| * |
| * Emitted when the inspector is requested to be detached from the window |
| * it is currently attached to. The inspector is detached when the inspector page |
| * is about to be closed, and this signal is emitted right before |
| * #WebKitWebInspector::closed, or when the user clicks on the detach button |
| * in the inspector view to show the inspector in a separate window. In this case |
| * the signal #WebKitWebInspector::open-window is emitted after this one. |
| * |
| * To prevent the inspector view from being detached you can connect to this |
| * signal and simply return %TRUE. |
| * |
| * Returns: %TRUE to stop other handlers from being invoked for the event. |
| * %FALSE to propagate the event further. |
| */ |
| signals[DETACH] = g_signal_new( |
| "detach", |
| G_TYPE_FROM_CLASS(gObjectClass), |
| G_SIGNAL_RUN_LAST, |
| 0, |
| g_signal_accumulator_true_handled, nullptr, |
| g_cclosure_marshal_generic, |
| G_TYPE_BOOLEAN, 0); |
| } |
| |
| class WebKitInspectorClient final : public WebInspectorProxyClient { |
| public: |
| explicit WebKitInspectorClient(WebKitWebInspector* inspector) |
| : m_inspector(inspector) |
| { |
| } |
| |
| private: |
| bool openWindow(WebInspectorProxy&) override |
| { |
| gboolean returnValue; |
| g_signal_emit(m_inspector, signals[OPEN_WINDOW], 0, &returnValue); |
| return returnValue; |
| } |
| |
| void didClose(WebInspectorProxy&) override |
| { |
| g_signal_emit(m_inspector, signals[CLOSED], 0); |
| } |
| |
| bool bringToFront(WebInspectorProxy&) override |
| { |
| gboolean returnValue; |
| g_signal_emit(m_inspector, signals[BRING_TO_FRONT], 0, &returnValue); |
| return returnValue; |
| } |
| |
| void inspectedURLChanged(WebInspectorProxy&, const String& url) override |
| { |
| CString uri = url.utf8(); |
| if (uri == m_inspector->priv->inspectedURI) |
| return; |
| m_inspector->priv->inspectedURI = uri; |
| g_object_notify(G_OBJECT(m_inspector), "inspected-uri"); |
| } |
| |
| bool attach(WebInspectorProxy&) override |
| { |
| gboolean returnValue; |
| g_signal_emit(m_inspector, signals[ATTACH], 0, &returnValue); |
| return returnValue; |
| } |
| |
| bool detach(WebInspectorProxy&) override |
| { |
| gboolean returnValue; |
| g_signal_emit(m_inspector, signals[DETACH], 0, &returnValue); |
| return returnValue; |
| } |
| |
| void didChangeAttachedHeight(WebInspectorProxy&, unsigned height) override |
| { |
| if (m_inspector->priv->attachedHeight == height) |
| return; |
| m_inspector->priv->attachedHeight = height; |
| g_object_notify(G_OBJECT(m_inspector), "attached-height"); |
| } |
| |
| void didChangeAttachedWidth(WebInspectorProxy&, unsigned width) override |
| { |
| } |
| |
| void didChangeAttachAvailability(WebInspectorProxy&, bool available) override |
| { |
| if (m_inspector->priv->canAttach == available) |
| return; |
| m_inspector->priv->canAttach = available; |
| g_object_notify(G_OBJECT(m_inspector), "can-attach"); |
| } |
| |
| WebKitWebInspector* m_inspector; |
| }; |
| |
| WebKitWebInspector* webkitWebInspectorCreate(WebInspectorProxy* webInspector) |
| { |
| WebKitWebInspector* inspector = WEBKIT_WEB_INSPECTOR(g_object_new(WEBKIT_TYPE_WEB_INSPECTOR, NULL)); |
| inspector->priv->webInspector = webInspector; |
| webInspector->setClient(std::make_unique<WebKitInspectorClient>(inspector)); |
| return inspector; |
| } |
| |
| /** |
| * webkit_web_inspector_get_web_view: |
| * @inspector: a #WebKitWebInspector |
| * |
| * Get the #WebKitWebViewBase used to display the inspector. |
| * This might be %NULL if the inspector hasn't been loaded yet, |
| * or it has been closed. |
| * |
| * Returns: (transfer none): the #WebKitWebViewBase used to display the inspector or %NULL |
| */ |
| WebKitWebViewBase* webkit_web_inspector_get_web_view(WebKitWebInspector* inspector) |
| { |
| g_return_val_if_fail(WEBKIT_IS_WEB_INSPECTOR(inspector), 0); |
| |
| return WEBKIT_WEB_VIEW_BASE(inspector->priv->webInspector->inspectorView()); |
| } |
| |
| /** |
| * webkit_web_inspector_get_inspected_uri: |
| * @inspector: a #WebKitWebInspector |
| * |
| * Get the URI that is currently being inspected. This can be %NULL if |
| * nothing has been loaded yet in the inspected view, if the inspector |
| * has been closed or when inspected view was loaded from a HTML string |
| * instead of a URI. |
| * |
| * Returns: the URI that is currently being inspected or %NULL |
| */ |
| const char* webkit_web_inspector_get_inspected_uri(WebKitWebInspector* inspector) |
| { |
| g_return_val_if_fail(WEBKIT_IS_WEB_INSPECTOR(inspector), 0); |
| |
| return inspector->priv->inspectedURI.data(); |
| } |
| |
| /** |
| * webkit_web_inspector_get_can_attach: |
| * @inspector: a #WebKitWebInspector |
| * |
| * Whether the @inspector can be attached to the same window that contains |
| * the inspected view. |
| * |
| * Returns: %TRUE if there is enough room for the inspector view inside the |
| * window that contains the inspected view, or %FALSE otherwise. |
| * |
| * Since: 2.8 |
| */ |
| gboolean webkit_web_inspector_get_can_attach(WebKitWebInspector* inspector) |
| { |
| g_return_val_if_fail(WEBKIT_IS_WEB_INSPECTOR(inspector), FALSE); |
| |
| return inspector->priv->canAttach; |
| } |
| |
| /** |
| * webkit_web_inspector_is_attached: |
| * @inspector: a #WebKitWebInspector |
| * |
| * Whether the @inspector view is currently attached to the same window that contains |
| * the inspected view. |
| * |
| * Returns: %TRUE if @inspector is currently attached or %FALSE otherwise |
| */ |
| gboolean webkit_web_inspector_is_attached(WebKitWebInspector* inspector) |
| { |
| g_return_val_if_fail(WEBKIT_IS_WEB_INSPECTOR(inspector), FALSE); |
| |
| return inspector->priv->webInspector->isAttached(); |
| } |
| |
| /** |
| * webkit_web_inspector_attach: |
| * @inspector: a #WebKitWebInspector |
| * |
| * Request @inspector to be attached. The signal #WebKitWebInspector::attach |
| * will be emitted. If the inspector is already attached it does nothing. |
| */ |
| void webkit_web_inspector_attach(WebKitWebInspector* inspector) |
| { |
| g_return_if_fail(WEBKIT_IS_WEB_INSPECTOR(inspector)); |
| |
| if (inspector->priv->webInspector->isAttached()) |
| return; |
| inspector->priv->webInspector->attach(); |
| } |
| |
| /** |
| * webkit_web_inspector_detach: |
| * @inspector: a #WebKitWebInspector |
| * |
| * Request @inspector to be detached. The signal #WebKitWebInspector::detach |
| * will be emitted. If the inspector is already detached it does nothing. |
| */ |
| void webkit_web_inspector_detach(WebKitWebInspector* inspector) |
| { |
| g_return_if_fail(WEBKIT_IS_WEB_INSPECTOR(inspector)); |
| |
| if (!inspector->priv->webInspector->isAttached()) |
| return; |
| inspector->priv->webInspector->detach(); |
| } |
| |
| /** |
| * webkit_web_inspector_show: |
| * @inspector: a #WebKitWebInspector |
| * |
| * Request @inspector to be shown. |
| */ |
| void webkit_web_inspector_show(WebKitWebInspector* inspector) |
| { |
| g_return_if_fail(WEBKIT_IS_WEB_INSPECTOR(inspector)); |
| |
| inspector->priv->webInspector->show(); |
| } |
| |
| /** |
| * webkit_web_inspector_close: |
| * @inspector: a #WebKitWebInspector |
| * |
| * Request @inspector to be closed. |
| */ |
| void webkit_web_inspector_close(WebKitWebInspector* inspector) |
| { |
| g_return_if_fail(WEBKIT_IS_WEB_INSPECTOR(inspector)); |
| |
| inspector->priv->webInspector->close(); |
| } |
| |
| /** |
| * webkit_web_inspector_get_attached_height: |
| * @inspector: a #WebKitWebInspector |
| * |
| * Get the height that the inspector view should have when |
| * it's attached. If the inspector view is not attached this |
| * returns 0. |
| * |
| * Returns: the height of the inspector view when attached |
| */ |
| guint webkit_web_inspector_get_attached_height(WebKitWebInspector* inspector) |
| { |
| g_return_val_if_fail(WEBKIT_IS_WEB_INSPECTOR(inspector), 0); |
| |
| if (!inspector->priv->webInspector->isAttached()) |
| return 0; |
| return inspector->priv->attachedHeight; |
| } |