WebInspectorClient.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. * Copyright (C) 2006, 2007, 2008, 2009, 2010 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. #include "config.h"
  29. #include "WebInspectorClient.h"
  30. #if ENABLE(INSPECTOR)
  31. #include "WebInspectorDelegate.h"
  32. #include "WebKit.h"
  33. #include "WebMutableURLRequest.h"
  34. #include "WebNodeHighlight.h"
  35. #include "WebView.h"
  36. #include <WebCore/BString.h>
  37. #include <WebCore/Element.h>
  38. #include <WebCore/FloatRect.h>
  39. #include <WebCore/FrameView.h>
  40. #include <WebCore/InspectorController.h>
  41. #include <WebCore/NotImplemented.h>
  42. #include <WebCore/Page.h>
  43. #include <WebCore/RenderObject.h>
  44. #include <WebCore/WindowMessageBroadcaster.h>
  45. #include <wchar.h>
  46. #include <wtf/RetainPtr.h>
  47. #include <wtf/text/StringConcatenate.h>
  48. using namespace WebCore;
  49. static LPCTSTR kWebInspectorWindowClassName = TEXT("WebInspectorWindowClass");
  50. static ATOM registerWindowClass();
  51. static LPCTSTR kWebInspectorPointerProp = TEXT("WebInspectorPointer");
  52. static const IntRect& defaultWindowRect()
  53. {
  54. static IntRect rect(60, 200, 750, 650);
  55. return rect;
  56. }
  57. static CFBundleRef getWebKitBundle()
  58. {
  59. return CFBundleGetBundleWithIdentifier(CFSTR("com.apple.WebKit"));
  60. }
  61. WebInspectorClient::WebInspectorClient(WebView* webView)
  62. : m_inspectedWebView(webView)
  63. , m_frontendPage(0)
  64. , m_frontendClient(0)
  65. {
  66. ASSERT(m_inspectedWebView);
  67. m_inspectedWebView->viewWindow((OLE_HANDLE*)&m_inspectedWebViewHwnd);
  68. }
  69. WebInspectorClient::~WebInspectorClient()
  70. {
  71. }
  72. void WebInspectorClient::inspectorDestroyed()
  73. {
  74. closeInspectorFrontend();
  75. delete this;
  76. }
  77. WebCore::InspectorFrontendChannel* WebInspectorClient::openInspectorFrontend(InspectorController* inspectorController)
  78. {
  79. registerWindowClass();
  80. HWND frontendHwnd = ::CreateWindowEx(0, kWebInspectorWindowClassName, 0, WS_OVERLAPPEDWINDOW,
  81. defaultWindowRect().x(), defaultWindowRect().y(), defaultWindowRect().width(), defaultWindowRect().height(),
  82. 0, 0, 0, 0);
  83. if (!frontendHwnd)
  84. return 0;
  85. COMPtr<WebView> frontendWebView(AdoptCOM, WebView::createInstance());
  86. if (FAILED(frontendWebView->setHostWindow((OLE_HANDLE)(ULONG64)frontendHwnd)))
  87. return 0;
  88. RECT rect;
  89. GetClientRect(frontendHwnd, &rect);
  90. if (FAILED(frontendWebView->initWithFrame(rect, 0, 0)))
  91. return 0;
  92. COMPtr<WebInspectorDelegate> delegate(AdoptCOM, WebInspectorDelegate::createInstance());
  93. if (FAILED(frontendWebView->setUIDelegate(delegate.get())))
  94. return 0;
  95. // Keep preferences separate from the rest of the client, making sure we are using expected preference values.
  96. // FIXME: It's crazy that we have to do this song and dance to end up with
  97. // a private WebPreferences object, even within WebKit. We should make this
  98. // process simpler, and consider whether we can make it simpler for WebKit
  99. // clients as well.
  100. COMPtr<WebPreferences> tempPreferences(AdoptCOM, WebPreferences::createInstance());
  101. COMPtr<IWebPreferences> iPreferences;
  102. if (FAILED(tempPreferences->initWithIdentifier(BString(L"WebInspectorPreferences"), &iPreferences)))
  103. return 0;
  104. COMPtr<WebPreferences> preferences(Query, iPreferences);
  105. if (!preferences)
  106. return 0;
  107. if (FAILED(preferences->setAutosaves(FALSE)))
  108. return 0;
  109. if (FAILED(preferences->setLoadsImagesAutomatically(TRUE)))
  110. return 0;
  111. if (FAILED(preferences->setAuthorAndUserStylesEnabled(TRUE)))
  112. return 0;
  113. if (FAILED(preferences->setAllowsAnimatedImages(TRUE)))
  114. return 0;
  115. if (FAILED(preferences->setLoadsImagesAutomatically(TRUE)))
  116. return 0;
  117. if (FAILED(preferences->setPlugInsEnabled(FALSE)))
  118. return 0;
  119. if (FAILED(preferences->setJavaEnabled(FALSE)))
  120. return 0;
  121. if (FAILED(preferences->setUserStyleSheetEnabled(FALSE)))
  122. return 0;
  123. if (FAILED(preferences->setTabsToLinks(FALSE)))
  124. return 0;
  125. if (FAILED(preferences->setMinimumFontSize(0)))
  126. return 0;
  127. if (FAILED(preferences->setMinimumLogicalFontSize(9)))
  128. return 0;
  129. if (FAILED(preferences->setFixedFontFamily(BString(L"Courier New"))))
  130. return 0;
  131. if (FAILED(preferences->setDefaultFixedFontSize(13)))
  132. return 0;
  133. if (FAILED(frontendWebView->setPreferences(preferences.get())))
  134. return 0;
  135. frontendWebView->setProhibitsMainFrameScrolling(TRUE);
  136. HWND frontendWebViewHwnd;
  137. if (FAILED(frontendWebView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&frontendWebViewHwnd))))
  138. return 0;
  139. COMPtr<WebMutableURLRequest> request(AdoptCOM, WebMutableURLRequest::createInstance());
  140. RetainPtr<CFURLRef> htmlURLRef = adoptCF(CFBundleCopyResourceURL(getWebKitBundle(), CFSTR("inspector"), CFSTR("html"), CFSTR("inspector")));
  141. if (!htmlURLRef)
  142. return 0;
  143. CFStringRef urlStringRef = ::CFURLGetString(htmlURLRef.get());
  144. if (FAILED(request->initWithURL(BString(urlStringRef), WebURLRequestUseProtocolCachePolicy, 60)))
  145. return 0;
  146. if (FAILED(frontendWebView->topLevelFrame()->loadRequest(request.get())))
  147. return 0;
  148. m_frontendPage = core(frontendWebView.get());
  149. OwnPtr<WebInspectorFrontendClient> frontendClient = adoptPtr(new WebInspectorFrontendClient(m_inspectedWebView, m_inspectedWebViewHwnd, frontendHwnd, frontendWebView, frontendWebViewHwnd, this, createFrontendSettings()));
  150. m_frontendClient = frontendClient.get();
  151. m_frontendPage->inspectorController()->setInspectorFrontendClient(frontendClient.release());
  152. m_frontendHwnd = frontendHwnd;
  153. return this;
  154. }
  155. void WebInspectorClient::closeInspectorFrontend()
  156. {
  157. if (m_frontendClient)
  158. m_frontendClient->destroyInspectorView(false);
  159. }
  160. void WebInspectorClient::bringFrontendToFront()
  161. {
  162. m_frontendClient->bringToFront();
  163. }
  164. void WebInspectorClient::highlight()
  165. {
  166. bool creatingHighlight = !m_highlight;
  167. if (creatingHighlight)
  168. m_highlight = adoptPtr(new WebNodeHighlight(m_inspectedWebView));
  169. if (m_highlight->isShowing())
  170. m_highlight->update();
  171. else
  172. m_highlight->setShowsWhileWebViewIsVisible(true);
  173. if (creatingHighlight && IsWindowVisible(m_frontendHwnd))
  174. m_highlight->placeBehindWindow(m_frontendHwnd);
  175. }
  176. void WebInspectorClient::hideHighlight()
  177. {
  178. if (m_highlight)
  179. m_highlight->setShowsWhileWebViewIsVisible(false);
  180. }
  181. void WebInspectorClient::updateHighlight()
  182. {
  183. if (m_highlight && m_highlight->isShowing())
  184. m_highlight->update();
  185. }
  186. void WebInspectorClient::releaseFrontend()
  187. {
  188. m_frontendClient = 0;
  189. m_frontendPage = 0;
  190. m_frontendHwnd = 0;
  191. }
  192. WebInspectorFrontendClient::WebInspectorFrontendClient(WebView* inspectedWebView, HWND inspectedWebViewHwnd, HWND frontendHwnd, const COMPtr<WebView>& frontendWebView, HWND frontendWebViewHwnd, WebInspectorClient* inspectorClient, PassOwnPtr<Settings> settings)
  193. : InspectorFrontendClientLocal(inspectedWebView->page()->inspectorController(), core(frontendWebView.get()), settings)
  194. , m_inspectedWebView(inspectedWebView)
  195. , m_inspectedWebViewHwnd(inspectedWebViewHwnd)
  196. , m_inspectorClient(inspectorClient)
  197. , m_frontendHwnd(frontendHwnd)
  198. , m_frontendWebView(frontendWebView)
  199. , m_frontendWebViewHwnd(frontendWebViewHwnd)
  200. , m_attached(false)
  201. , m_destroyingInspectorView(false)
  202. {
  203. ::SetProp(frontendHwnd, kWebInspectorPointerProp, reinterpret_cast<HANDLE>(this));
  204. // FIXME: Implement window size/position save/restore
  205. #if 0
  206. [self setWindowFrameAutosaveName:@"Web Inspector"];
  207. #endif
  208. }
  209. WebInspectorFrontendClient::~WebInspectorFrontendClient()
  210. {
  211. destroyInspectorView(true);
  212. }
  213. void WebInspectorFrontendClient::frontendLoaded()
  214. {
  215. InspectorFrontendClientLocal::frontendLoaded();
  216. if (m_attached)
  217. restoreAttachedWindowHeight();
  218. setAttachedWindow(m_attached ? DOCKED_TO_BOTTOM : UNDOCKED);
  219. }
  220. String WebInspectorFrontendClient::localizedStringsURL()
  221. {
  222. RetainPtr<CFURLRef> url = adoptCF(CFBundleCopyResourceURL(getWebKitBundle(), CFSTR("localizedStrings"), CFSTR("js"), 0));
  223. if (!url)
  224. return String();
  225. return CFURLGetString(url.get());
  226. }
  227. void WebInspectorFrontendClient::bringToFront()
  228. {
  229. showWindowWithoutNotifications();
  230. }
  231. void WebInspectorFrontendClient::closeWindow()
  232. {
  233. destroyInspectorView(true);
  234. }
  235. void WebInspectorFrontendClient::attachWindow(DockSide)
  236. {
  237. if (m_attached)
  238. return;
  239. m_inspectorClient->setInspectorStartsAttached(true);
  240. closeWindowWithoutNotifications();
  241. // We need to set the attached window's height before we actually attach the window.
  242. // Make sure that m_attached is true so that calling setAttachedWindowHeight from restoreAttachedWindowHeight doesn't return early.
  243. m_attached = true;
  244. // Immediately after calling showWindowWithoutNotifications(), the parent frameview's visibleHeight incorrectly returns 0 always (Windows only).
  245. // We are expecting this value to be just the height of the parent window when we call restoreAttachedWindowHeight, which it is before
  246. // calling showWindowWithoutNotifications().
  247. restoreAttachedWindowHeight();
  248. showWindowWithoutNotifications();
  249. }
  250. void WebInspectorFrontendClient::detachWindow()
  251. {
  252. if (!m_attached)
  253. return;
  254. m_inspectorClient->setInspectorStartsAttached(false);
  255. closeWindowWithoutNotifications();
  256. showWindowWithoutNotifications();
  257. }
  258. void WebInspectorFrontendClient::setAttachedWindowHeight(unsigned height)
  259. {
  260. if (!m_attached)
  261. return;
  262. HWND hostWindow;
  263. if (!SUCCEEDED(m_inspectedWebView->hostWindow((OLE_HANDLE*)&hostWindow)))
  264. return;
  265. RECT hostWindowRect;
  266. GetClientRect(hostWindow, &hostWindowRect);
  267. RECT inspectedRect;
  268. GetClientRect(m_inspectedWebViewHwnd, &inspectedRect);
  269. int totalHeight = hostWindowRect.bottom - hostWindowRect.top;
  270. int webViewWidth = inspectedRect.right - inspectedRect.left;
  271. SetWindowPos(m_frontendWebViewHwnd, 0, 0, totalHeight - height, webViewWidth, height, SWP_NOZORDER);
  272. // We want to set the inspected web view height to the totalHeight, because the height adjustment
  273. // of the inspected web view happens in onWebViewWindowPosChanging, not here.
  274. SetWindowPos(m_inspectedWebViewHwnd, 0, 0, 0, webViewWidth, totalHeight, SWP_NOZORDER);
  275. RedrawWindow(m_frontendWebViewHwnd, 0, 0, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);
  276. RedrawWindow(m_inspectedWebViewHwnd, 0, 0, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);
  277. }
  278. void WebInspectorFrontendClient::setAttachedWindowWidth(unsigned)
  279. {
  280. notImplemented();
  281. }
  282. void WebInspectorFrontendClient::setToolbarHeight(unsigned)
  283. {
  284. notImplemented();
  285. }
  286. void WebInspectorFrontendClient::inspectedURLChanged(const String& newURL)
  287. {
  288. m_inspectedURL = newURL;
  289. updateWindowTitle();
  290. }
  291. void WebInspectorFrontendClient::closeWindowWithoutNotifications()
  292. {
  293. if (!m_frontendHwnd)
  294. return;
  295. if (!m_attached) {
  296. ShowWindow(m_frontendHwnd, SW_HIDE);
  297. return;
  298. }
  299. ASSERT(m_frontendWebView);
  300. ASSERT(m_inspectedWebViewHwnd);
  301. ASSERT(!IsWindowVisible(m_frontendHwnd));
  302. // Remove the Inspector's WebView from the inspected WebView's parent window.
  303. WindowMessageBroadcaster::removeListener(m_inspectedWebViewHwnd, this);
  304. m_attached = false;
  305. m_frontendWebView->setHostWindow(reinterpret_cast<OLE_HANDLE>(m_frontendHwnd));
  306. // Make sure everything has the right size/position.
  307. HWND hostWindow;
  308. if (SUCCEEDED(m_inspectedWebView->hostWindow((OLE_HANDLE*)&hostWindow)))
  309. SendMessage(hostWindow, WM_SIZE, 0, 0);
  310. }
  311. void WebInspectorFrontendClient::showWindowWithoutNotifications()
  312. {
  313. if (!m_frontendHwnd)
  314. return;
  315. ASSERT(m_frontendWebView);
  316. ASSERT(m_inspectedWebViewHwnd);
  317. bool shouldAttach = false;
  318. if (m_attached)
  319. shouldAttach = true;
  320. else {
  321. // If no preference is set - default to an attached window. This is important for inspector LayoutTests.
  322. // FIXME: This flag can be fetched directly from the flags storage.
  323. shouldAttach = m_inspectorClient->inspectorStartsAttached();
  324. if (shouldAttach && !canAttachWindow())
  325. shouldAttach = false;
  326. }
  327. if (!shouldAttach) {
  328. // Put the Inspector's WebView inside our window and show it.
  329. m_frontendWebView->setHostWindow(reinterpret_cast<OLE_HANDLE>(m_frontendHwnd));
  330. SendMessage(m_frontendHwnd, WM_SIZE, 0, 0);
  331. updateWindowTitle();
  332. SetWindowPos(m_frontendHwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
  333. return;
  334. }
  335. // Put the Inspector's WebView inside the inspected WebView's parent window.
  336. WindowMessageBroadcaster::addListener(m_inspectedWebViewHwnd, this);
  337. HWND hostWindow;
  338. if (FAILED(m_inspectedWebView->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow))))
  339. return;
  340. m_frontendWebView->setHostWindow(reinterpret_cast<OLE_HANDLE>(hostWindow));
  341. // Then hide our own window.
  342. ShowWindow(m_frontendHwnd, SW_HIDE);
  343. m_attached = true;
  344. // Make sure everything has the right size/position.
  345. SendMessage(hostWindow, WM_SIZE, 0, 0);
  346. m_inspectorClient->updateHighlight();
  347. }
  348. void WebInspectorFrontendClient::destroyInspectorView(bool notifyInspectorController)
  349. {
  350. m_inspectorClient->releaseFrontend();
  351. if (m_destroyingInspectorView)
  352. return;
  353. m_destroyingInspectorView = true;
  354. closeWindowWithoutNotifications();
  355. if (notifyInspectorController) {
  356. m_inspectedWebView->page()->inspectorController()->disconnectFrontend();
  357. m_inspectorClient->updateHighlight();
  358. }
  359. ::DestroyWindow(m_frontendHwnd);
  360. }
  361. void WebInspectorFrontendClient::updateWindowTitle()
  362. {
  363. String title = makeString("Web Inspector ", static_cast<UChar>(0x2014), ' ', m_inspectedURL);
  364. ::SetWindowText(m_frontendHwnd, title.charactersWithNullTermination());
  365. }
  366. LRESULT WebInspectorFrontendClient::onGetMinMaxInfo(WPARAM, LPARAM lParam)
  367. {
  368. MINMAXINFO* info = reinterpret_cast<MINMAXINFO*>(lParam);
  369. POINT size = {400, 400};
  370. info->ptMinTrackSize = size;
  371. return 0;
  372. }
  373. LRESULT WebInspectorFrontendClient::onSize(WPARAM, LPARAM)
  374. {
  375. RECT rect;
  376. ::GetClientRect(m_frontendHwnd, &rect);
  377. ::SetWindowPos(m_frontendWebViewHwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
  378. return 0;
  379. }
  380. LRESULT WebInspectorFrontendClient::onClose(WPARAM, LPARAM)
  381. {
  382. ::ShowWindow(m_frontendHwnd, SW_HIDE);
  383. m_inspectedWebView->page()->inspectorController()->close();
  384. return 0;
  385. }
  386. LRESULT WebInspectorFrontendClient::onSetFocus()
  387. {
  388. SetFocus(m_frontendWebViewHwnd);
  389. return 0;
  390. }
  391. void WebInspectorFrontendClient::onWebViewWindowPosChanging(WPARAM, LPARAM lParam)
  392. {
  393. ASSERT(m_attached);
  394. WINDOWPOS* windowPos = reinterpret_cast<WINDOWPOS*>(lParam);
  395. ASSERT_ARG(lParam, windowPos);
  396. if (windowPos->flags & SWP_NOSIZE)
  397. return;
  398. RECT inspectorRect;
  399. GetClientRect(m_frontendWebViewHwnd, &inspectorRect);
  400. unsigned inspectorHeight = inspectorRect.bottom - inspectorRect.top;
  401. windowPos->cy -= inspectorHeight;
  402. SetWindowPos(m_frontendWebViewHwnd, 0, windowPos->x, windowPos->y + windowPos->cy, windowPos->cx, inspectorHeight, SWP_NOZORDER);
  403. }
  404. static LRESULT CALLBACK WebInspectorWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  405. {
  406. WebInspectorFrontendClient* client = reinterpret_cast<WebInspectorFrontendClient*>(::GetProp(hwnd, kWebInspectorPointerProp));
  407. if (!client)
  408. return ::DefWindowProc(hwnd, msg, wParam, lParam);
  409. switch (msg) {
  410. case WM_GETMINMAXINFO:
  411. return client->onGetMinMaxInfo(wParam, lParam);
  412. case WM_SIZE:
  413. return client->onSize(wParam, lParam);
  414. case WM_CLOSE:
  415. return client->onClose(wParam, lParam);
  416. case WM_SETFOCUS:
  417. return client->onSetFocus();
  418. default:
  419. break;
  420. }
  421. return ::DefWindowProc(hwnd, msg, wParam, lParam);
  422. }
  423. void WebInspectorFrontendClient::windowReceivedMessage(HWND, UINT msg, WPARAM wParam, LPARAM lParam)
  424. {
  425. switch (msg) {
  426. case WM_WINDOWPOSCHANGING:
  427. onWebViewWindowPosChanging(wParam, lParam);
  428. break;
  429. default:
  430. break;
  431. }
  432. }
  433. static ATOM registerWindowClass()
  434. {
  435. static bool haveRegisteredWindowClass = false;
  436. if (haveRegisteredWindowClass)
  437. return true;
  438. WNDCLASSEX wcex;
  439. wcex.cbSize = sizeof(WNDCLASSEX);
  440. wcex.style = 0;
  441. wcex.lpfnWndProc = WebInspectorWndProc;
  442. wcex.cbClsExtra = 0;
  443. wcex.cbWndExtra = 0;
  444. wcex.hInstance = 0;
  445. wcex.hIcon = 0;
  446. wcex.hCursor = LoadCursor(0, IDC_ARROW);
  447. wcex.hbrBackground = 0;
  448. wcex.lpszMenuName = 0;
  449. wcex.lpszClassName = kWebInspectorWindowClassName;
  450. wcex.hIconSm = 0;
  451. haveRegisteredWindowClass = true;
  452. return ::RegisterClassEx(&wcex);
  453. }
  454. #endif // ENABLE(INSPECTOR)