1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
4 * Copyright (C) 2012 Igalia S.L.
5 * Copyright (C) 2013 Gustavo Noronha Silva <gns@gnome.org>.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "WebInspectorProxy.h"
31
32#if ENABLE(INSPECTOR)
33
34#include "WebKitWebViewBasePrivate.h"
35#include "WebProcessProxy.h"
36#include <WebCore/FileSystem.h>
37#include <WebCore/GtkUtilities.h>
38#include <WebCore/NotImplemented.h>
39#include <glib/gi18n-lib.h>
40#include <gtk/gtk.h>
41#include <wtf/gobject/GUniquePtr.h>
42#include <wtf/text/CString.h>
43#include <wtf/text/WTFString.h>
44
45namespace WebKit {
46
47static void inspectorViewDestroyed(GtkWidget*, gpointer userData)
48{
49    WebInspectorProxy* inspectorProxy = static_cast<WebInspectorProxy*>(userData);
50
51    // Inform WebProcess about webinspector closure. Not doing so,
52    // results in failure of subsequent invocation of webinspector.
53    inspectorProxy->close();
54}
55
56void WebInspectorProxy::initializeInspectorClientGtk(const WKInspectorClientGtkBase* inspectorClient)
57{
58    m_client.initialize(inspectorClient);
59}
60
61WebPageProxy* WebInspectorProxy::platformCreateInspectorPage()
62{
63    ASSERT(m_page);
64    ASSERT(!m_inspectorView);
65    m_inspectorView = GTK_WIDGET(webkitWebViewBaseCreate(&page()->process().context(), inspectorPageGroup(), nullptr, m_page));
66    g_object_add_weak_pointer(G_OBJECT(m_inspectorView), reinterpret_cast<void**>(&m_inspectorView));
67    return webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(m_inspectorView));
68}
69
70void WebInspectorProxy::createInspectorWindow()
71{
72    if (m_client.openWindow(this))
73        return;
74
75    ASSERT(!m_inspectorWindow);
76    m_inspectorWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
77
78    GtkWidget* inspectedViewParent = gtk_widget_get_toplevel(m_page->viewWidget());
79    if (WebCore::widgetIsOnscreenToplevelWindow(inspectedViewParent))
80        gtk_window_set_transient_for(GTK_WINDOW(m_inspectorWindow), GTK_WINDOW(inspectedViewParent));
81
82    gtk_window_set_title(GTK_WINDOW(m_inspectorWindow), _("Web Inspector"));
83    gtk_window_set_default_size(GTK_WINDOW(m_inspectorWindow), initialWindowWidth, initialWindowHeight);
84
85    gtk_container_add(GTK_CONTAINER(m_inspectorWindow), m_inspectorView);
86    gtk_widget_show(m_inspectorView);
87
88    g_object_add_weak_pointer(G_OBJECT(m_inspectorWindow), reinterpret_cast<void**>(&m_inspectorWindow));
89    gtk_window_present(GTK_WINDOW(m_inspectorWindow));
90}
91
92void WebInspectorProxy::platformOpen()
93{
94    ASSERT(!m_inspectorWindow);
95    ASSERT(m_inspectorView);
96
97    if (m_isAttached)
98        platformAttach();
99    else
100        createInspectorWindow();
101    g_signal_connect(m_inspectorView, "destroy", G_CALLBACK(inspectorViewDestroyed), this);
102}
103
104void WebInspectorProxy::platformDidClose()
105{
106    if (m_inspectorView)
107        g_signal_handlers_disconnect_by_func(m_inspectorView, reinterpret_cast<void*>(inspectorViewDestroyed), this);
108
109    m_client.didClose(this);
110
111    if (m_inspectorWindow) {
112        gtk_widget_destroy(m_inspectorWindow);
113        m_inspectorWindow = 0;
114    }
115    m_inspectorView = 0;
116}
117
118void WebInspectorProxy::platformHide()
119{
120    notImplemented();
121}
122
123void WebInspectorProxy::platformBringToFront()
124{
125    if (m_client.bringToFront(this))
126        return;
127
128    GtkWidget* parent = gtk_widget_get_toplevel(m_inspectorView);
129    if (WebCore::widgetIsOnscreenToplevelWindow(parent))
130        gtk_window_present(GTK_WINDOW(parent));
131}
132
133bool WebInspectorProxy::platformIsFront()
134{
135    GtkWidget* parent = gtk_widget_get_toplevel(m_inspectorView);
136    if (WebCore::widgetIsOnscreenToplevelWindow(parent))
137        return m_isVisible && gtk_window_is_active(GTK_WINDOW(parent));
138    return false;
139}
140
141void WebInspectorProxy::platformInspectedURLChanged(const String& url)
142{
143    m_client.inspectedURLChanged(this, url);
144
145    if (!m_inspectorWindow)
146        return;
147    GUniquePtr<gchar> title(g_strdup_printf("%s - %s", _("Web Inspector"), url.utf8().data()));
148    gtk_window_set_title(GTK_WINDOW(m_inspectorWindow), title.get());
149}
150
151String WebInspectorProxy::inspectorPageURL() const
152{
153    return String("resource:///org/webkitgtk/inspector/UserInterface/Main.html");
154}
155
156String WebInspectorProxy::inspectorTestPageURL() const
157{
158    return String("resource:///org/webkitgtk/inspector/UserInterface/Test.html");
159}
160
161String WebInspectorProxy::inspectorBaseURL() const
162{
163    return String("resource:///org/webkitgtk/inspector/UserInterface/");
164}
165
166unsigned WebInspectorProxy::platformInspectedWindowHeight()
167{
168    return gtk_widget_get_allocated_height(m_page->viewWidget());
169}
170
171unsigned WebInspectorProxy::platformInspectedWindowWidth()
172{
173    return gtk_widget_get_allocated_width(m_page->viewWidget());
174}
175
176void WebInspectorProxy::platformAttach()
177{
178    GRefPtr<GtkWidget> inspectorView = m_inspectorView;
179    if (m_inspectorWindow) {
180        gtk_container_remove(GTK_CONTAINER(m_inspectorWindow), m_inspectorView);
181        gtk_widget_destroy(m_inspectorWindow);
182        m_inspectorWindow = 0;
183    }
184
185    // Set a default attached size based on InspectorFrontendClientLocal.
186    static const unsigned defaultAttachedSize = 300;
187    if (m_attachmentSide == AttachmentSideBottom) {
188        unsigned maximumAttachedHeight = platformInspectedWindowHeight() * 3 / 4;
189        platformSetAttachedWindowHeight(std::max(minimumAttachedHeight, std::min(defaultAttachedSize, maximumAttachedHeight)));
190    } else {
191        unsigned maximumAttachedWidth = platformInspectedWindowWidth() * 3 / 4;
192        platformSetAttachedWindowWidth(std::max(minimumAttachedWidth, std::min(defaultAttachedSize, maximumAttachedWidth)));
193    }
194
195    if (m_client.attach(this))
196        return;
197
198    webkitWebViewBaseAddWebInspector(WEBKIT_WEB_VIEW_BASE(m_page->viewWidget()), m_inspectorView, m_attachmentSide);
199    gtk_widget_show(m_inspectorView);
200}
201
202void WebInspectorProxy::platformDetach()
203{
204    if (!m_page->isValid())
205        return;
206
207    GRefPtr<GtkWidget> inspectorView = m_inspectorView;
208    if (!m_client.detach(this)) {
209        GtkWidget* parent = gtk_widget_get_parent(m_inspectorView);
210        ASSERT(parent);
211        gtk_container_remove(GTK_CONTAINER(parent), m_inspectorView);
212    }
213
214    if (!m_isVisible)
215        return;
216
217    createInspectorWindow();
218}
219
220void WebInspectorProxy::platformSetAttachedWindowHeight(unsigned height)
221{
222    if (!m_isAttached)
223        return;
224
225    m_client.didChangeAttachedHeight(this, height);
226    webkitWebViewBaseSetInspectorViewSize(WEBKIT_WEB_VIEW_BASE(m_page->viewWidget()), height);
227}
228
229void WebInspectorProxy::platformSetAttachedWindowWidth(unsigned width)
230{
231    if (!m_isAttached)
232        return;
233
234    m_client.didChangeAttachedWidth(this, width);
235    webkitWebViewBaseSetInspectorViewSize(WEBKIT_WEB_VIEW_BASE(m_page->viewWidget()), width);
236}
237
238void WebInspectorProxy::platformSetToolbarHeight(unsigned)
239{
240    notImplemented();
241}
242
243void WebInspectorProxy::platformSave(const String&, const String&, bool, bool)
244{
245    notImplemented();
246}
247
248void WebInspectorProxy::platformAppend(const String&, const String&)
249{
250    notImplemented();
251}
252
253void WebInspectorProxy::platformAttachAvailabilityChanged(bool)
254{
255    notImplemented();
256}
257
258} // namespace WebKit
259
260#endif // ENABLE(INSPECTOR)
261