• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 #include "WebInspectorClient.h"
31 
32 #include "WebInspectorDelegate.h"
33 #include "WebKit.h"
34 #include "WebMutableURLRequest.h"
35 #include "WebNodeHighlight.h"
36 #include "WebView.h"
37 
38 #pragma warning(push, 0)
39 #include <WebCore/BString.h>
40 #include <WebCore/Element.h>
41 #include <WebCore/FloatRect.h>
42 #include <WebCore/FrameView.h>
43 #include <WebCore/InspectorController.h>
44 #include <WebCore/Page.h>
45 #include <WebCore/RenderObject.h>
46 #include <WebCore/WindowMessageBroadcaster.h>
47 #pragma warning(pop)
48 
49 #include <tchar.h>
50 #include <wtf/RetainPtr.h>
51 
52 using namespace WebCore;
53 
54 static LPCTSTR kWebInspectorWindowClassName = TEXT("WebInspectorWindowClass");
55 static ATOM registerWindowClass();
56 static LPCTSTR kWebInspectorPointerProp = TEXT("WebInspectorPointer");
57 
58 static const unsigned defaultAttachedHeight = 300;
59 
defaultWindowRect()60 static const IntRect& defaultWindowRect()
61 {
62     static IntRect rect(60, 200, 750, 650);
63     return rect;
64 }
65 
getWebKitBundle()66 static CFBundleRef getWebKitBundle()
67 {
68     return CFBundleGetBundleWithIdentifier(CFSTR("com.apple.WebKit"));
69 }
70 
WebInspectorClient(WebView * webView)71 WebInspectorClient::WebInspectorClient(WebView* webView)
72     : m_inspectedWebView(webView)
73     , m_hwnd(0)
74     , m_webViewHwnd(0)
75     , m_shouldAttachWhenShown(false)
76     , m_attached(false)
77 {
78     ASSERT(m_inspectedWebView);
79 
80     m_inspectedWebView->viewWindow((OLE_HANDLE*)&m_inspectedWebViewHwnd);
81 
82     // FIXME: Implement window size/position save/restore
83 #if 0
84     [self setWindowFrameAutosaveName:@"Web Inspector"];
85 #endif
86 }
87 
~WebInspectorClient()88 WebInspectorClient::~WebInspectorClient()
89 {
90     if (m_hwnd)
91         ::DestroyWindow(m_hwnd);
92 }
93 
inspectorDestroyed()94 void WebInspectorClient::inspectorDestroyed()
95 {
96     delete this;
97 }
98 
createPage()99 Page* WebInspectorClient::createPage()
100 {
101     if (m_webView)
102         return core(m_webView.get());
103 
104     ASSERT(!m_hwnd);
105 
106     registerWindowClass();
107 
108     m_hwnd = ::CreateWindowEx(0, kWebInspectorWindowClassName, 0, WS_OVERLAPPEDWINDOW,
109         defaultWindowRect().x(), defaultWindowRect().y(), defaultWindowRect().width(), defaultWindowRect().height(),
110         0, 0, 0, 0);
111 
112     if (!m_hwnd)
113         return 0;
114 
115     ::SetProp(m_hwnd, kWebInspectorPointerProp, reinterpret_cast<HANDLE>(this));
116 
117     m_webView.adoptRef(WebView::createInstance());
118 
119     if (FAILED(m_webView->setHostWindow((OLE_HANDLE)(ULONG64)m_hwnd)))
120         return 0;
121 
122     RECT rect;
123     GetClientRect(m_hwnd, &rect);
124     if (FAILED(m_webView->initWithFrame(rect, 0, 0)))
125         return 0;
126 
127     COMPtr<WebInspectorDelegate> delegate(AdoptCOM, WebInspectorDelegate::createInstance());
128     if (FAILED(m_webView->setUIDelegate(delegate.get())))
129         return 0;
130 
131     // Keep preferences separate from the rest of the client, making sure we are using expected preference values.
132     // One reason this is good is that it keeps the inspector out of history via "private browsing".
133     // FIXME: It's crazy that we have to do this song and dance to end up with
134     // a private WebPreferences object, even within WebKit. We should make this
135     // process simpler, and consider whether we can make it simpler for WebKit
136     // clients as well.
137     COMPtr<WebPreferences> tempPreferences(AdoptCOM, WebPreferences::createInstance());
138     COMPtr<IWebPreferences> iPreferences;
139     if (FAILED(tempPreferences->initWithIdentifier(BString(L"WebInspectorPreferences"), &iPreferences)))
140         return 0;
141     COMPtr<WebPreferences> preferences(Query, iPreferences);
142     if (!preferences)
143         return 0;
144     if (FAILED(preferences->setAutosaves(FALSE)))
145         return 0;
146     if (FAILED(preferences->setPrivateBrowsingEnabled(TRUE)))
147         return 0;
148     if (FAILED(preferences->setLoadsImagesAutomatically(TRUE)))
149         return 0;
150     if (FAILED(preferences->setAuthorAndUserStylesEnabled(TRUE)))
151         return 0;
152     if (FAILED(preferences->setAllowsAnimatedImages(TRUE)))
153         return 0;
154     if (FAILED(preferences->setLoadsImagesAutomatically(TRUE)))
155         return 0;
156     if (FAILED(preferences->setPlugInsEnabled(FALSE)))
157         return 0;
158     if (FAILED(preferences->setJavaEnabled(FALSE)))
159         return 0;
160     if (FAILED(preferences->setUserStyleSheetEnabled(FALSE)))
161         return 0;
162     if (FAILED(preferences->setTabsToLinks(FALSE)))
163         return 0;
164     if (FAILED(preferences->setMinimumFontSize(0)))
165         return 0;
166     if (FAILED(preferences->setMinimumLogicalFontSize(9)))
167         return 0;
168 
169     if (FAILED(m_webView->setPreferences(preferences.get())))
170         return 0;
171 
172     m_webView->setProhibitsMainFrameScrolling(TRUE);
173 
174     if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&m_webViewHwnd))))
175         return 0;
176 
177     COMPtr<WebMutableURLRequest> request;
178     request.adoptRef(WebMutableURLRequest::createInstance());
179 
180     RetainPtr<CFURLRef> htmlURLRef(AdoptCF, CFBundleCopyResourceURL(getWebKitBundle(), CFSTR("inspector"), CFSTR("html"), CFSTR("inspector")));
181     if (!htmlURLRef)
182         return 0;
183 
184     CFStringRef urlStringRef = ::CFURLGetString(htmlURLRef.get());
185     if (FAILED(request->initWithURL(BString(urlStringRef), WebURLRequestUseProtocolCachePolicy, 60)))
186         return 0;
187 
188     if (FAILED(m_webView->topLevelFrame()->loadRequest(request.get())))
189         return 0;
190 
191     return core(m_webView.get());
192 }
193 
194 
localizedStringsURL()195 String WebInspectorClient::localizedStringsURL()
196 {
197     RetainPtr<CFURLRef> url(AdoptCF, CFBundleCopyResourceURL(getWebKitBundle(), CFSTR("localizedStrings"), CFSTR("js"), 0));
198     if (!url)
199         return String();
200 
201     return CFURLGetString(url.get());
202 }
203 
showWindow()204 void WebInspectorClient::showWindow()
205 {
206     showWindowWithoutNotifications();
207     m_inspectedWebView->page()->inspectorController()->setWindowVisible(true);
208 }
209 
closeWindow()210 void WebInspectorClient::closeWindow()
211 {
212     closeWindowWithoutNotifications();
213     m_inspectedWebView->page()->inspectorController()->setWindowVisible(false);
214 }
215 
windowVisible()216 bool WebInspectorClient::windowVisible()
217 {
218     return !!::IsWindowVisible(m_hwnd);
219 }
220 
attachWindow()221 void WebInspectorClient::attachWindow()
222 {
223     if (m_attached)
224         return;
225 
226     m_shouldAttachWhenShown = true;
227 
228     closeWindowWithoutNotifications();
229     showWindowWithoutNotifications();
230 }
231 
detachWindow()232 void WebInspectorClient::detachWindow()
233 {
234     if (!m_attached)
235         return;
236 
237     m_shouldAttachWhenShown = false;
238 
239     closeWindowWithoutNotifications();
240     showWindowWithoutNotifications();
241 }
242 
setAttachedWindowHeight(unsigned height)243 void WebInspectorClient::setAttachedWindowHeight(unsigned height)
244 {
245     // FIXME: implement this.
246 }
247 
highlight(Node *)248 void WebInspectorClient::highlight(Node*)
249 {
250     bool creatingHighlight = !m_highlight;
251 
252     if (creatingHighlight)
253         m_highlight.set(new WebNodeHighlight(m_inspectedWebView));
254 
255     if (m_highlight->isShowing())
256         m_highlight->update();
257     else
258         m_highlight->setShowsWhileWebViewIsVisible(true);
259 
260     if (creatingHighlight && IsWindowVisible(m_hwnd))
261         m_highlight->placeBehindWindow(m_hwnd);
262 }
263 
hideHighlight()264 void WebInspectorClient::hideHighlight()
265 {
266     if (m_highlight)
267         m_highlight->setShowsWhileWebViewIsVisible(false);
268 }
269 
inspectedURLChanged(const String & newURL)270 void WebInspectorClient::inspectedURLChanged(const String& newURL)
271 {
272     m_inspectedURL = newURL;
273     updateWindowTitle();
274 }
275 
closeWindowWithoutNotifications()276 void WebInspectorClient::closeWindowWithoutNotifications()
277 {
278     if (!m_hwnd)
279         return;
280 
281     if (!m_attached) {
282         ShowWindow(m_hwnd, SW_HIDE);
283         return;
284     }
285 
286     ASSERT(m_webView);
287     ASSERT(m_inspectedWebViewHwnd);
288     ASSERT(!IsWindowVisible(m_hwnd));
289 
290     // Remove the Inspector's WebView from the inspected WebView's parent window.
291     WindowMessageBroadcaster::removeListener(m_inspectedWebViewHwnd, this);
292 
293     m_attached = false;
294 
295     m_webView->setHostWindow(reinterpret_cast<OLE_HANDLE>(m_hwnd));
296 
297     // Make sure everything has the right size/position.
298     HWND hostWindow;
299     if (SUCCEEDED(m_inspectedWebView->hostWindow((OLE_HANDLE*)&hostWindow)))
300         SendMessage(hostWindow, WM_SIZE, 0, 0);
301 
302     if (m_highlight && m_highlight->isShowing())
303         m_highlight->update();
304 }
305 
showWindowWithoutNotifications()306 void WebInspectorClient::showWindowWithoutNotifications()
307 {
308     if (!m_hwnd)
309         return;
310 
311     ASSERT(m_webView);
312     ASSERT(m_inspectedWebViewHwnd);
313 
314     if (!m_shouldAttachWhenShown) {
315         // Put the Inspector's WebView inside our window and show it.
316         m_webView->setHostWindow(reinterpret_cast<OLE_HANDLE>(m_hwnd));
317         SendMessage(m_hwnd, WM_SIZE, 0, 0);
318         updateWindowTitle();
319 
320         SetWindowPos(m_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
321         return;
322     }
323 
324     // Put the Inspector's WebView inside the inspected WebView's parent window.
325     WindowMessageBroadcaster::addListener(m_inspectedWebViewHwnd, this);
326 
327     HWND hostWindow;
328     if (FAILED(m_inspectedWebView->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow))))
329         return;
330 
331     m_webView->setHostWindow(reinterpret_cast<OLE_HANDLE>(hostWindow));
332 
333     // Then hide our own window.
334     ShowWindow(m_hwnd, SW_HIDE);
335 
336     m_attached = true;
337 
338     // Make sure everything has the right size/position.
339     SendMessage(hostWindow, WM_SIZE, 0, 0);
340     if (m_highlight && m_highlight->isShowing())
341         m_highlight->update();
342 }
343 
updateWindowTitle()344 void WebInspectorClient::updateWindowTitle()
345 {
346     // FIXME: The series of appends should be replaced with a call to String::format()
347     // when it can be figured out how to get the unicode em-dash to show up.
348     String title = "Web Inspector ";
349     title.append((UChar)0x2014); // em-dash
350     title.append(' ');
351     title.append(m_inspectedURL);
352     ::SetWindowText(m_hwnd, title.charactersWithNullTermination());
353 }
354 
onGetMinMaxInfo(WPARAM,LPARAM lParam)355 LRESULT WebInspectorClient::onGetMinMaxInfo(WPARAM, LPARAM lParam)
356 {
357     MINMAXINFO* info = reinterpret_cast<MINMAXINFO*>(lParam);
358     POINT size = {400, 400};
359     info->ptMinTrackSize = size;
360 
361     return 0;
362 }
363 
onSize(WPARAM,LPARAM)364 LRESULT WebInspectorClient::onSize(WPARAM, LPARAM)
365 {
366     RECT rect;
367     ::GetClientRect(m_hwnd, &rect);
368 
369     ::SetWindowPos(m_webViewHwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
370 
371     return 0;
372 }
373 
onClose(WPARAM,LPARAM)374 LRESULT WebInspectorClient::onClose(WPARAM, LPARAM)
375 {
376     ::ShowWindow(m_hwnd, SW_HIDE);
377     m_inspectedWebView->page()->inspectorController()->setWindowVisible(false);
378 
379     hideHighlight();
380 
381     return 0;
382 }
383 
onSetFocus()384 LRESULT WebInspectorClient::onSetFocus()
385 {
386     SetFocus(m_webViewHwnd);
387     return 0;
388 }
389 
onWebViewWindowPosChanging(WPARAM,LPARAM lParam)390 void WebInspectorClient::onWebViewWindowPosChanging(WPARAM, LPARAM lParam)
391 {
392     ASSERT(m_attached);
393 
394     WINDOWPOS* windowPos = reinterpret_cast<WINDOWPOS*>(lParam);
395     ASSERT_ARG(lParam, windowPos);
396 
397     if (windowPos->flags & SWP_NOSIZE)
398         return;
399 
400     windowPos->cy -= defaultAttachedHeight;
401 
402     ::SetWindowPos(m_webViewHwnd, 0, windowPos->x, windowPos->y + windowPos->cy, windowPos->cx, defaultAttachedHeight, SWP_NOZORDER);
403 }
404 
WebInspectorWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)405 static LRESULT CALLBACK WebInspectorWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
406 {
407     WebInspectorClient* client = reinterpret_cast<WebInspectorClient*>(::GetProp(hwnd, kWebInspectorPointerProp));
408     if (!client)
409         return ::DefWindowProc(hwnd, msg, wParam, lParam);
410 
411     switch (msg) {
412         case WM_GETMINMAXINFO:
413             return client->onGetMinMaxInfo(wParam, lParam);
414         case WM_SIZE:
415             return client->onSize(wParam, lParam);
416         case WM_CLOSE:
417             return client->onClose(wParam, lParam);
418         case WM_SETFOCUS:
419             return client->onSetFocus();
420         default:
421             break;
422     }
423 
424     return ::DefWindowProc(hwnd, msg, wParam, lParam);
425 }
426 
windowReceivedMessage(HWND,UINT msg,WPARAM wParam,LPARAM lParam)427 void WebInspectorClient::windowReceivedMessage(HWND, UINT msg, WPARAM wParam, LPARAM lParam)
428 {
429     switch (msg) {
430         case WM_WINDOWPOSCHANGING:
431             onWebViewWindowPosChanging(wParam, lParam);
432             break;
433         default:
434             break;
435     }
436 }
437 
registerWindowClass()438 static ATOM registerWindowClass()
439 {
440     static bool haveRegisteredWindowClass = false;
441 
442     if (haveRegisteredWindowClass)
443         return true;
444 
445     WNDCLASSEX wcex;
446 
447     wcex.cbSize = sizeof(WNDCLASSEX);
448 
449     wcex.style          = 0;
450     wcex.lpfnWndProc    = WebInspectorWndProc;
451     wcex.cbClsExtra     = 0;
452     wcex.cbWndExtra     = 0;
453     wcex.hInstance      = 0;
454     wcex.hIcon          = 0;
455     wcex.hCursor        = LoadCursor(0, IDC_ARROW);
456     wcex.hbrBackground  = 0;
457     wcex.lpszMenuName   = 0;
458     wcex.lpszClassName  = kWebInspectorWindowClassName;
459     wcex.hIconSm        = 0;
460 
461     haveRegisteredWindowClass = true;
462 
463     return ::RegisterClassEx(&wcex);
464 }
465