[WinCairo] Add support to WebView for setting tooltips
[WebKit-https.git] / Source / WebKit / UIProcess / win / WebView.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2017 Sony Interactive Entertainment Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "WebView.h"
29
30 #include "APIPageConfiguration.h"
31 #include "DrawingAreaProxyImpl.h"
32 #include "Logging.h"
33 #include "NativeWebKeyboardEvent.h"
34 #include "NativeWebMouseEvent.h"
35 #include "NativeWebWheelEvent.h"
36 #include "WKAPICast.h"
37 #include "WebContextMenuProxyWin.h"
38 #include "WebEditCommandProxy.h"
39 #include "WebEventFactory.h"
40 #include "WebPageGroup.h"
41 #include "WebPageProxy.h"
42 #include "WebProcessPool.h"
43 #include <Commctrl.h>
44 #include <WebCore/BitmapInfo.h>
45 #include <WebCore/Cursor.h>
46 #include <WebCore/Editor.h>
47 #include <WebCore/FileSystem.h>
48 #include <WebCore/FloatRect.h>
49 #include <WebCore/HWndDC.h>
50 #include <WebCore/IntRect.h>
51 #include <WebCore/NotImplemented.h>
52 #include <WebCore/Region.h>
53 #include <WebCore/WebCoreInstanceHandle.h>
54 #include <WebCore/WindowMessageBroadcaster.h>
55 #include <WebCore/WindowsTouch.h>
56 #include <cairo-win32.h>
57 #include <cairo.h>
58 #include <wtf/SoftLinking.h>
59 #include <wtf/text/StringBuffer.h>
60 #include <wtf/text/StringBuilder.h>
61 #include <wtf/text/WTFString.h>
62
63 using namespace WebCore;
64
65 namespace WebKit {
66
67 static const LPCWSTR kWebKit2WebViewWindowClassName = L"WebKit2WebViewWindowClass";
68
69 static const int kMaxToolTipWidth = 250;
70
71 enum {
72     UpdateActiveStateTimer = 1,
73 };
74
75 LRESULT CALLBACK WebView::WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
76 {
77     LONG_PTR longPtr = ::GetWindowLongPtr(hWnd, 0);
78
79     if (WebView* webView = reinterpret_cast<WebView*>(longPtr))
80         return webView->wndProc(hWnd, message, wParam, lParam);
81
82     if (message == WM_CREATE) {
83         LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
84
85         // Associate the WebView with the window.
86         ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams);
87         return 0;
88     }
89
90     return ::DefWindowProc(hWnd, message, wParam, lParam);
91 }
92
93 LRESULT WebView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
94 {
95     LRESULT lResult = 0;
96     bool handled = true;
97
98     switch (message) {
99     case WM_CLOSE:
100         m_page->tryClose();
101         break;
102     case WM_DESTROY:
103         m_isBeingDestroyed = true;
104         close();
105         break;
106     case WM_ERASEBKGND:
107         lResult = 1;
108         break;
109     case WM_PAINT:
110         lResult = onPaintEvent(hWnd, message, wParam, lParam, handled);
111         break;
112     case WM_PRINTCLIENT:
113         lResult = onPrintClientEvent(hWnd, message, wParam, lParam, handled);
114         break;
115     case WM_MOUSEACTIVATE:
116         setWasActivatedByMouseEvent(true);
117         handled = false;
118         break;
119     case WM_MOUSEMOVE:
120     case WM_LBUTTONDOWN:
121     case WM_MBUTTONDOWN:
122     case WM_RBUTTONDOWN:
123     case WM_LBUTTONDBLCLK:
124     case WM_MBUTTONDBLCLK:
125     case WM_RBUTTONDBLCLK:
126     case WM_LBUTTONUP:
127     case WM_MBUTTONUP:
128     case WM_RBUTTONUP:
129     case WM_MOUSELEAVE:
130         lResult = onMouseEvent(hWnd, message, wParam, lParam, handled);
131         break;
132     case WM_MOUSEWHEEL:
133         lResult = onWheelEvent(hWnd, message, wParam, lParam, handled);
134         break;
135     case WM_HSCROLL:
136         lResult = onHorizontalScroll(hWnd, message, wParam, lParam, handled);
137         break;
138     case WM_VSCROLL:
139         lResult = onVerticalScroll(hWnd, message, wParam, lParam, handled);
140         break;
141     case WM_SYSKEYDOWN:
142     case WM_KEYDOWN:
143     case WM_SYSCHAR:
144     case WM_CHAR:
145     case WM_SYSKEYUP:
146     case WM_KEYUP:
147         lResult = onKeyEvent(hWnd, message, wParam, lParam, handled);
148         break;
149     case WM_SIZE:
150         lResult = onSizeEvent(hWnd, message, wParam, lParam, handled);
151         break;
152     case WM_WINDOWPOSCHANGED:
153         lResult = onWindowPositionChangedEvent(hWnd, message, wParam, lParam, handled);
154         break;
155     case WM_SETFOCUS:
156         lResult = onSetFocusEvent(hWnd, message, wParam, lParam, handled);
157         break;
158     case WM_KILLFOCUS:
159         lResult = onKillFocusEvent(hWnd, message, wParam, lParam, handled);
160         break;
161     case WM_TIMER:
162         lResult = onTimerEvent(hWnd, message, wParam, lParam, handled);
163         break;
164     case WM_SHOWWINDOW:
165         lResult = onShowWindowEvent(hWnd, message, wParam, lParam, handled);
166         break;
167     case WM_SETCURSOR:
168         lResult = onSetCursor(hWnd, message, wParam, lParam, handled);
169         break;
170     case WM_MENUCOMMAND:
171         lResult = onMenuCommand(hWnd, message, wParam, lParam, handled);
172         break;
173     default:
174         handled = false;
175         break;
176     }
177
178     if (!handled)
179         lResult = ::DefWindowProc(hWnd, message, wParam, lParam);
180
181     return lResult;
182 }
183
184 bool WebView::registerWebViewWindowClass()
185 {
186     static bool haveRegisteredWindowClass = false;
187     if (haveRegisteredWindowClass)
188         return true;
189     haveRegisteredWindowClass = true;
190
191     WNDCLASSEX wcex;
192
193     wcex.cbSize = sizeof(WNDCLASSEX);
194     wcex.style = CS_DBLCLKS;
195     wcex.lpfnWndProc = WebView::WebViewWndProc;
196     wcex.cbClsExtra = 0;
197     wcex.cbWndExtra = sizeof(WebView*);
198     wcex.hInstance = instanceHandle();
199     wcex.hIcon = 0;
200     wcex.hCursor = ::LoadCursor(0, IDC_ARROW);
201     wcex.hbrBackground = 0;
202     wcex.lpszMenuName = 0;
203     wcex.lpszClassName = kWebKit2WebViewWindowClassName;
204     wcex.hIconSm = 0;
205
206     return !!::RegisterClassEx(&wcex);
207 }
208
209 WebView::WebView(RECT rect, const API::PageConfiguration& configuration, HWND parentWindow)
210     : m_pageClient(std::make_unique<PageClientImpl>(*this))
211 {
212     registerWebViewWindowClass();
213
214     m_window = ::CreateWindowExW(0, kWebKit2WebViewWindowClassName, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
215         rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, parentWindow ? parentWindow : HWND_MESSAGE, 0, instanceHandle(), this);
216     ASSERT(::IsWindow(m_window));
217     // We only check our window style, and not ::IsWindowVisible, because m_isVisible only tracks
218     // this window's visibility status, while ::IsWindowVisible takes our ancestors' visibility
219     // status into account. <http://webkit.org/b/54104>
220     ASSERT(m_isVisible == static_cast<bool>(::GetWindowLong(m_window, GWL_STYLE) & WS_VISIBLE));
221
222     auto pageConfiguration = configuration.copy();
223     auto* preferences = pageConfiguration->preferences();
224     if (!preferences && pageConfiguration->pageGroup()) {
225         preferences = &pageConfiguration->pageGroup()->preferences();
226         pageConfiguration->setPreferences(preferences);
227     }
228     if (preferences) {
229         // Disable accelerated compositing until it is supported.
230         preferences->setAcceleratedCompositingEnabled(false);
231     }
232
233     WebProcessPool* processPool = pageConfiguration->processPool();
234     m_page = processPool->createWebPage(*m_pageClient, WTFMove(pageConfiguration));
235     m_page->initializeWebPage();
236
237     if (m_page->drawingArea())
238         m_page->drawingArea()->setSize(IntSize(rect.right - rect.left, rect.bottom - rect.top));
239
240     // FIXME: Initializing the tooltip window here matches WebKit win, but seems like something
241     // we could do on demand to save resources.
242     initializeToolTipWindow();
243
244     // Initialize the top level parent window and register it with the WindowMessageBroadcaster.
245     windowAncestryDidChange();
246 }
247
248 WebView::~WebView()
249 {
250     // Tooltip window needs to be explicitly destroyed since it isn't a WS_CHILD.
251     if (::IsWindow(m_toolTipWindow))
252         ::DestroyWindow(m_toolTipWindow);
253 }
254
255 void WebView::initialize()
256 {
257     if (shouldInitializeTrackPointHack()) {
258         // If we detected a registry key belonging to a TrackPoint driver, then create fake
259         // scrollbars, so the WebView will receive WM_VSCROLL and WM_HSCROLL messages.
260         // We create an invisible vertical scrollbar and an invisible horizontal scrollbar to allow
261         // for receiving both types of messages.
262         ::CreateWindow(TEXT("SCROLLBAR"), TEXT("FAKETRACKPOINTHSCROLLBAR"), WS_CHILD | WS_VISIBLE | SBS_HORZ, 0, 0, 0, 0, m_window, 0, instanceHandle(), 0);
263         ::CreateWindow(TEXT("SCROLLBAR"), TEXT("FAKETRACKPOINTVSCROLLBAR"), WS_CHILD | WS_VISIBLE | SBS_VERT, 0, 0, 0, 0, m_window, 0, instanceHandle(), 0);
264     }
265 }
266
267 void WebView::setParentWindow(HWND parentWindow)
268 {
269     if (m_window) {
270         // If the host window hasn't changed, bail.
271         if (::GetParent(m_window) == parentWindow)
272             return;
273         if (parentWindow)
274             ::SetParent(m_window, parentWindow);
275         else if (!m_isBeingDestroyed) {
276             // Turn the WebView into a message-only window so it will no longer be a child of the
277             // old parent window and will be hidden from screen. We only do this when
278             // isBeingDestroyed() is false because doing this while handling WM_DESTROY can leave
279             // m_window in a weird state (see <http://webkit.org/b/29337>).
280             ::SetParent(m_window, HWND_MESSAGE);
281         }
282     }
283
284     windowAncestryDidChange();
285 }
286
287 static HWND findTopLevelParentWindow(HWND window)
288 {
289     if (!window)
290         return 0;
291
292     HWND current = window;
293     for (HWND parent = GetParent(current); current; current = parent, parent = GetParent(parent)) {
294         if (!parent || !(GetWindowLongPtr(current, GWL_STYLE) & (WS_POPUP | WS_CHILD)))
295             return current;
296     }
297     ASSERT_NOT_REACHED();
298     return 0;
299 }
300
301 void WebView::windowAncestryDidChange()
302 {
303     HWND newTopLevelParentWindow;
304     if (m_window)
305         newTopLevelParentWindow = findTopLevelParentWindow(m_window);
306     else {
307         // There's no point in tracking active state changes of our parent window if we don't have
308         // a window ourselves.
309         newTopLevelParentWindow = 0;
310     }
311
312     if (newTopLevelParentWindow == m_topLevelParentWindow)
313         return;
314
315     if (m_topLevelParentWindow)
316         WindowMessageBroadcaster::removeListener(m_topLevelParentWindow, this);
317
318     m_topLevelParentWindow = newTopLevelParentWindow;
319
320     if (m_topLevelParentWindow)
321         WindowMessageBroadcaster::addListener(m_topLevelParentWindow, this);
322
323     updateActiveState();
324 }
325
326 LRESULT WebView::onMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
327 {
328     NativeWebMouseEvent mouseEvent = NativeWebMouseEvent(hWnd, message, wParam, lParam, m_wasActivatedByMouseEvent);
329     setWasActivatedByMouseEvent(false);
330
331     switch (message) {
332     case WM_LBUTTONDOWN:
333     case WM_MBUTTONDOWN:
334     case WM_RBUTTONDOWN:
335         ::SetFocus(m_window);
336         ::SetCapture(m_window);
337         break;
338     case WM_LBUTTONUP:
339     case WM_MBUTTONUP:
340     case WM_RBUTTONUP:
341         ::ReleaseCapture();
342         break;
343     case WM_MOUSEMOVE:
344         startTrackingMouseLeave();
345         break;
346     case WM_MOUSELEAVE:
347         stopTrackingMouseLeave();
348         break;
349     case WM_LBUTTONDBLCLK:
350     case WM_MBUTTONDBLCLK:
351     case WM_RBUTTONDBLCLK:
352         break;
353     default:
354         ASSERT_NOT_REACHED();
355     }
356
357     m_page->handleMouseEvent(mouseEvent);
358
359     handled = true;
360     return 0;
361 }
362
363 LRESULT WebView::onWheelEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
364 {
365     NativeWebWheelEvent wheelEvent(hWnd, message, wParam, lParam);
366     if (wheelEvent.controlKey()) {
367         // We do not want WebKit to handle Control + Wheel, this should be handled by the client application
368         // to zoom the page.
369         handled = false;
370         return 0;
371     }
372
373     m_page->handleWheelEvent(wheelEvent);
374
375     handled = true;
376     return 0;
377 }
378
379 LRESULT WebView::onHorizontalScroll(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
380 {
381     ScrollDirection direction;
382     ScrollGranularity granularity;
383     switch (LOWORD(wParam)) {
384     case SB_LINELEFT:
385         granularity = ScrollByLine;
386         direction = ScrollLeft;
387         break;
388     case SB_LINERIGHT:
389         granularity = ScrollByLine;
390         direction = ScrollRight;
391         break;
392     case SB_PAGELEFT:
393         granularity = ScrollByDocument;
394         direction = ScrollLeft;
395         break;
396     case SB_PAGERIGHT:
397         granularity = ScrollByDocument;
398         direction = ScrollRight;
399         break;
400     default:
401         handled = false;
402         return 0;
403     }
404
405     m_page->scrollBy(direction, granularity);
406
407     handled = true;
408     return 0;
409 }
410
411 LRESULT WebView::onVerticalScroll(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
412 {
413     ScrollDirection direction;
414     ScrollGranularity granularity;
415     switch (LOWORD(wParam)) {
416     case SB_LINEDOWN:
417         granularity = ScrollByLine;
418         direction = ScrollDown;
419         break;
420     case SB_LINEUP:
421         granularity = ScrollByLine;
422         direction = ScrollUp;
423         break;
424     case SB_PAGEDOWN:
425         granularity = ScrollByDocument;
426         direction = ScrollDown;
427         break;
428     case SB_PAGEUP:
429         granularity = ScrollByDocument;
430         direction = ScrollUp;
431         break;
432     default:
433         handled = false;
434         return 0;
435     }
436
437     m_page->scrollBy(direction, granularity);
438
439     handled = true;
440     return 0;
441 }
442
443 LRESULT WebView::onKeyEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
444 {
445     m_page->handleKeyboardEvent(NativeWebKeyboardEvent(hWnd, message, wParam, lParam));
446
447     // We claim here to always have handled the event. If the event is not in fact handled, we will
448     // find out later in didNotHandleKeyEvent.
449     handled = true;
450     return 0;
451 }
452
453 static void drawPageBackground(HDC dc, const WebPageProxy* page, const RECT& rect)
454 {
455     if (!page->drawsBackground())
456         return;
457
458     ::FillRect(dc, &rect, reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1));
459 }
460
461 void WebView::paint(HDC hdc, const IntRect& dirtyRect)
462 {
463     if (dirtyRect.isEmpty())
464         return;
465     m_page->endPrinting();
466     if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(m_page->drawingArea())) {
467         // FIXME: We should port WebKit1's rect coalescing logic here.
468         Region unpaintedRegion;
469         cairo_surface_t* surface = cairo_win32_surface_create(hdc);
470         cairo_t* context = cairo_create(surface);
471
472         drawingArea->paint(context, dirtyRect, unpaintedRegion);
473
474         cairo_destroy(context);
475         cairo_surface_destroy(surface);
476
477         Vector<IntRect> unpaintedRects = unpaintedRegion.rects();
478         for (size_t i = 0; i < unpaintedRects.size(); ++i) {
479             RECT winRect = unpaintedRects[i];
480             drawPageBackground(hdc, m_page.get(), unpaintedRects[i]);
481         }
482     } else
483         drawPageBackground(hdc, m_page.get(), dirtyRect);
484 }
485
486 LRESULT WebView::onPaintEvent(HWND hWnd, UINT message, WPARAM, LPARAM, bool& handled)
487 {
488     // Update child windows now so that any areas of our window they reveal will be included in the
489     // invalid region that ::BeginPaint sees.
490
491     PAINTSTRUCT paintStruct;
492     HDC hdc = ::BeginPaint(m_window, &paintStruct);
493     paint(hdc, paintStruct.rcPaint);
494
495     ::EndPaint(m_window, &paintStruct);
496
497     handled = true;
498     return 0;
499 }
500
501 LRESULT WebView::onPrintClientEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
502 {
503     HDC hdc = reinterpret_cast<HDC>(wParam);
504     RECT winRect;
505     ::GetClientRect(hWnd, &winRect);
506
507     paint(hdc, winRect);
508
509     handled = true;
510     return 0;
511 }
512
513 LRESULT WebView::onSizeEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
514 {
515     int width = LOWORD(lParam);
516     int height = HIWORD(lParam);
517
518     if (m_page && m_page->drawingArea()) {
519         // FIXME specify correctly layerPosition.
520         m_page->drawingArea()->setSize(IntSize(width, height), m_nextResizeScrollOffset);
521         m_nextResizeScrollOffset = IntSize();
522     }
523
524     handled = true;
525     return 0;
526 }
527
528 LRESULT WebView::onWindowPositionChangedEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
529 {
530     if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
531         updateActiveStateSoon();
532
533     handled = false;
534     return 0;
535 }
536
537 LRESULT WebView::onSetFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
538 {
539     m_page->activityStateDidChange(ActivityState::IsFocused);
540     handled = true;
541     return 0;
542 }
543
544 LRESULT WebView::onKillFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
545 {
546     m_page->activityStateDidChange(ActivityState::IsFocused);
547     handled = true;
548     return 0;
549 }
550
551 LRESULT WebView::onTimerEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
552 {
553     switch (wParam) {
554     case UpdateActiveStateTimer:
555         ::KillTimer(hWnd, UpdateActiveStateTimer);
556         updateActiveState();
557         break;
558     }
559
560     handled = true;
561     return 0;
562 }
563
564 LRESULT WebView::onShowWindowEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
565 {
566     // lParam is 0 when the message is sent because of a ShowWindow call.
567     // FIXME: Since we don't get notified when an ancestor window is hidden or shown, we will keep
568     // painting even when we have a hidden ancestor. <http://webkit.org/b/54104>
569     if (!lParam)
570         setIsVisible(wParam);
571
572     handled = false;
573     return 0;
574 }
575
576 LRESULT WebView::onSetCursor(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
577 {
578     if (!m_lastCursorSet) {
579         handled = false;
580         return 0;
581     }
582
583     ::SetCursor(m_lastCursorSet);
584     return 0;
585 }
586
587 LRESULT WebView::onMenuCommand(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
588 {
589     auto hMenu = reinterpret_cast<HMENU>(lParam);
590     auto index = static_cast<unsigned>(wParam);
591
592     MENUITEMINFO menuItemInfo;
593     menuItemInfo.cbSize = sizeof(menuItemInfo);
594     menuItemInfo.cch = 0;
595     menuItemInfo.fMask = MIIM_STRING;
596     ::GetMenuItemInfo(hMenu, index, TRUE, &menuItemInfo);
597
598     menuItemInfo.cch++;
599     Vector<WCHAR> buffer(menuItemInfo.cch);
600     menuItemInfo.dwTypeData = buffer.data();
601     menuItemInfo.fMask |= MIIM_ID;
602
603     ::GetMenuItemInfo(hMenu, index, TRUE, &menuItemInfo);
604
605     String title(buffer.data(), menuItemInfo.cch);
606     ContextMenuAction action = static_cast<ContextMenuAction>(menuItemInfo.wID);
607     bool enabled = !(menuItemInfo.fState & MFS_DISABLED);
608     bool checked = menuItemInfo.fState & MFS_CHECKED;
609     WebContextMenuItemData item(ContextMenuItemType::ActionType, action, title, enabled, checked);
610     m_page->contextMenuItemSelected(item);
611
612     handled = true;
613     return 0;
614 }
615
616 void WebView::updateActiveState()
617 {
618     m_page->activityStateDidChange(ActivityState::WindowIsActive);
619 }
620
621 void WebView::updateActiveStateSoon()
622 {
623     // This function is called while processing the WM_NCACTIVATE message.
624     // While processing WM_NCACTIVATE when we are being deactivated, GetActiveWindow() will
625     // still return our window. If we were to call updateActiveState() in that case, we would
626     // wrongly think that we are still the active window. To work around this, we update our
627     // active state after a 0-delay timer fires, at which point GetActiveWindow() will return
628     // the newly-activated window.
629
630     ::SetTimer(m_window, UpdateActiveStateTimer, 0, 0);
631 }
632
633 static bool initCommonControls()
634 {
635     static bool haveInitialized = false;
636     if (haveInitialized)
637         return true;
638
639     INITCOMMONCONTROLSEX init;
640     init.dwSize = sizeof(init);
641     init.dwICC = ICC_TREEVIEW_CLASSES;
642     haveInitialized = !!::InitCommonControlsEx(&init);
643     return haveInitialized;
644 }
645
646 void WebView::initializeToolTipWindow()
647 {
648     if (!initCommonControls())
649         return;
650
651     m_toolTipWindow = ::CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
652         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
653         m_window, 0, 0, 0);
654     if (!m_toolTipWindow)
655         return;
656
657     TOOLINFO info = { 0 };
658     info.cbSize = sizeof(info);
659     info.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
660     info.uId = reinterpret_cast<UINT_PTR>(m_window);
661
662     ::SendMessage(m_toolTipWindow, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
663     ::SendMessage(m_toolTipWindow, TTM_SETMAXTIPWIDTH, 0, kMaxToolTipWidth);
664     ::SetWindowPos(m_toolTipWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
665 }
666
667 void WebView::startTrackingMouseLeave()
668 {
669     if (m_trackingMouseLeave)
670         return;
671     m_trackingMouseLeave = true;
672
673     TRACKMOUSEEVENT trackMouseEvent;
674     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
675     trackMouseEvent.dwFlags = TME_LEAVE;
676     trackMouseEvent.hwndTrack = m_window;
677
678     ::TrackMouseEvent(&trackMouseEvent);
679 }
680
681 void WebView::stopTrackingMouseLeave()
682 {
683     if (!m_trackingMouseLeave)
684         return;
685     m_trackingMouseLeave = false;
686
687     TRACKMOUSEEVENT trackMouseEvent;
688     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
689     trackMouseEvent.dwFlags = TME_LEAVE | TME_CANCEL;
690     trackMouseEvent.hwndTrack = m_window;
691
692     ::TrackMouseEvent(&trackMouseEvent);
693 }
694
695 bool WebView::shouldInitializeTrackPointHack()
696 {
697     static bool shouldCreateScrollbars;
698     static bool hasRunTrackPointCheck;
699
700     if (hasRunTrackPointCheck)
701         return shouldCreateScrollbars;
702
703     hasRunTrackPointCheck = true;
704     const wchar_t* trackPointKeys[] = {
705         L"Software\\Lenovo\\TrackPoint",
706         L"Software\\Lenovo\\UltraNav",
707         L"Software\\Alps\\Apoint\\TrackPoint",
708         L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
709         L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"
710     };
711
712     for (size_t i = 0; i < WTF_ARRAY_LENGTH(trackPointKeys); ++i) {
713         HKEY trackPointKey;
714         int readKeyResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, trackPointKeys[i], 0, KEY_READ, &trackPointKey);
715         ::RegCloseKey(trackPointKey);
716         if (readKeyResult == ERROR_SUCCESS) {
717             shouldCreateScrollbars = true;
718             return shouldCreateScrollbars;
719         }
720     }
721
722     return shouldCreateScrollbars;
723 }
724
725 void WebView::close()
726 {
727     if (m_window) {
728         // We can't check IsWindow(m_window) here, because that will return true even while
729         // we're already handling WM_DESTROY. So we check !m_isBeingDestroyed instead.
730         if (!m_isBeingDestroyed)
731             DestroyWindow(m_window);
732         // Either we just destroyed m_window, or it's in the process of being destroyed. Either
733         // way, we clear it out to make sure we don't try to use it later.
734         m_window = 0;
735     }
736     setParentWindow(0);
737     m_page->close();
738 }
739
740 HCURSOR WebView::cursorToShow() const
741 {
742     if (!m_page->isValid())
743         return 0;
744
745     // We only show the override cursor if the default (arrow) cursor is showing.
746     static HCURSOR arrowCursor = ::LoadCursor(0, IDC_ARROW);
747     if (m_overrideCursor && m_webCoreCursor == arrowCursor)
748         return m_overrideCursor;
749
750     return m_webCoreCursor;
751 }
752
753 void WebView::setCursor(const WebCore::Cursor& cursor)
754 {
755     if (!cursor.platformCursor()->nativeCursor())
756         return;
757     m_webCoreCursor = cursor.platformCursor()->nativeCursor();
758     updateNativeCursor();
759 }
760
761 void WebView::updateNativeCursor()
762 {
763     m_lastCursorSet = cursorToShow();
764     if (!m_lastCursorSet)
765         return;
766     ::SetCursor(m_lastCursorSet);
767 }
768
769 void WebView::setOverrideCursor(HCURSOR overrideCursor)
770 {
771     m_overrideCursor = overrideCursor;
772     updateNativeCursor();
773 }
774
775 void WebView::setIsInWindow(bool isInWindow)
776 {
777     m_isInWindow = isInWindow;
778     if (m_page)
779         m_page->activityStateDidChange(ActivityState::IsInWindow);
780 }
781
782 void WebView::setIsVisible(bool isVisible)
783 {
784     m_isVisible = isVisible;
785     if (m_page)
786         m_page->activityStateDidChange(ActivityState::IsVisible);
787 }
788
789 bool WebView::isWindowActive()
790 {
791     HWND activeWindow = ::GetActiveWindow();
792     return (activeWindow && m_topLevelParentWindow == findTopLevelParentWindow(activeWindow));
793 }
794
795 bool WebView::isFocused()
796 {
797     return ::GetFocus() == m_window;
798 }
799
800 bool WebView::isVisible()
801 {
802     return m_isVisible;
803 }
804
805 bool WebView::isInWindow()
806 {
807     return m_isInWindow;
808 }
809
810 void WebView::setScrollOffsetOnNextResize(const IntSize& scrollOffset)
811 {
812     // The next time we get a WM_SIZE message, scroll by the specified amount in onSizeEvent().
813     m_nextResizeScrollOffset = scrollOffset;
814 }
815
816 void WebView::setViewNeedsDisplay(const WebCore::Region& region)
817 {
818     const RECT r = region.bounds();
819     ::InvalidateRect(m_window, &r, true);
820 }
821
822 #if ENABLE(INPUT_TYPE_COLOR)
823 PassRefPtr<WebColorChooserProxy> WebView::createColorChooserProxy(WebPageProxy*, const WebCore::Color&, const WebCore::IntRect&)
824 {
825     notImplemented();
826     return 0;
827 }
828 #endif
829
830 void WebView::didCommitLoadForMainFrame(bool useCustomRepresentation)
831 {
832 }
833
834 double WebView::customRepresentationZoomFactor()
835 {
836     return 1;
837 }
838
839 void WebView::setCustomRepresentationZoomFactor(double)
840 {
841 }
842
843 void WebView::findStringInCustomRepresentation(const String&, FindOptions, unsigned)
844 {
845 }
846
847 void WebView::countStringMatchesInCustomRepresentation(const String&, FindOptions, unsigned)
848 {
849 }
850
851 HWND WebView::nativeWindow()
852 {
853     return m_window;
854 }
855
856 // WebCore::WindowMessageListener
857
858 void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
859 {
860     switch (message) {
861     case WM_NCACTIVATE:
862         updateActiveStateSoon();
863         break;
864     case WM_SETTINGCHANGE:
865         break;
866     }
867 }
868
869 void WebView::setToolTip(const String& toolTip)
870 {
871     if (!m_toolTipWindow)
872         return;
873
874     if (!toolTip.isEmpty()) {
875         TOOLINFO info = { 0 };
876         info.cbSize = sizeof(info);
877         info.uFlags = TTF_IDISHWND;
878         info.uId = reinterpret_cast<UINT_PTR>(nativeWindow());
879         Vector<UChar> toolTipCharacters = toolTip.charactersWithNullTermination(); // Retain buffer long enough to make the SendMessage call
880         info.lpszText = const_cast<UChar*>(toolTipCharacters.data());
881         ::SendMessage(m_toolTipWindow, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
882     }
883
884     ::SendMessage(m_toolTipWindow, TTM_ACTIVATE, !toolTip.isEmpty(), 0);
885 }
886
887 } // namespace WebKit