diff -r 000000000000 -r 4f2f89ce4247 WebKit/gtk/webkit/webkitwebinspector.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebKit/gtk/webkit/webkitwebinspector.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,561 @@ +/* + * Copyright (C) 2008 Gustavo Noronha Silva + * Copyright (C) 2008, 2009 Holger Hans Peter Freyther + * Copyright (C) 2009 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 "FocusController.h" +#include "Frame.h" +#include +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "InspectorClientGtk.h" +#include "IntPoint.h" +#include "Page.h" +#include "RenderLayer.h" +#include "RenderView.h" +#include "webkitmarshal.h" +#include "webkitprivate.h" + +/** + * SECTION:webkitwebinspector + * @short_description: Access to the WebKit Inspector + * + * The WebKit Inspector is a graphical tool to inspect and change + * the content of a #WebKitWebView. It also includes an interactive + * JavaScriptDebugger. 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 #WebKitWebSettings of the + * #WebKitWebView has set the #WebKitWebSettings:enable-developer-extras + * to true otherwise no inspector is available. + * + * + * /* Enable the developer extras */ + * WebKitWebSettings *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_view_open (WEBKIT_WEB_VIEW(my_webview), "http://www.gnome.org"); + * + * /* Embed the inspector somewhere */ + * WebKitWebInspector *inspector = webkit_web_view_get_inspector (WEBKIT_WEB_VIEW(my_webview)); + * g_signal_connect (G_OBJECT (inspector), "inspect-web-view", G_CALLBACK(create_gtk_window_around_it), NULL); + * g_signal_connect (G_OBJECT (inspector), "show-window", G_CALLBACK(show_inpector_window), NULL)); + * g_signal_connect (G_OBJECT (inspector), "notify::inspected-uri", G_CALLBACK(inspected_uri_changed_do_stuff), NULL); + * + */ + +using namespace WebKit; +using namespace WebCore; + +enum { + INSPECT_WEB_VIEW, + SHOW_WINDOW, + ATTACH_WINDOW, + DETACH_WINDOW, + CLOSE_WINDOW, + FINISHED, + LAST_SIGNAL +}; + +static guint webkit_web_inspector_signals[LAST_SIGNAL] = { 0, }; + +enum { + PROP_0, + + PROP_WEB_VIEW, + PROP_INSPECTED_URI, + PROP_JAVASCRIPT_PROFILING_ENABLED, + PROP_TIMELINE_PROFILING_ENABLED +}; + +G_DEFINE_TYPE(WebKitWebInspector, webkit_web_inspector, G_TYPE_OBJECT) + +struct _WebKitWebInspectorPrivate { + WebCore::Page* page; + WebKitWebView* inspector_view; + gchar* inspected_uri; +}; + +#define WEBKIT_WEB_INSPECTOR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_WEB_INSPECTOR, WebKitWebInspectorPrivate)) + +static void webkit_web_inspector_finalize(GObject* object); + +static void webkit_web_inspector_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec); + +static void webkit_web_inspector_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec); + +static gboolean webkit_inspect_web_view_request_handled(GSignalInvocationHint* ihint, GValue* returnAccu, const GValue* handlerReturn, gpointer dummy) +{ + gboolean continueEmission = TRUE; + gpointer newWebView = g_value_get_object(handlerReturn); + g_value_set_object(returnAccu, newWebView); + + if (newWebView) + continueEmission = FALSE; + + return continueEmission; +} + +static void webkit_web_inspector_class_init(WebKitWebInspectorClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + gobject_class->finalize = webkit_web_inspector_finalize; + gobject_class->set_property = webkit_web_inspector_set_property; + gobject_class->get_property = webkit_web_inspector_get_property; + + /** + * WebKitWebInspector::inspect-web-view: + * @web_inspector: the object on which the signal is emitted + * @web_view: the #WebKitWebView which will be inspected + * @return: a newly allocated #WebKitWebView or %NULL + * + * Emitted when the user activates the 'inspect' context menu item + * to inspect a web view. The application which is interested in + * the inspector should create a window, or otherwise add the + * #WebKitWebView it creates to an existing window. + * + * You don't need to handle the reference count of the + * #WebKitWebView instance you create; the widget to which you add + * it will do that. + * + * Since: 1.0.3 + */ + webkit_web_inspector_signals[INSPECT_WEB_VIEW] = g_signal_new("inspect-web-view", + G_TYPE_FROM_CLASS(klass), + (GSignalFlags)G_SIGNAL_RUN_LAST, + 0, + webkit_inspect_web_view_request_handled, + NULL, + webkit_marshal_OBJECT__OBJECT, + WEBKIT_TYPE_WEB_VIEW , 1, + WEBKIT_TYPE_WEB_VIEW); + + /** + * WebKitWebInspector::show-window: + * @web_inspector: the object on which the signal is emitted + * @return: %TRUE if the signal has been handled + * + * Emitted when the inspector window should be displayed. Notice + * that the window must have been created already by handling + * #WebKitWebInspector::inspect-web-view. + * + * Since: 1.0.3 + */ + webkit_web_inspector_signals[SHOW_WINDOW] = g_signal_new("show-window", + G_TYPE_FROM_CLASS(klass), + (GSignalFlags)G_SIGNAL_RUN_LAST, + 0, + g_signal_accumulator_true_handled, + NULL, + webkit_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN , 0); + + /** + * WebKitWebInspector::attach-window: + * @web_inspector: the object on which the signal is emitted + * @return: %TRUE if the signal has been handled + * + * Emitted when the inspector should appear at the same window as + * the #WebKitWebView being inspected. + * + * Since: 1.0.3 + */ + webkit_web_inspector_signals[ATTACH_WINDOW] = g_signal_new("attach-window", + G_TYPE_FROM_CLASS(klass), + (GSignalFlags)G_SIGNAL_RUN_LAST, + 0, + g_signal_accumulator_true_handled, + NULL, + webkit_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN , 0); + + /** + * WebKitWebInspector::detach-window: + * @web_inspector: the object on which the signal is emitted + * @return: %TRUE if the signal has been handled + * + * Emitted when the inspector should appear in a separate window. + * + * Since: 1.0.3 + */ + webkit_web_inspector_signals[DETACH_WINDOW] = g_signal_new("detach-window", + G_TYPE_FROM_CLASS(klass), + (GSignalFlags)G_SIGNAL_RUN_LAST, + 0, + g_signal_accumulator_true_handled, + NULL, + webkit_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN , 0); + + /** + * WebKitWebInspector::close-window: + * @web_inspector: the object on which the signal is emitted + * @return: %TRUE if the signal has been handled + * + * Emitted when the inspector window should be closed. You can + * destroy the window or hide it so that it can be displayed again + * by handling #WebKitWebInspector::show-window later on. + * + * Notice that the inspected #WebKitWebView may no longer exist + * when this signal is emitted. + * + * Notice, too, that if you decide to destroy the window, + * #WebKitWebInspector::inspect-web-view will be emmited again, when the user + * inspects an element. + * + * Since: 1.0.3 + */ + webkit_web_inspector_signals[CLOSE_WINDOW] = g_signal_new("close-window", + G_TYPE_FROM_CLASS(klass), + (GSignalFlags)G_SIGNAL_RUN_LAST, + 0, + g_signal_accumulator_true_handled, + NULL, + webkit_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN , 0); + + /** + * WebKitWebInspector::finished: + * @web_inspector: the object on which the signal is emitted + * + * Emitted when the inspection is done. You should release your + * references on the inspector at this time. The inspected + * #WebKitWebView may no longer exist when this signal is emitted. + * + * Since: 1.0.3 + */ + webkit_web_inspector_signals[FINISHED] = g_signal_new("finished", + G_TYPE_FROM_CLASS(klass), + (GSignalFlags)G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE , 0); + + /* + * properties + */ + + /** + * WebKitWebInspector:web-view: + * + * The Web View that renders the Web Inspector itself. + * + * Since: 1.0.3 + */ + g_object_class_install_property(gobject_class, PROP_WEB_VIEW, + g_param_spec_object("web-view", + _("Web View"), + _("The Web View that renders the Web Inspector itself"), + WEBKIT_TYPE_WEB_VIEW, + WEBKIT_PARAM_READABLE)); + + /** + * WebKitWebInspector:inspected-uri: + * + * The URI that is currently being inspected. + * + * Since: 1.0.3 + */ + g_object_class_install_property(gobject_class, PROP_INSPECTED_URI, + g_param_spec_string("inspected-uri", + _("Inspected URI"), + _("The URI that is currently being inspected"), + NULL, + WEBKIT_PARAM_READABLE)); + + /** + * WebKitWebInspector:javascript-profiling-enabled + * + * This is enabling JavaScript profiling in the Inspector. This means + * that Console.profiles will return the profiles. + * + * Since: 1.1.1 + */ + g_object_class_install_property(gobject_class, + PROP_JAVASCRIPT_PROFILING_ENABLED, + g_param_spec_boolean( + "javascript-profiling-enabled", + _("Enable JavaScript profiling"), + _("Profile the executed JavaScript."), + FALSE, + WEBKIT_PARAM_READWRITE)); + + /** + * WebKitWebInspector:timeline-profiling-enabled + * + * This is enabling Timeline profiling in the Inspector. + * + * Since: 1.1.17 + */ + g_object_class_install_property(gobject_class, + PROP_TIMELINE_PROFILING_ENABLED, + g_param_spec_boolean( + "timeline-profiling-enabled", + _("Enable Timeline profiling"), + _("Profile the WebCore instrumentation."), + FALSE, + WEBKIT_PARAM_READWRITE)); + + g_type_class_add_private(klass, sizeof(WebKitWebInspectorPrivate)); +} + +static void webkit_web_inspector_init(WebKitWebInspector* web_inspector) +{ + web_inspector->priv = WEBKIT_WEB_INSPECTOR_GET_PRIVATE(web_inspector); +} + +static void webkit_web_inspector_finalize(GObject* object) +{ + WebKitWebInspector* web_inspector = WEBKIT_WEB_INSPECTOR(object); + WebKitWebInspectorPrivate* priv = web_inspector->priv; + + if (priv->inspector_view) + g_object_unref(priv->inspector_view); + + if (priv->inspected_uri) + g_free(priv->inspected_uri); + + G_OBJECT_CLASS(webkit_web_inspector_parent_class)->finalize(object); +} + +static void webkit_web_inspector_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) +{ + WebKitWebInspector* web_inspector = WEBKIT_WEB_INSPECTOR(object); + WebKitWebInspectorPrivate* priv = web_inspector->priv; + + switch(prop_id) { + case PROP_JAVASCRIPT_PROFILING_ENABLED: { +#if ENABLE(JAVASCRIPT_DEBUGGER) + bool enabled = g_value_get_boolean(value); + WebCore::InspectorController* controller = priv->page->inspectorController(); + if (enabled) + controller->enableProfiler(); + else + controller->disableProfiler(); +#else + g_message("PROP_JAVASCRIPT_PROFILING_ENABLED is not work because of the javascript debugger is disabled\n"); +#endif + break; + } + case PROP_TIMELINE_PROFILING_ENABLED: { + bool enabled = g_value_get_boolean(value); + WebCore::InspectorController* controller = priv->page->inspectorController(); + if (enabled) + controller->startTimelineProfiler(); + else + controller->stopTimelineProfiler(); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void webkit_web_inspector_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec) +{ + WebKitWebInspector* web_inspector = WEBKIT_WEB_INSPECTOR(object); + WebKitWebInspectorPrivate* priv = web_inspector->priv; + + switch (prop_id) { + case PROP_WEB_VIEW: + g_value_set_object(value, priv->inspector_view); + break; + case PROP_INSPECTED_URI: + g_value_set_string(value, priv->inspected_uri); + break; + case PROP_JAVASCRIPT_PROFILING_ENABLED: +#if ENABLE(JAVASCRIPT_DEBUGGER) + g_value_set_boolean(value, priv->page->inspectorController()->profilerEnabled()); +#else + g_message("PROP_JAVASCRIPT_PROFILING_ENABLED is not work because of the javascript debugger is disabled\n"); +#endif + break; + case PROP_TIMELINE_PROFILING_ENABLED: + g_value_set_boolean(value, priv->page->inspectorController()->timelineAgent() != 0); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +// internal use only +void webkit_web_inspector_set_web_view(WebKitWebInspector *web_inspector, WebKitWebView *web_view) +{ + g_return_if_fail(WEBKIT_IS_WEB_INSPECTOR(web_inspector)); + g_return_if_fail(WEBKIT_IS_WEB_VIEW(web_view)); + + WebKitWebInspectorPrivate* priv = web_inspector->priv; + + if (priv->inspector_view) + g_object_unref(priv->inspector_view); + + g_object_ref(web_view); + priv->inspector_view = web_view; +} + +/** + * webkit_web_inspector_get_web_view: + * + * Obtains the #WebKitWebView that is used to render the + * inspector. The #WebKitWebView instance is created by the + * application, by handling the #WebKitWebInspector::inspect-web-view signal. This means + * that this method may return %NULL if the user hasn't inspected + * anything. + * + * Returns: the #WebKitWebView instance that is used to render the + * inspector or %NULL if it is not yet created. + * + * Since: 1.0.3 + **/ +WebKitWebView* webkit_web_inspector_get_web_view(WebKitWebInspector *web_inspector) +{ + WebKitWebInspectorPrivate* priv = web_inspector->priv; + + return priv->inspector_view; +} + +// internal use only +void webkit_web_inspector_set_inspected_uri(WebKitWebInspector* web_inspector, const gchar* inspected_uri) +{ + g_return_if_fail(WEBKIT_IS_WEB_INSPECTOR(web_inspector)); + + WebKitWebInspectorPrivate* priv = web_inspector->priv; + + g_free(priv->inspected_uri); + priv->inspected_uri = g_strdup(inspected_uri); +} + +/** + * webkit_web_inspector_get_inspected_uri: + * + * Obtains the URI that is currently being inspected. + * + * Returns: a pointer to the URI as an internally allocated string; it + * should not be freed, modified or stored. + * + * Since: 1.0.3 + **/ +const gchar* webkit_web_inspector_get_inspected_uri(WebKitWebInspector *web_inspector) +{ + WebKitWebInspectorPrivate* priv = web_inspector->priv; + + return priv->inspected_uri; +} + +void +webkit_web_inspector_set_inspector_client(WebKitWebInspector* web_inspector, WebCore::Page* page) +{ + WebKitWebInspectorPrivate* priv = web_inspector->priv; + + priv->page = page; +} + +/** + * webkit_web_inspector_show: + * @web_inspector: the #WebKitWebInspector that will be shown + * + * Causes the Web Inspector to be shown. + * + * Since: 1.1.17 + */ +void webkit_web_inspector_show(WebKitWebInspector* webInspector) +{ + g_return_if_fail(WEBKIT_IS_WEB_INSPECTOR(webInspector)); + + WebKitWebInspectorPrivate* priv = webInspector->priv; + + Frame* frame = priv->page->focusController()->focusedOrMainFrame(); + FrameView* view = frame->view(); + + if (!view) + return; + + priv->page->inspectorController()->show(); +} + +/** + * webkit_web_inspector_inspect_coordinates: + * @web_inspector: the #WebKitWebInspector that will do the inspection + * @x: the X coordinate of the node to be inspected + * @y: the Y coordinate of the node to be inspected + * + * Causes the Web Inspector to inspect the node that is located at the + * given coordinates of the widget. The coordinates should be relative + * to the #WebKitWebView widget, not to the scrollable content, and + * may be obtained from a #GdkEvent directly. + * + * This means @x, and @y being zero doesn't guarantee you will hit the + * left-most top corner of the content, since the contents may have + * been scrolled. + * + * Since: 1.1.17 + */ +void webkit_web_inspector_inspect_coordinates(WebKitWebInspector* webInspector, gdouble x, gdouble y) +{ + g_return_if_fail(WEBKIT_IS_WEB_INSPECTOR(webInspector)); + g_return_if_fail(x >= 0 && y >= 0); + + WebKitWebInspectorPrivate* priv = webInspector->priv; + + Frame* frame = priv->page->focusController()->focusedOrMainFrame(); + FrameView* view = frame->view(); + + if (!view) + return; + + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); + IntPoint documentPoint = view->windowToContents(IntPoint(static_cast(x), static_cast(y))); + HitTestResult result(documentPoint); + + frame->contentRenderer()->layer()->hitTest(request, result); + priv->page->inspectorController()->inspect(result.innerNonSharedNode()); +} + +/** + * webkit_web_inspector_close: + * @web_inspector: the #WebKitWebInspector that will be closed + * + * Causes the Web Inspector to be closed. + * + * Since: 1.1.17 + */ +void webkit_web_inspector_close(WebKitWebInspector* webInspector) +{ + g_return_if_fail(WEBKIT_IS_WEB_INSPECTOR(webInspector)); + + WebKitWebInspectorPrivate* priv = webInspector->priv; + priv->page->inspectorController()->close(); +} + +void webkit_web_inspector_execute_script(WebKitWebInspector* webInspector, long callId, const gchar* script) +{ + g_return_if_fail(WEBKIT_IS_WEB_INSPECTOR(webInspector)); + g_return_if_fail(script); + + WebKitWebInspectorPrivate* priv = webInspector->priv; + priv->page->inspectorController()->evaluateForTestInFrontend(callId, script); +}