• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
notifyWebViewDestroyed(WebKitWebView * webView,InspectorFrontendClient * inspectorFrontendClient)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:
~InspectorFrontendSettingsGtk()48     virtual ~InspectorFrontendSettingsGtk() { }
49 #ifdef HAVE_GSETTINGS
shouldIgnoreSetting(const String & key)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 
getProperty(const String & name)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 
setProperty(const String & name,const String & value)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
getProperty(const String &)87     virtual String getProperty(const String&)
88     {
89         notImplemented();
90         return String();
91     }
92 
setProperty(const String &,const String &)93     virtual void setProperty(const String&, const String&)
94     {
95         notImplemented();
96     }
97 #endif // HAVE_GSETTINGS
98 };
99 
100 } // namespace
101 
InspectorClient(WebKitWebView * webView)102 InspectorClient::InspectorClient(WebKitWebView* webView)
103     : m_inspectedWebView(webView)
104     , m_frontendPage(0)
105     , m_frontendClient(0)
106 {}
107 
~InspectorClient()108 InspectorClient::~InspectorClient()
109 {
110     if (m_frontendClient) {
111         m_frontendClient->disconnectInspectorClient();
112         m_frontendClient = 0;
113     }
114 }
115 
inspectorDestroyed()116 void InspectorClient::inspectorDestroyed()
117 {
118     delete this;
119 }
120 
openInspectorFrontend(InspectorController * controller)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 
releaseFrontendPage()156 void InspectorClient::releaseFrontendPage()
157 {
158     m_frontendPage = 0;
159 }
160 
highlight(Node *)161 void InspectorClient::highlight(Node*)
162 {
163     hideHighlight();
164 }
165 
hideHighlight()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 
sendMessageToFrontend(const String & message)175 bool InspectorClient::sendMessageToFrontend(const String& message)
176 {
177     return doDispatchMessageOnFrontendPage(m_frontendPage, message);
178 }
179 
inspectorFilesPath()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 
InspectorFrontendClient(WebKitWebView * inspectedWebView,WebKitWebView * inspectorWebView,WebKitWebInspector * webInspector,Page * inspectorPage,InspectorClient * inspectorClient)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 
~InspectorFrontendClient()205 InspectorFrontendClient::~InspectorFrontendClient()
206 {
207     if (m_inspectorClient) {
208         m_inspectorClient->disconnectFrontendClient();
209         m_inspectorClient = 0;
210     }
211     ASSERT(!m_webInspector);
212 }
213 
destroyInspectorWindow(bool notifyInspectorController)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 
localizedStringsURL()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 
hiddenPanels()250 String InspectorFrontendClient::hiddenPanels()
251 {
252     notImplemented();
253     return String();
254 }
255 
bringToFront()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 
closeWindow()265 void InspectorFrontendClient::closeWindow()
266 {
267     destroyInspectorWindow(true);
268 }
269 
disconnectFromBackend()270 void InspectorFrontendClient::disconnectFromBackend()
271 {
272     destroyInspectorWindow(false);
273 }
274 
attachWindow()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 
detachWindow()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 
setAttachedWindowHeight(unsigned height)293 void InspectorFrontendClient::setAttachedWindowHeight(unsigned height)
294 {
295     notImplemented();
296 }
297 
inspectedURLChanged(const String & newURL)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