Home | History | Annotate | Download | only in WebCoreSupport
      1 /*
      2  * Copyright (C) 2008 Gustavo Noronha Silva
      3  * Copyright (C) 2010 Collabora Ltd.
      4  *
      5  *  This library is free software; you can redistribute it and/or
      6  *  modify it under the terms of the GNU Lesser General Public
      7  *  License as published by the Free Software Foundation; either
      8  *  version 2 of the License, or (at your option) any later version.
      9  *
     10  *  This library is distributed in the hope that it will be useful,
     11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  *  Lesser General Public License for more details.
     14  *
     15  *  You should have received a copy of the GNU Lesser General Public
     16  *  License along with this library; if not, write to the Free Software
     17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     18  */
     19 
     20 #include "config.h"
     21 #include "InspectorClientGtk.h"
     22 
     23 #include "Frame.h"
     24 #include "InspectorController.h"
     25 #include "NotImplemented.h"
     26 #include "Page.h"
     27 #include "PlatformString.h"
     28 #include "webkitversion.h"
     29 #include "webkitwebinspector.h"
     30 #include "webkitwebinspectorprivate.h"
     31 #include "webkitwebview.h"
     32 #include "webkitwebviewprivate.h"
     33 #include <wtf/text/CString.h>
     34 
     35 using namespace WebCore;
     36 
     37 namespace WebKit {
     38 
     39 static void notifyWebViewDestroyed(WebKitWebView* webView, InspectorFrontendClient* inspectorFrontendClient)
     40 {
     41     inspectorFrontendClient->destroyInspectorWindow(true);
     42 }
     43 
     44 namespace {
     45 
     46 class InspectorFrontendSettingsGtk : public InspectorFrontendClientLocal::Settings {
     47 private:
     48     virtual ~InspectorFrontendSettingsGtk() { }
     49 #ifdef HAVE_GSETTINGS
     50     static bool shouldIgnoreSetting(const String& key)
     51     {
     52         // GSettings considers trying to fetch or set a setting that is
     53         // not backed by a schema as programmer error, and aborts the
     54         // program's execution. We check here to avoid having an unhandled
     55         // setting as a fatal error.
     56         LOG_VERBOSE(NotYetImplemented, "Unknown key ignored: %s", key.ascii().data());
     57         return true;
     58     }
     59 
     60     virtual String getProperty(const String& name)
     61     {
     62         if (shouldIgnoreSetting(name))
     63             return String();
     64 
     65         GSettings* settings = inspectorGSettings();
     66         if (!settings)
     67             return String();
     68 
     69         GRefPtr<GVariant> variant = adoptGRef(g_settings_get_value(settings, name.utf8().data()));
     70         return String(g_variant_get_string(variant.get(), 0));
     71     }
     72 
     73     virtual void setProperty(const String& name, const String& value)
     74     {
     75         // Avoid setting unknown keys to avoid aborting the execution.
     76         if (shouldIgnoreSetting(name))
     77             return;
     78 
     79         GSettings* settings = inspectorGSettings();
     80         if (!settings)
     81             return;
     82 
     83         GRefPtr<GVariant> variant = adoptGRef(g_variant_new_string(value.utf8().data()));
     84         g_settings_set_value(settings, name.utf8().data(), variant.get());
     85     }
     86 #else
     87     virtual String getProperty(const String&)
     88     {
     89         notImplemented();
     90         return String();
     91     }
     92 
     93     virtual void setProperty(const String&, const String&)
     94     {
     95         notImplemented();
     96     }
     97 #endif // HAVE_GSETTINGS
     98 };
     99 
    100 } // namespace
    101 
    102 InspectorClient::InspectorClient(WebKitWebView* webView)
    103     : m_inspectedWebView(webView)
    104     , m_frontendPage(0)
    105     , m_frontendClient(0)
    106 {}
    107 
    108 InspectorClient::~InspectorClient()
    109 {
    110     if (m_frontendClient) {
    111         m_frontendClient->disconnectInspectorClient();
    112         m_frontendClient = 0;
    113     }
    114 }
    115 
    116 void InspectorClient::inspectorDestroyed()
    117 {
    118     delete this;
    119 }
    120 
    121 void InspectorClient::openInspectorFrontend(InspectorController* controller)
    122 {
    123     // This g_object_get will ref the inspector. We're not doing an
    124     // unref if this method succeeds because the inspector object must
    125     // be alive even after the inspected WebView is destroyed - the
    126     // close-window and destroy signals still need to be
    127     // emitted.
    128     WebKitWebInspector* webInspector = 0;
    129     g_object_get(m_inspectedWebView, "web-inspector", &webInspector, NULL);
    130     ASSERT(webInspector);
    131 
    132     WebKitWebView* inspectorWebView = 0;
    133     g_signal_emit_by_name(webInspector, "inspect-web-view", m_inspectedWebView, &inspectorWebView);
    134 
    135     if (!inspectorWebView) {
    136         g_object_unref(webInspector);
    137         return;
    138     }
    139 
    140     webkit_web_inspector_set_web_view(webInspector, inspectorWebView);
    141 
    142     GOwnPtr<gchar> inspectorPath(g_build_filename(inspectorFilesPath(), "inspector.html", NULL));
    143     GOwnPtr<gchar> inspectorURI(g_filename_to_uri(inspectorPath.get(), 0, 0));
    144     webkit_web_view_load_uri(inspectorWebView, inspectorURI.get());
    145 
    146     gtk_widget_show(GTK_WIDGET(inspectorWebView));
    147 
    148     m_frontendPage = core(inspectorWebView);
    149     m_frontendClient = new InspectorFrontendClient(m_inspectedWebView, inspectorWebView, webInspector, m_frontendPage, this);
    150     m_frontendPage->inspectorController()->setInspectorFrontendClient(m_frontendClient);
    151 
    152     // The inspector must be in it's own PageGroup to avoid deadlock while debugging.
    153     m_frontendPage->setGroupName("");
    154 }
    155 
    156 void InspectorClient::releaseFrontendPage()
    157 {
    158     m_frontendPage = 0;
    159 }
    160 
    161 void InspectorClient::highlight(Node*)
    162 {
    163     hideHighlight();
    164 }
    165 
    166 void InspectorClient::hideHighlight()
    167 {
    168     // FIXME: we should be able to only invalidate the actual rects of
    169     // the new and old nodes. We need to track the nodes, and take the
    170     // actual highlight size into account when calculating the damage
    171     // rect.
    172     gtk_widget_queue_draw(GTK_WIDGET(m_inspectedWebView));
    173 }
    174 
    175 bool InspectorClient::sendMessageToFrontend(const String& message)
    176 {
    177     return doDispatchMessageOnFrontendPage(m_frontendPage, message);
    178 }
    179 
    180 const char* InspectorClient::inspectorFilesPath()
    181 {
    182     if (m_inspectorFilesPath)
    183         m_inspectorFilesPath.get();
    184 
    185     const char* environmentPath = getenv("WEBKIT_INSPECTOR_PATH");
    186     if (environmentPath && g_file_test(environmentPath, G_FILE_TEST_IS_DIR))
    187         m_inspectorFilesPath.set(g_strdup(environmentPath));
    188     else
    189         m_inspectorFilesPath.set(g_build_filename(DATA_DIR, "webkitgtk-"WEBKITGTK_API_VERSION_STRING, "webinspector", NULL));
    190 
    191     return m_inspectorFilesPath.get();
    192 }
    193 
    194 InspectorFrontendClient::InspectorFrontendClient(WebKitWebView* inspectedWebView, WebKitWebView* inspectorWebView, WebKitWebInspector* webInspector, Page* inspectorPage, InspectorClient* inspectorClient)
    195     : InspectorFrontendClientLocal(core(inspectedWebView)->inspectorController(), inspectorPage, new InspectorFrontendSettingsGtk())
    196     , m_inspectorWebView(inspectorWebView)
    197     , m_inspectedWebView(inspectedWebView)
    198     , m_webInspector(webInspector)
    199     , m_inspectorClient(inspectorClient)
    200 {
    201     g_signal_connect(m_inspectorWebView, "destroy",
    202                      G_CALLBACK(notifyWebViewDestroyed), (gpointer)this);
    203 }
    204 
    205 InspectorFrontendClient::~InspectorFrontendClient()
    206 {
    207     if (m_inspectorClient) {
    208         m_inspectorClient->disconnectFrontendClient();
    209         m_inspectorClient = 0;
    210     }
    211     ASSERT(!m_webInspector);
    212 }
    213 
    214 void InspectorFrontendClient::destroyInspectorWindow(bool notifyInspectorController)
    215 {
    216     if (!m_webInspector)
    217         return;
    218     WebKitWebInspector* webInspector = m_webInspector;
    219     m_webInspector = 0;
    220 
    221     g_signal_handlers_disconnect_by_func(m_inspectorWebView, (gpointer)notifyWebViewDestroyed, (gpointer)this);
    222     m_inspectorWebView = 0;
    223 
    224     if (notifyInspectorController)
    225         core(m_inspectedWebView)->inspectorController()->disconnectFrontend();
    226 
    227     if (m_inspectorClient)
    228         m_inspectorClient->releaseFrontendPage();
    229 
    230     gboolean handled = FALSE;
    231     g_signal_emit_by_name(webInspector, "close-window", &handled);
    232     ASSERT(handled);
    233 
    234     // Please do not use member variables here because InspectorFrontendClient object pointed by 'this'
    235     // has been implicitly deleted by "close-window" function.
    236 
    237     /* we should now dispose our own reference */
    238     g_object_unref(webInspector);
    239 }
    240 
    241 String InspectorFrontendClient::localizedStringsURL()
    242 {
    243     GOwnPtr<gchar> stringsPath(g_build_filename(m_inspectorClient->inspectorFilesPath(), "localizedStrings.js", NULL));
    244     GOwnPtr<gchar> stringsURI(g_filename_to_uri(stringsPath.get(), 0, 0));
    245 
    246     // FIXME: support l10n of localizedStrings.js
    247     return String::fromUTF8(stringsURI.get());
    248 }
    249 
    250 String InspectorFrontendClient::hiddenPanels()
    251 {
    252     notImplemented();
    253     return String();
    254 }
    255 
    256 void InspectorFrontendClient::bringToFront()
    257 {
    258     if (!m_inspectorWebView)
    259         return;
    260 
    261     gboolean handled = FALSE;
    262     g_signal_emit_by_name(m_webInspector, "show-window", &handled);
    263 }
    264 
    265 void InspectorFrontendClient::closeWindow()
    266 {
    267     destroyInspectorWindow(true);
    268 }
    269 
    270 void InspectorFrontendClient::disconnectFromBackend()
    271 {
    272     destroyInspectorWindow(false);
    273 }
    274 
    275 void InspectorFrontendClient::attachWindow()
    276 {
    277     if (!m_inspectorWebView)
    278         return;
    279 
    280     gboolean handled = FALSE;
    281     g_signal_emit_by_name(m_webInspector, "attach-window", &handled);
    282 }
    283 
    284 void InspectorFrontendClient::detachWindow()
    285 {
    286     if (!m_inspectorWebView)
    287         return;
    288 
    289     gboolean handled = FALSE;
    290     g_signal_emit_by_name(m_webInspector, "detach-window", &handled);
    291 }
    292 
    293 void InspectorFrontendClient::setAttachedWindowHeight(unsigned height)
    294 {
    295     notImplemented();
    296 }
    297 
    298 void InspectorFrontendClient::inspectedURLChanged(const String& newURL)
    299 {
    300     if (!m_inspectorWebView)
    301         return;
    302 
    303     webkit_web_inspector_set_inspected_uri(m_webInspector, newURL.utf8().data());
    304 }
    305 
    306 }
    307 
    308