1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
4 * Copyright (C) 2011 Igalia S.L.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25 * THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "config.h"
29#include "WebKitWebViewBase.h"
30
31#include "DrawingAreaProxyImpl.h"
32#include "NativeWebMouseEvent.h"
33#include "NativeWebWheelEvent.h"
34#include "PageClientImpl.h"
35#include "WebContext.h"
36#include "WebEventFactory.h"
37#include "WebFullScreenClientGtk.h"
38#include "WebInspectorProxy.h"
39#include "WebKitAuthenticationDialog.h"
40#include "WebKitPrivate.h"
41#include "WebKitWebViewBaseAccessible.h"
42#include "WebKitWebViewBasePrivate.h"
43#include "WebPageProxy.h"
44#include "WebViewBaseInputMethodFilter.h"
45#include <WebCore/ClipboardUtilitiesGtk.h>
46#include <WebCore/DataObjectGtk.h>
47#include <WebCore/DragData.h>
48#include <WebCore/DragIcon.h>
49#include <WebCore/GOwnPtrGtk.h>
50#include <WebCore/GtkClickCounter.h>
51#include <WebCore/GtkDragAndDropHelper.h>
52#include <WebCore/GtkUtilities.h>
53#include <WebCore/GtkVersioning.h>
54#include <WebCore/NotImplemented.h>
55#include <WebCore/PasteboardHelper.h>
56#include <WebCore/RefPtrCairo.h>
57#include <WebCore/Region.h>
58#include <gdk/gdk.h>
59#include <gdk/gdkkeysyms.h>
60#include <wtf/HashMap.h>
61#include <wtf/gobject/GOwnPtr.h>
62#include <wtf/gobject/GRefPtr.h>
63#include <wtf/text/CString.h>
64
65#if ENABLE(FULLSCREEN_API)
66#include "WebFullScreenManagerProxy.h"
67#endif
68
69#if USE(TEXTURE_MAPPER_GL) && defined(GDK_WINDOWING_X11)
70#include <WebCore/RedirectedXCompositeWindow.h>
71#endif
72
73using namespace WebKit;
74using namespace WebCore;
75
76typedef HashMap<GtkWidget*, IntRect> WebKitWebViewChildrenMap;
77
78#if USE(TEXTURE_MAPPER_GL)
79void redirectedWindowDamagedCallback(void* data);
80#endif
81
82struct _WebKitWebViewBasePrivate {
83    _WebKitWebViewBasePrivate()
84#if USE(TEXTURE_MAPPER_GL)
85        : redirectedWindow(RedirectedXCompositeWindow::create(IntSize(1, 1), RedirectedXCompositeWindow::DoNotCreateGLContext))
86#endif
87    {
88    }
89
90    ~_WebKitWebViewBasePrivate()
91    {
92        pageProxy->close();
93    }
94
95    WebKitWebViewChildrenMap children;
96    OwnPtr<PageClientImpl> pageClient;
97    RefPtr<WebPageProxy> pageProxy;
98    bool shouldForwardNextKeyEvent;
99    GtkClickCounter clickCounter;
100    CString tooltipText;
101    IntRect tooltipArea;
102    GtkDragAndDropHelper dragAndDropHelper;
103    DragIcon dragIcon;
104    IntSize resizerSize;
105    GRefPtr<AtkObject> accessible;
106    bool needsResizeOnMap;
107    GtkWidget* authenticationDialog;
108    GtkWidget* inspectorView;
109    unsigned inspectorViewHeight;
110    GOwnPtr<GdkEvent> contextMenuEvent;
111    WebContextMenuProxyGtk* activeContextMenuProxy;
112    WebViewBaseInputMethodFilter inputMethodFilter;
113
114    GtkWindow* toplevelOnScreenWindow;
115    unsigned long toplevelResizeGripVisibilityID;
116    unsigned long toplevelFocusInEventID;
117    unsigned long toplevelFocusOutEventID;
118
119    // View State.
120    bool isInWindowActive : 1;
121    bool isFocused : 1;
122    bool isVisible : 1;
123
124    WebKitWebViewBaseDownloadRequestHandler downloadHandler;
125
126#if ENABLE(FULLSCREEN_API)
127    bool fullScreenModeActive;
128    WebFullScreenClientGtk fullScreenClient;
129#endif
130
131#if USE(TEXTURE_MAPPER_GL)
132    OwnPtr<RedirectedXCompositeWindow> redirectedWindow;
133#endif
134};
135
136WEBKIT_DEFINE_TYPE(WebKitWebViewBase, webkit_web_view_base, GTK_TYPE_CONTAINER)
137
138static void webkitWebViewBaseNotifyResizerSize(WebKitWebViewBase* webViewBase)
139{
140    WebKitWebViewBasePrivate* priv = webViewBase->priv;
141    if (!priv->toplevelOnScreenWindow)
142        return;
143
144    gboolean resizerVisible;
145    g_object_get(G_OBJECT(priv->toplevelOnScreenWindow), "resize-grip-visible", &resizerVisible, NULL);
146
147    IntSize resizerSize;
148    if (resizerVisible) {
149        GdkRectangle resizerRect;
150        gtk_window_get_resize_grip_area(priv->toplevelOnScreenWindow, &resizerRect);
151        GdkRectangle allocation;
152        gtk_widget_get_allocation(GTK_WIDGET(webViewBase), &allocation);
153        if (gdk_rectangle_intersect(&resizerRect, &allocation, 0))
154            resizerSize = IntSize(resizerRect.width, resizerRect.height);
155    }
156
157    if (resizerSize != priv->resizerSize) {
158        priv->resizerSize = resizerSize;
159        priv->pageProxy->setWindowResizerSize(resizerSize);
160    }
161}
162
163static void toplevelWindowResizeGripVisibilityChanged(GObject*, GParamSpec*, WebKitWebViewBase* webViewBase)
164{
165    webkitWebViewBaseNotifyResizerSize(webViewBase);
166}
167
168static gboolean toplevelWindowFocusInEvent(GtkWidget* widget, GdkEventFocus*, WebKitWebViewBase* webViewBase)
169{
170    WebKitWebViewBasePrivate* priv = webViewBase->priv;
171    if (!priv->isInWindowActive) {
172        priv->isInWindowActive = true;
173        priv->pageProxy->viewStateDidChange(WebPageProxy::ViewWindowIsActive);
174    }
175
176    return FALSE;
177}
178
179static gboolean toplevelWindowFocusOutEvent(GtkWidget* widget, GdkEventFocus*, WebKitWebViewBase* webViewBase)
180{
181    WebKitWebViewBasePrivate* priv = webViewBase->priv;
182    if (priv->isInWindowActive) {
183        priv->isInWindowActive = false;
184        priv->pageProxy->viewStateDidChange(WebPageProxy::ViewWindowIsActive);
185    }
186
187    return FALSE;
188}
189
190static void webkitWebViewBaseSetToplevelOnScreenWindow(WebKitWebViewBase* webViewBase, GtkWindow* window)
191{
192    WebKitWebViewBasePrivate* priv = webViewBase->priv;
193    if (priv->toplevelOnScreenWindow == window)
194        return;
195
196    if (priv->toplevelResizeGripVisibilityID) {
197        g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelResizeGripVisibilityID);
198        priv->toplevelResizeGripVisibilityID = 0;
199    }
200    if (priv->toplevelFocusInEventID) {
201        g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusInEventID);
202        priv->toplevelFocusInEventID = 0;
203    }
204    if (priv->toplevelFocusOutEventID) {
205        g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusOutEventID);
206        priv->toplevelFocusOutEventID = 0;
207    }
208
209    priv->toplevelOnScreenWindow = window;
210    priv->pageProxy->viewStateDidChange(WebPageProxy::ViewIsInWindow);
211    if (!priv->toplevelOnScreenWindow)
212        return;
213
214    webkitWebViewBaseNotifyResizerSize(webViewBase);
215
216    priv->toplevelResizeGripVisibilityID =
217        g_signal_connect(priv->toplevelOnScreenWindow, "notify::resize-grip-visible",
218                         G_CALLBACK(toplevelWindowResizeGripVisibilityChanged), webViewBase);
219    priv->toplevelFocusInEventID =
220        g_signal_connect(priv->toplevelOnScreenWindow, "focus-in-event",
221                         G_CALLBACK(toplevelWindowFocusInEvent), webViewBase);
222    priv->toplevelFocusOutEventID =
223        g_signal_connect(priv->toplevelOnScreenWindow, "focus-out-event",
224                         G_CALLBACK(toplevelWindowFocusOutEvent), webViewBase);
225}
226
227static void webkitWebViewBaseRealize(GtkWidget* widget)
228{
229    gtk_widget_set_realized(widget, TRUE);
230
231    GtkAllocation allocation;
232    gtk_widget_get_allocation(widget, &allocation);
233
234    GdkWindowAttr attributes;
235    attributes.window_type = GDK_WINDOW_CHILD;
236    attributes.x = allocation.x;
237    attributes.y = allocation.y;
238    attributes.width = allocation.width;
239    attributes.height = allocation.height;
240    attributes.wclass = GDK_INPUT_OUTPUT;
241    attributes.visual = gtk_widget_get_visual(widget);
242    attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK
243        | GDK_EXPOSURE_MASK
244        | GDK_BUTTON_PRESS_MASK
245        | GDK_BUTTON_RELEASE_MASK
246        | GDK_SCROLL_MASK
247        | GDK_SMOOTH_SCROLL_MASK
248        | GDK_POINTER_MOTION_MASK
249        | GDK_KEY_PRESS_MASK
250        | GDK_KEY_RELEASE_MASK
251        | GDK_BUTTON_MOTION_MASK
252        | GDK_BUTTON1_MOTION_MASK
253        | GDK_BUTTON2_MOTION_MASK
254        | GDK_BUTTON3_MOTION_MASK;
255
256    gint attributesMask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
257
258    GdkWindow* window = gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributesMask);
259    gtk_widget_set_window(widget, window);
260    gdk_window_set_user_data(window, widget);
261
262    gtk_style_context_set_background(gtk_widget_get_style_context(widget), window);
263
264    WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget);
265    GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
266    if (widgetIsOnscreenToplevelWindow(toplevel))
267        webkitWebViewBaseSetToplevelOnScreenWindow(webView, GTK_WINDOW(toplevel));
268}
269
270static bool webkitWebViewChildIsInternalWidget(WebKitWebViewBase* webViewBase, GtkWidget* widget)
271{
272    WebKitWebViewBasePrivate* priv = webViewBase->priv;
273    return widget == priv->inspectorView || widget == priv->authenticationDialog;
274}
275
276static void webkitWebViewBaseContainerAdd(GtkContainer* container, GtkWidget* widget)
277{
278    WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
279    WebKitWebViewBasePrivate* priv = webView->priv;
280
281    // Internal widgets like the web inspector and authentication dialog have custom
282    // allocations so we don't need to add them to our list of children.
283    if (!webkitWebViewChildIsInternalWidget(webView, widget)) {
284        GtkAllocation childAllocation;
285        gtk_widget_get_allocation(widget, &childAllocation);
286        priv->children.set(widget, childAllocation);
287    }
288
289    gtk_widget_set_parent(widget, GTK_WIDGET(container));
290}
291
292void webkitWebViewBaseAddAuthenticationDialog(WebKitWebViewBase* webViewBase, GtkWidget* dialog)
293{
294    WebKitWebViewBasePrivate* priv = webViewBase->priv;
295    priv->authenticationDialog = dialog;
296    gtk_container_add(GTK_CONTAINER(webViewBase), dialog);
297    gtk_widget_show(dialog);
298
299    // We need to draw the shadow over the widget.
300    gtk_widget_queue_draw(GTK_WIDGET(webViewBase));
301}
302
303void webkitWebViewBaseCancelAuthenticationDialog(WebKitWebViewBase* webViewBase)
304{
305    WebKitWebViewBasePrivate* priv = webViewBase->priv;
306    if (priv->authenticationDialog)
307        gtk_widget_destroy(priv->authenticationDialog);
308}
309
310void webkitWebViewBaseAddWebInspector(WebKitWebViewBase* webViewBase, GtkWidget* inspector)
311{
312    webViewBase->priv->inspectorView = inspector;
313    gtk_container_add(GTK_CONTAINER(webViewBase), inspector);
314}
315
316static void webkitWebViewBaseContainerRemove(GtkContainer* container, GtkWidget* widget)
317{
318    WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
319    WebKitWebViewBasePrivate* priv = webView->priv;
320    GtkWidget* widgetContainer = GTK_WIDGET(container);
321
322    gboolean wasVisible = gtk_widget_get_visible(widget);
323    gtk_widget_unparent(widget);
324
325    if (priv->inspectorView == widget) {
326        priv->inspectorView = 0;
327        priv->inspectorViewHeight = 0;
328    } else if (priv->authenticationDialog == widget) {
329        priv->authenticationDialog = 0;
330    } else {
331        ASSERT(priv->children.contains(widget));
332        priv->children.remove(widget);
333    }
334    if (wasVisible && gtk_widget_get_visible(widgetContainer))
335        gtk_widget_queue_resize(widgetContainer);
336}
337
338static void webkitWebViewBaseContainerForall(GtkContainer* container, gboolean includeInternals, GtkCallback callback, gpointer callbackData)
339{
340    WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
341    WebKitWebViewBasePrivate* priv = webView->priv;
342
343    WebKitWebViewChildrenMap children = priv->children;
344    WebKitWebViewChildrenMap::const_iterator end = children.end();
345    for (WebKitWebViewChildrenMap::const_iterator current = children.begin(); current != end; ++current)
346        (*callback)(current->key, callbackData);
347
348    if (includeInternals && priv->inspectorView)
349        (*callback)(priv->inspectorView, callbackData);
350
351    if (includeInternals && priv->authenticationDialog)
352        (*callback)(priv->authenticationDialog, callbackData);
353}
354
355void webkitWebViewBaseChildMoveResize(WebKitWebViewBase* webView, GtkWidget* child, const IntRect& childRect)
356{
357    const IntRect& geometry = webView->priv->children.get(child);
358    if (geometry == childRect)
359        return;
360
361    webView->priv->children.set(child, childRect);
362    gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webView));
363}
364
365static void webkitWebViewBaseDispose(GObject* gobject)
366{
367    webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(gobject), 0);
368    G_OBJECT_CLASS(webkit_web_view_base_parent_class)->dispose(gobject);
369}
370
371static void webkitWebViewBaseConstructed(GObject* object)
372{
373    G_OBJECT_CLASS(webkit_web_view_base_parent_class)->constructed(object);
374
375    GtkWidget* viewWidget = GTK_WIDGET(object);
376    gtk_widget_set_can_focus(viewWidget, TRUE);
377    gtk_drag_dest_set(viewWidget, static_cast<GtkDestDefaults>(0), 0, 0,
378                      static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_PRIVATE));
379    gtk_drag_dest_set_target_list(viewWidget, PasteboardHelper::defaultPasteboardHelper()->targetList());
380
381    WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(object)->priv;
382    priv->pageClient = PageClientImpl::create(viewWidget);
383    priv->dragAndDropHelper.setWidget(viewWidget);
384
385#if USE(TEXTURE_MAPPER_GL)
386    if (priv->redirectedWindow)
387        priv->redirectedWindow->setDamageNotifyCallback(redirectedWindowDamagedCallback, object);
388#endif
389
390    priv->authenticationDialog = 0;
391}
392
393#if USE(TEXTURE_MAPPER_GL)
394static bool webkitWebViewRenderAcceleratedCompositingResults(WebKitWebViewBase* webViewBase, DrawingAreaProxyImpl* drawingArea, cairo_t* cr, GdkRectangle* clipRect)
395{
396    if (!drawingArea->isInAcceleratedCompositingMode())
397        return false;
398
399    // To avoid flashes when initializing accelerated compositing for the first
400    // time, we wait until we know there's a frame ready before rendering.
401    WebKitWebViewBasePrivate* priv = webViewBase->priv;
402    if (!priv->redirectedWindow)
403        return false;
404
405    cairo_rectangle(cr, clipRect->x, clipRect->y, clipRect->width, clipRect->height);
406    cairo_surface_t* surface = priv->redirectedWindow->cairoSurfaceForWidget(GTK_WIDGET(webViewBase));
407    cairo_set_source_surface(cr, surface, 0, 0);
408    cairo_fill(cr);
409    return true;
410}
411#endif
412
413static gboolean webkitWebViewBaseDraw(GtkWidget* widget, cairo_t* cr)
414{
415    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
416    DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(webViewBase->priv->pageProxy->drawingArea());
417    if (!drawingArea)
418        return FALSE;
419
420    GdkRectangle clipRect;
421    if (!gdk_cairo_get_clip_rectangle(cr, &clipRect))
422        return FALSE;
423
424#if USE(TEXTURE_MAPPER_GL)
425    if (webkitWebViewRenderAcceleratedCompositingResults(webViewBase, drawingArea, cr, &clipRect))
426        return FALSE;
427#endif
428
429    WebCore::Region unpaintedRegion; // This is simply unused.
430    drawingArea->paint(cr, clipRect, unpaintedRegion);
431
432    if (webViewBase->priv->authenticationDialog) {
433        cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
434        cairo_set_source_rgba(cr, 0, 0, 0, 0.5);
435        cairo_paint(cr);
436    }
437
438    GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->draw(widget, cr);
439
440    return FALSE;
441}
442
443static void webkitWebViewBaseChildAllocate(GtkWidget* child, gpointer userData)
444{
445    if (!gtk_widget_get_visible(child))
446        return;
447
448    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(userData);
449    WebKitWebViewBasePrivate* priv = webViewBase->priv;
450    const IntRect& geometry = priv->children.get(child);
451    if (geometry.isEmpty())
452        return;
453
454    GtkAllocation childAllocation = geometry;
455    gtk_widget_size_allocate(child, &childAllocation);
456    priv->children.set(child, IntRect());
457}
458
459static void resizeWebKitWebViewBaseFromAllocation(WebKitWebViewBase* webViewBase, GtkAllocation* allocation, bool sizeChanged)
460{
461    gtk_container_foreach(GTK_CONTAINER(webViewBase), webkitWebViewBaseChildAllocate, webViewBase);
462
463    IntRect viewRect(allocation->x, allocation->y, allocation->width, allocation->height);
464    WebKitWebViewBasePrivate* priv = webViewBase->priv;
465    if (priv->inspectorView) {
466        int inspectorViewHeight = std::min(static_cast<int>(priv->inspectorViewHeight), allocation->height);
467        GtkAllocation childAllocation = viewRect;
468        childAllocation.y = allocation->height - inspectorViewHeight;
469        childAllocation.height = inspectorViewHeight;
470        gtk_widget_size_allocate(priv->inspectorView, &childAllocation);
471
472        viewRect.setHeight(std::max(allocation->height - inspectorViewHeight, 1));
473    }
474
475    // The authentication dialog is centered in the view rect, which means that it
476    // never overlaps the web inspector. Thus, we need to calculate the allocation here
477    // after calculating the inspector allocation.
478    if (priv->authenticationDialog) {
479        GtkRequisition naturalSize;
480        gtk_widget_get_preferred_size(priv->authenticationDialog, 0, &naturalSize);
481
482        GtkAllocation childAllocation = {
483            (viewRect.width() - naturalSize.width) / 2,
484            (viewRect.height() - naturalSize.height) / 2,
485            naturalSize.width,
486            naturalSize.height
487        };
488        gtk_widget_size_allocate(priv->authenticationDialog, &childAllocation);
489    }
490
491#if USE(TEXTURE_MAPPER_GL)
492    if (sizeChanged && webViewBase->priv->redirectedWindow)
493        webViewBase->priv->redirectedWindow->resize(viewRect.size());
494#endif
495
496    if (priv->pageProxy->drawingArea())
497        priv->pageProxy->drawingArea()->setSize(viewRect.size(), IntSize(), IntSize());
498
499    webkitWebViewBaseNotifyResizerSize(webViewBase);
500}
501
502static void webkitWebViewBaseSizeAllocate(GtkWidget* widget, GtkAllocation* allocation)
503{
504    bool sizeChanged = gtk_widget_get_allocated_width(widget) != allocation->width
505                       || gtk_widget_get_allocated_height(widget) != allocation->height;
506
507    GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->size_allocate(widget, allocation);
508
509    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
510    if (sizeChanged && !gtk_widget_get_mapped(widget) && !webViewBase->priv->pageProxy->drawingArea()->size().isEmpty()) {
511        webViewBase->priv->needsResizeOnMap = true;
512        return;
513    }
514
515    resizeWebKitWebViewBaseFromAllocation(webViewBase, allocation, sizeChanged);
516}
517
518static void webkitWebViewBaseMap(GtkWidget* widget)
519{
520    GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->map(widget);
521
522    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
523    WebKitWebViewBasePrivate* priv = webViewBase->priv;
524    if (!priv->isVisible) {
525        priv->isVisible = true;
526        priv->pageProxy->viewStateDidChange(WebPageProxy::ViewIsVisible);
527    }
528
529    if (!priv->needsResizeOnMap)
530        return;
531
532    GtkAllocation allocation;
533    gtk_widget_get_allocation(widget, &allocation);
534    resizeWebKitWebViewBaseFromAllocation(webViewBase, &allocation, true /* sizeChanged */);
535    priv->needsResizeOnMap = false;
536}
537
538static void webkitWebViewBaseUnmap(GtkWidget* widget)
539{
540    GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->unmap(widget);
541
542    WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
543    if (priv->isVisible) {
544        priv->isVisible = false;
545        priv->pageProxy->viewStateDidChange(WebPageProxy::ViewIsVisible);
546    }
547}
548
549static gboolean webkitWebViewBaseFocusInEvent(GtkWidget* widget, GdkEventFocus* event)
550{
551    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
552    webkitWebViewBaseSetFocus(webViewBase, true);
553    webViewBase->priv->inputMethodFilter.notifyFocusedIn();
554
555    return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_in_event(widget, event);
556}
557
558static gboolean webkitWebViewBaseFocusOutEvent(GtkWidget* widget, GdkEventFocus* event)
559{
560    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
561    webkitWebViewBaseSetFocus(webViewBase, false);
562    webViewBase->priv->inputMethodFilter.notifyFocusedOut();
563
564    return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_out_event(widget, event);
565}
566
567static gboolean webkitWebViewBaseKeyPressEvent(GtkWidget* widget, GdkEventKey* event)
568{
569    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
570    WebKitWebViewBasePrivate* priv = webViewBase->priv;
571
572    if (priv->authenticationDialog)
573        return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, event);
574
575#if ENABLE(FULLSCREEN_API)
576    if (priv->fullScreenModeActive) {
577        switch (event->keyval) {
578        case GDK_KEY_Escape:
579        case GDK_KEY_f:
580        case GDK_KEY_F:
581            webkitWebViewBaseExitFullScreen(webViewBase);
582            return TRUE;
583        default:
584            break;
585        }
586    }
587#endif
588
589    // Since WebProcess key event handling is not synchronous, handle the event in two passes.
590    // When WebProcess processes the input event, it will call PageClientImpl::doneWithKeyEvent
591    // with event handled status which determines whether to pass the input event to parent or not
592    // using gtk_main_do_event().
593    if (priv->shouldForwardNextKeyEvent) {
594        priv->shouldForwardNextKeyEvent = FALSE;
595        return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, event);
596    }
597    priv->inputMethodFilter.filterKeyEvent(event);
598    return TRUE;
599}
600
601static gboolean webkitWebViewBaseKeyReleaseEvent(GtkWidget* widget, GdkEventKey* event)
602{
603    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
604    WebKitWebViewBasePrivate* priv = webViewBase->priv;
605
606    if (priv->shouldForwardNextKeyEvent) {
607        priv->shouldForwardNextKeyEvent = FALSE;
608        return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_release_event(widget, event);
609    }
610    priv->inputMethodFilter.filterKeyEvent(event);
611    return TRUE;
612}
613
614static gboolean webkitWebViewBaseButtonPressEvent(GtkWidget* widget, GdkEventButton* buttonEvent)
615{
616    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
617    WebKitWebViewBasePrivate* priv = webViewBase->priv;
618
619    if (priv->authenticationDialog)
620        return TRUE;
621
622    gtk_widget_grab_focus(widget);
623
624    priv->inputMethodFilter.notifyMouseButtonPress();
625
626    if (!priv->clickCounter.shouldProcessButtonEvent(buttonEvent))
627        return TRUE;
628
629    // If it's a right click event save it as a possible context menu event.
630    if (buttonEvent->button == 3)
631        priv->contextMenuEvent.set(gdk_event_copy(reinterpret_cast<GdkEvent*>(buttonEvent)));
632    priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(buttonEvent),
633                                                     priv->clickCounter.clickCountForGdkButtonEvent(widget, buttonEvent)));
634    return TRUE;
635}
636
637static gboolean webkitWebViewBaseButtonReleaseEvent(GtkWidget* widget, GdkEventButton* event)
638{
639    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
640    WebKitWebViewBasePrivate* priv = webViewBase->priv;
641
642    if (priv->authenticationDialog)
643        return TRUE;
644
645    gtk_widget_grab_focus(widget);
646    priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(event), 0 /* currentClickCount */));
647
648    return TRUE;
649}
650
651static gboolean webkitWebViewBaseScrollEvent(GtkWidget* widget, GdkEventScroll* event)
652{
653    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
654    WebKitWebViewBasePrivate* priv = webViewBase->priv;
655
656    if (priv->authenticationDialog)
657        return TRUE;
658
659    priv->pageProxy->handleWheelEvent(NativeWebWheelEvent(reinterpret_cast<GdkEvent*>(event)));
660
661    return TRUE;
662}
663
664static gboolean webkitWebViewBaseMotionNotifyEvent(GtkWidget* widget, GdkEventMotion* event)
665{
666    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
667    WebKitWebViewBasePrivate* priv = webViewBase->priv;
668
669    if (priv->authenticationDialog)
670        return TRUE;
671
672    priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(event), 0 /* currentClickCount */));
673
674    return TRUE;
675}
676
677static gboolean webkitWebViewBaseQueryTooltip(GtkWidget* widget, gint x, gint y, gboolean keyboardMode, GtkTooltip* tooltip)
678{
679    WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
680
681    if (keyboardMode) {
682        // TODO: https://bugs.webkit.org/show_bug.cgi?id=61732.
683        notImplemented();
684        return FALSE;
685    }
686
687    if (priv->tooltipText.length() <= 0)
688        return FALSE;
689
690    if (!priv->tooltipArea.isEmpty()) {
691        GdkRectangle area = priv->tooltipArea;
692        gtk_tooltip_set_tip_area(tooltip, &area);
693    } else
694        gtk_tooltip_set_tip_area(tooltip, 0);
695    gtk_tooltip_set_text(tooltip, priv->tooltipText.data());
696
697    return TRUE;
698}
699
700static void webkitWebViewBaseDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selectionData, guint info, guint time)
701{
702    WEBKIT_WEB_VIEW_BASE(widget)->priv->dragAndDropHelper.handleGetDragData(context, selectionData, info);
703}
704
705static void webkitWebViewBaseDragEnd(GtkWidget* widget, GdkDragContext* context)
706{
707    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
708    if (!webViewBase->priv->dragAndDropHelper.handleDragEnd(context))
709        return;
710
711    GdkDevice* device = gdk_drag_context_get_device(context);
712    int x = 0, y = 0;
713    gdk_device_get_window_at_position(device, &x, &y);
714    int xRoot = 0, yRoot = 0;
715    gdk_device_get_position(device, 0, &xRoot, &yRoot);
716    webViewBase->priv->pageProxy->dragEnded(IntPoint(x, y), IntPoint(xRoot, yRoot),
717                                            gdkDragActionToDragOperation(gdk_drag_context_get_selected_action(context)));
718}
719
720static void webkitWebViewBaseDragDataReceived(GtkWidget* widget, GdkDragContext* context, gint x, gint y, GtkSelectionData* selectionData, guint info, guint time)
721{
722    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
723    IntPoint position;
724    DataObjectGtk* dataObject = webViewBase->priv->dragAndDropHelper.handleDragDataReceived(context, selectionData, info, position);
725    if (!dataObject)
726        return;
727
728    DragData dragData(dataObject, position, convertWidgetPointToScreenPoint(widget, position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context)));
729    webViewBase->priv->pageProxy->resetDragOperation();
730    webViewBase->priv->pageProxy->dragEntered(&dragData);
731    DragOperation operation = webViewBase->priv->pageProxy->dragSession().operation;
732    gdk_drag_status(context, dragOperationToSingleGdkDragAction(operation), time);
733}
734
735static AtkObject* webkitWebViewBaseGetAccessible(GtkWidget* widget)
736{
737    // If the socket has already been created and embedded a plug ID, return it.
738    WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
739    if (priv->accessible && atk_socket_is_occupied(ATK_SOCKET(priv->accessible.get())))
740        return priv->accessible.get();
741
742    // Create the accessible object and associate it to the widget.
743    if (!priv->accessible) {
744        priv->accessible = adoptGRef(ATK_OBJECT(webkitWebViewBaseAccessibleNew(widget)));
745
746        // Set the parent not to break bottom-up navigation.
747        GtkWidget* parentWidget = gtk_widget_get_parent(widget);
748        AtkObject* axParent = parentWidget ? gtk_widget_get_accessible(parentWidget) : 0;
749        if (axParent)
750            atk_object_set_parent(priv->accessible.get(), axParent);
751    }
752
753    // Try to embed the plug in the socket, if posssible.
754    String plugID = priv->pageProxy->accessibilityPlugID();
755    if (plugID.isNull())
756        return priv->accessible.get();
757
758    atk_socket_embed(ATK_SOCKET(priv->accessible.get()), const_cast<gchar*>(plugID.utf8().data()));
759
760    return priv->accessible.get();
761}
762
763static gboolean webkitWebViewBaseDragMotion(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
764{
765    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
766    IntPoint position(x, y);
767    DataObjectGtk* dataObject = webViewBase->priv->dragAndDropHelper.handleDragMotion(context, position, time);
768    if (!dataObject)
769        return TRUE;
770
771    DragData dragData(dataObject, position, convertWidgetPointToScreenPoint(widget, position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context)));
772    webViewBase->priv->pageProxy->dragUpdated(&dragData);
773    DragOperation operation = webViewBase->priv->pageProxy->dragSession().operation;
774    gdk_drag_status(context, dragOperationToSingleGdkDragAction(operation), time);
775    return TRUE;
776}
777
778static void dragExitedCallback(GtkWidget* widget, DragData* dragData, bool dropHappened)
779{
780    // Don't call dragExited if we have just received a drag-drop signal. This
781    // happens in the case of a successful drop onto the view.
782    if (dropHappened)
783        return;
784
785    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
786    webViewBase->priv->pageProxy->dragExited(dragData);
787    webViewBase->priv->pageProxy->resetDragOperation();
788}
789
790static void webkitWebViewBaseDragLeave(GtkWidget* widget, GdkDragContext* context, guint time)
791{
792    WEBKIT_WEB_VIEW_BASE(widget)->priv->dragAndDropHelper.handleDragLeave(context, dragExitedCallback);
793}
794
795static gboolean webkitWebViewBaseDragDrop(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
796{
797    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
798    DataObjectGtk* dataObject = webViewBase->priv->dragAndDropHelper.handleDragDrop(context);
799    if (!dataObject)
800        return FALSE;
801
802    IntPoint position(x, y);
803    DragData dragData(dataObject, position, convertWidgetPointToScreenPoint(widget, position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context)));
804    SandboxExtension::Handle handle;
805    SandboxExtension::HandleArray sandboxExtensionForUpload;
806    webViewBase->priv->pageProxy->performDrag(&dragData, String(), handle, sandboxExtensionForUpload);
807    gtk_drag_finish(context, TRUE, FALSE, time);
808    return TRUE;
809}
810
811static void webkitWebViewBaseParentSet(GtkWidget* widget, GtkWidget* oldParent)
812{
813    if (!gtk_widget_get_parent(widget))
814        webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), 0);
815}
816
817static gboolean webkitWebViewBaseFocus(GtkWidget* widget, GtkDirectionType direction)
818{
819    // If the authentication dialog is active, we need to forward focus events there. This
820    // ensures that you can tab between elements in the box.
821    WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
822    if (priv->authenticationDialog) {
823        gboolean returnValue;
824        g_signal_emit_by_name(priv->authenticationDialog, "focus", direction, &returnValue);
825        return returnValue;
826    }
827
828    return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus(widget, direction);
829}
830
831static void webkitWebViewBaseDestroy(GtkWidget* widget)
832{
833    WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
834    if (priv->authenticationDialog)
835        gtk_widget_destroy(priv->authenticationDialog);
836
837    GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->destroy(widget);
838}
839
840static void webkit_web_view_base_class_init(WebKitWebViewBaseClass* webkitWebViewBaseClass)
841{
842    GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(webkitWebViewBaseClass);
843    widgetClass->realize = webkitWebViewBaseRealize;
844    widgetClass->draw = webkitWebViewBaseDraw;
845    widgetClass->size_allocate = webkitWebViewBaseSizeAllocate;
846    widgetClass->map = webkitWebViewBaseMap;
847    widgetClass->unmap = webkitWebViewBaseUnmap;
848    widgetClass->focus = webkitWebViewBaseFocus;
849    widgetClass->focus_in_event = webkitWebViewBaseFocusInEvent;
850    widgetClass->focus_out_event = webkitWebViewBaseFocusOutEvent;
851    widgetClass->key_press_event = webkitWebViewBaseKeyPressEvent;
852    widgetClass->key_release_event = webkitWebViewBaseKeyReleaseEvent;
853    widgetClass->button_press_event = webkitWebViewBaseButtonPressEvent;
854    widgetClass->button_release_event = webkitWebViewBaseButtonReleaseEvent;
855    widgetClass->scroll_event = webkitWebViewBaseScrollEvent;
856    widgetClass->motion_notify_event = webkitWebViewBaseMotionNotifyEvent;
857    widgetClass->query_tooltip = webkitWebViewBaseQueryTooltip;
858    widgetClass->drag_end = webkitWebViewBaseDragEnd;
859    widgetClass->drag_data_get = webkitWebViewBaseDragDataGet;
860    widgetClass->drag_motion = webkitWebViewBaseDragMotion;
861    widgetClass->drag_leave = webkitWebViewBaseDragLeave;
862    widgetClass->drag_drop = webkitWebViewBaseDragDrop;
863    widgetClass->drag_data_received = webkitWebViewBaseDragDataReceived;
864    widgetClass->get_accessible = webkitWebViewBaseGetAccessible;
865    widgetClass->parent_set = webkitWebViewBaseParentSet;
866    widgetClass->destroy = webkitWebViewBaseDestroy;
867
868    GObjectClass* gobjectClass = G_OBJECT_CLASS(webkitWebViewBaseClass);
869    gobjectClass->constructed = webkitWebViewBaseConstructed;
870    gobjectClass->dispose = webkitWebViewBaseDispose;
871
872    GtkContainerClass* containerClass = GTK_CONTAINER_CLASS(webkitWebViewBaseClass);
873    containerClass->add = webkitWebViewBaseContainerAdd;
874    containerClass->remove = webkitWebViewBaseContainerRemove;
875    containerClass->forall = webkitWebViewBaseContainerForall;
876}
877
878WebKitWebViewBase* webkitWebViewBaseCreate(WebContext* context, WebPageGroup* pageGroup)
879{
880    WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(g_object_new(WEBKIT_TYPE_WEB_VIEW_BASE, NULL));
881    webkitWebViewBaseCreateWebPage(webkitWebViewBase, context, pageGroup);
882    return webkitWebViewBase;
883}
884
885GtkIMContext* webkitWebViewBaseGetIMContext(WebKitWebViewBase* webkitWebViewBase)
886{
887    return webkitWebViewBase->priv->inputMethodFilter.context();
888}
889
890WebPageProxy* webkitWebViewBaseGetPage(WebKitWebViewBase* webkitWebViewBase)
891{
892    return webkitWebViewBase->priv->pageProxy.get();
893}
894
895void webkitWebViewBaseCreateWebPage(WebKitWebViewBase* webkitWebViewBase, WebContext* context, WebPageGroup* pageGroup)
896{
897    WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
898
899    priv->pageProxy = context->createWebPage(priv->pageClient.get(), pageGroup);
900    priv->pageProxy->initializeWebPage();
901
902#if ENABLE(FULLSCREEN_API)
903    priv->pageProxy->fullScreenManager()->setWebView(webkitWebViewBase);
904#endif
905
906#if USE(TEXTURE_MAPPER_GL)
907    if (priv->redirectedWindow)
908        priv->pageProxy->setAcceleratedCompositingWindowId(priv->redirectedWindow->windowId());
909#endif
910
911    // This must happen here instead of the instance initializer, because the input method
912    // filter must have access to the page.
913    priv->inputMethodFilter.setWebView(webkitWebViewBase);
914}
915
916void webkitWebViewBaseSetTooltipText(WebKitWebViewBase* webViewBase, const char* tooltip)
917{
918    WebKitWebViewBasePrivate* priv = webViewBase->priv;
919    if (tooltip && tooltip[0] != '\0') {
920        priv->tooltipText = tooltip;
921        gtk_widget_set_has_tooltip(GTK_WIDGET(webViewBase), TRUE);
922    } else {
923        priv->tooltipText = "";
924        gtk_widget_set_has_tooltip(GTK_WIDGET(webViewBase), FALSE);
925    }
926
927    gtk_widget_trigger_tooltip_query(GTK_WIDGET(webViewBase));
928}
929
930void webkitWebViewBaseSetTooltipArea(WebKitWebViewBase* webViewBase, const IntRect& tooltipArea)
931{
932    webViewBase->priv->tooltipArea = tooltipArea;
933}
934
935void webkitWebViewBaseStartDrag(WebKitWebViewBase* webViewBase, const DragData& dragData, PassRefPtr<ShareableBitmap> dragImage)
936{
937    WebKitWebViewBasePrivate* priv = webViewBase->priv;
938
939    RefPtr<DataObjectGtk> dataObject = adoptRef(dragData.platformData());
940    GRefPtr<GtkTargetList> targetList = adoptGRef(PasteboardHelper::defaultPasteboardHelper()->targetListForDataObject(dataObject.get()));
941    GOwnPtr<GdkEvent> currentEvent(gtk_get_current_event());
942    GdkDragContext* context = gtk_drag_begin(GTK_WIDGET(webViewBase),
943                                             targetList.get(),
944                                             dragOperationToGdkDragActions(dragData.draggingSourceOperationMask()),
945                                             1, /* button */
946                                             currentEvent.get());
947    priv->dragAndDropHelper.startedDrag(context, dataObject.get());
948
949
950    // A drag starting should prevent a double-click from happening. This might
951    // happen if a drag is followed very quickly by another click (like in the DRT).
952    priv->clickCounter.reset();
953
954    if (dragImage) {
955        RefPtr<cairo_surface_t> image(dragImage->createCairoSurface());
956        priv->dragIcon.setImage(image.get());
957        priv->dragIcon.useForDrag(context);
958    } else
959        gtk_drag_set_icon_default(context);
960}
961
962void webkitWebViewBaseForwardNextKeyEvent(WebKitWebViewBase* webkitWebViewBase)
963{
964    webkitWebViewBase->priv->shouldForwardNextKeyEvent = TRUE;
965}
966
967void webkitWebViewBaseEnterFullScreen(WebKitWebViewBase* webkitWebViewBase)
968{
969#if ENABLE(FULLSCREEN_API)
970    WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
971    if (priv->fullScreenModeActive)
972        return;
973
974    if (!priv->fullScreenClient.willEnterFullScreen())
975        return;
976
977    WebFullScreenManagerProxy* fullScreenManagerProxy = priv->pageProxy->fullScreenManager();
978    fullScreenManagerProxy->willEnterFullScreen();
979
980    GtkWidget* topLevelWindow = gtk_widget_get_toplevel(GTK_WIDGET(webkitWebViewBase));
981    if (gtk_widget_is_toplevel(topLevelWindow))
982        gtk_window_fullscreen(GTK_WINDOW(topLevelWindow));
983    fullScreenManagerProxy->didEnterFullScreen();
984    priv->fullScreenModeActive = true;
985#endif
986}
987
988void webkitWebViewBaseExitFullScreen(WebKitWebViewBase* webkitWebViewBase)
989{
990#if ENABLE(FULLSCREEN_API)
991    WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
992    if (!priv->fullScreenModeActive)
993        return;
994
995    if (!priv->fullScreenClient.willExitFullScreen())
996        return;
997
998    WebFullScreenManagerProxy* fullScreenManagerProxy = priv->pageProxy->fullScreenManager();
999    fullScreenManagerProxy->willExitFullScreen();
1000
1001    GtkWidget* topLevelWindow = gtk_widget_get_toplevel(GTK_WIDGET(webkitWebViewBase));
1002    if (gtk_widget_is_toplevel(topLevelWindow))
1003        gtk_window_unfullscreen(GTK_WINDOW(topLevelWindow));
1004    fullScreenManagerProxy->didExitFullScreen();
1005    priv->fullScreenModeActive = false;
1006#endif
1007}
1008
1009void webkitWebViewBaseInitializeFullScreenClient(WebKitWebViewBase* webkitWebViewBase, const WKFullScreenClientGtk* wkClient)
1010{
1011    webkitWebViewBase->priv->fullScreenClient.initialize(wkClient);
1012}
1013
1014void webkitWebViewBaseSetInspectorViewHeight(WebKitWebViewBase* webkitWebViewBase, unsigned height)
1015{
1016    if (webkitWebViewBase->priv->inspectorViewHeight == height)
1017        return;
1018    webkitWebViewBase->priv->inspectorViewHeight = height;
1019    if (webkitWebViewBase->priv->inspectorView)
1020        gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase));
1021}
1022
1023void webkitWebViewBaseSetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase, WebContextMenuProxyGtk* contextMenuProxy)
1024{
1025    webkitWebViewBase->priv->activeContextMenuProxy = contextMenuProxy;
1026}
1027
1028WebContextMenuProxyGtk* webkitWebViewBaseGetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase)
1029{
1030    return webkitWebViewBase->priv->activeContextMenuProxy;
1031}
1032
1033GdkEvent* webkitWebViewBaseTakeContextMenuEvent(WebKitWebViewBase* webkitWebViewBase)
1034{
1035    return webkitWebViewBase->priv->contextMenuEvent.release();
1036}
1037
1038#if USE(TEXTURE_MAPPER_GL)
1039void redirectedWindowDamagedCallback(void* data)
1040{
1041    gtk_widget_queue_draw(GTK_WIDGET(data));
1042}
1043#endif
1044
1045void webkitWebViewBaseSetFocus(WebKitWebViewBase* webViewBase, bool focused)
1046{
1047    WebKitWebViewBasePrivate* priv = webViewBase->priv;
1048    if (priv->isFocused == focused)
1049        return;
1050
1051    unsigned viewStateFlags = WebPageProxy::ViewIsFocused;
1052    priv->isFocused = focused;
1053
1054    // If the view has received the focus and the window is not active
1055    // mark the current window as active now. This can happen if the
1056    // toplevel window is a GTK_WINDOW_POPUP and the focus has been
1057    // set programatically like WebKitTestRunner does, because POPUP
1058    // can't be focused.
1059    if (priv->isFocused && !priv->isInWindowActive) {
1060        priv->isInWindowActive = true;
1061        viewStateFlags |= WebPageProxy::ViewWindowIsActive;
1062    }
1063    priv->pageProxy->viewStateDidChange(viewStateFlags);
1064}
1065
1066bool webkitWebViewBaseIsInWindowActive(WebKitWebViewBase* webViewBase)
1067{
1068    return webViewBase->priv->isInWindowActive;
1069}
1070
1071bool webkitWebViewBaseIsFocused(WebKitWebViewBase* webViewBase)
1072{
1073    return webViewBase->priv->isFocused;
1074}
1075
1076bool webkitWebViewBaseIsVisible(WebKitWebViewBase* webViewBase)
1077{
1078    return webViewBase->priv->isVisible;
1079}
1080
1081bool webkitWebViewBaseIsInWindow(WebKitWebViewBase* webViewBase)
1082{
1083    return webViewBase->priv->toplevelOnScreenWindow;
1084}
1085
1086void webkitWebViewBaseSetDownloadRequestHandler(WebKitWebViewBase* webViewBase, WebKitWebViewBaseDownloadRequestHandler downloadHandler)
1087{
1088    webViewBase->priv->downloadHandler = downloadHandler;
1089}
1090
1091void webkitWebViewBaseHandleDownloadRequest(WebKitWebViewBase* webViewBase, DownloadProxy* download)
1092{
1093    if (webViewBase->priv->downloadHandler)
1094        webViewBase->priv->downloadHandler(webViewBase, download);
1095}
1096
1097void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase* webkitWebViewBase, bool enabled)
1098{
1099    webkitWebViewBase->priv->inputMethodFilter.setEnabled(enabled);
1100}
1101
1102void webkitWebViewBaseUpdateTextInputState(WebKitWebViewBase* webkitWebViewBase)
1103{
1104    webkitWebViewBase->priv->inputMethodFilter.setCursorRect(webkitWebViewBase->priv->pageProxy->editorState().cursorRect);
1105}
1106