Home | History | Annotate | Download | only in renderer_host
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/renderer_host/render_widget_host_view_gtk.h"
      6 
      7 #include <cairo/cairo.h>
      8 #include <gdk/gdk.h>
      9 #include <gdk/gdkkeysyms.h>
     10 #include <gdk/gdkx.h>
     11 #include <gtk/gtk.h>
     12 
     13 #include <algorithm>
     14 #include <string>
     15 
     16 #include "base/bind_helpers.h"
     17 #include "base/command_line.h"
     18 #include "base/debug/trace_event.h"
     19 #include "base/logging.h"
     20 #include "base/message_loop/message_loop.h"
     21 #include "base/metrics/histogram.h"
     22 #include "base/strings/string_number_conversions.h"
     23 #include "base/strings/utf_offset_string_conversions.h"
     24 #include "base/strings/utf_string_conversions.h"
     25 #include "base/time/time.h"
     26 #include "content/browser/accessibility/browser_accessibility_gtk.h"
     27 #include "content/browser/accessibility/browser_accessibility_manager_gtk.h"
     28 #include "content/browser/renderer_host/backing_store_gtk.h"
     29 #include "content/browser/renderer_host/gtk_im_context_wrapper.h"
     30 #include "content/browser/renderer_host/gtk_key_bindings_handler.h"
     31 #include "content/browser/renderer_host/gtk_window_utils.h"
     32 #include "content/browser/renderer_host/input/web_input_event_builders_gtk.h"
     33 #include "content/browser/renderer_host/render_view_host_delegate.h"
     34 #include "content/browser/renderer_host/render_view_host_impl.h"
     35 #include "content/common/gpu/gpu_messages.h"
     36 #include "content/common/input_messages.h"
     37 #include "content/common/view_messages.h"
     38 #include "content/common/webplugin_geometry.h"
     39 #include "content/public/browser/native_web_keyboard_event.h"
     40 #include "content/public/common/content_switches.h"
     41 #include "skia/ext/platform_canvas.h"
     42 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
     43 #include "third_party/WebKit/public/web/WebInputEvent.h"
     44 #include "ui/base/clipboard/scoped_clipboard_writer.h"
     45 #include "ui/base/x/active_window_watcher_x.h"
     46 #include "ui/base/x/x11_util.h"
     47 #include "ui/gfx/gtk_compat.h"
     48 #include "ui/gfx/gtk_native_view_id_manager.h"
     49 #include "ui/gfx/gtk_preserve_window.h"
     50 #include "ui/gfx/text_elider.h"
     51 #include "webkit/common/cursors/webcursor_gtk_data.h"
     52 
     53 using blink::WebMouseWheelEvent;
     54 using blink::WebScreenInfo;
     55 
     56 namespace content {
     57 namespace {
     58 
     59 // Paint rects on Linux are bounded by the maximum size of a shared memory
     60 // region. By default that's 32MB, but many distros increase it significantly
     61 // (i.e. to 256MB).
     62 //
     63 // We fetch the maximum value from /proc/sys/kernel/shmmax at runtime and, if
     64 // we exceed that, then we limit the height of the paint rect in the renderer.
     65 //
     66 // These constants are here to ensure that, in the event that we exceed it, we
     67 // end up with something a little more square. Previously we had 4000x4000, but
     68 // people's monitor setups are actually exceeding that these days.
     69 const int kMaxWindowWidth = 10000;
     70 const int kMaxWindowHeight = 10000;
     71 
     72 const GdkColor kBGColor =
     73 #if defined(NDEBUG)
     74     { 0, 0xff * 257, 0xff * 257, 0xff * 257 };
     75 #else
     76     { 0, 0x00 * 257, 0xff * 257, 0x00 * 257 };
     77 #endif
     78 
     79 // Returns the spinning cursor used for loading state.
     80 GdkCursor* GetMozSpinningCursor() {
     81   static GdkCursor* moz_spinning_cursor = NULL;
     82   if (!moz_spinning_cursor) {
     83     const GdkColor fg = { 0, 0, 0, 0 };
     84     const GdkColor bg = { 65535, 65535, 65535, 65535 };
     85     GdkPixmap* source = gdk_bitmap_create_from_data(
     86         NULL, reinterpret_cast<const gchar*>(moz_spinning_bits), 32, 32);
     87     GdkPixmap* mask = gdk_bitmap_create_from_data(
     88         NULL, reinterpret_cast<const gchar*>(moz_spinning_mask_bits), 32, 32);
     89     moz_spinning_cursor =
     90         gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, 2, 2);
     91     g_object_unref(source);
     92     g_object_unref(mask);
     93   }
     94   return moz_spinning_cursor;
     95 }
     96 
     97 bool MovedToPoint(const blink::WebMouseEvent& mouse_event,
     98                    const gfx::Point& center) {
     99   return mouse_event.globalX == center.x() &&
    100          mouse_event.globalY == center.y();
    101 }
    102 
    103 }  // namespace
    104 
    105 // This class is a simple convenience wrapper for Gtk functions. It has only
    106 // static methods.
    107 class RenderWidgetHostViewGtkWidget {
    108  public:
    109   static AtkObject* GetAccessible(void* userdata) {
    110     return (static_cast<RenderWidgetHostViewGtk*>(userdata))->
    111         GetAccessible();
    112   }
    113 
    114   static GtkWidget* CreateNewWidget(RenderWidgetHostViewGtk* host_view) {
    115     GtkWidget* widget = gtk_preserve_window_new();
    116     gtk_widget_set_name(widget, "chrome-render-widget-host-view");
    117     // We manually double-buffer in Paint() because Paint() may or may not be
    118     // called in repsonse to an "expose-event" signal.
    119     gtk_widget_set_double_buffered(widget, FALSE);
    120     gtk_widget_set_redraw_on_allocate(widget, FALSE);
    121     gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &kBGColor);
    122     // Allow the browser window to be resized freely.
    123     gtk_widget_set_size_request(widget, 0, 0);
    124 
    125     gtk_widget_add_events(widget, GDK_EXPOSURE_MASK |
    126                                   GDK_STRUCTURE_MASK |
    127                                   GDK_POINTER_MOTION_MASK |
    128                                   GDK_BUTTON_PRESS_MASK |
    129                                   GDK_BUTTON_RELEASE_MASK |
    130                                   GDK_KEY_PRESS_MASK |
    131                                   GDK_KEY_RELEASE_MASK |
    132                                   GDK_FOCUS_CHANGE_MASK |
    133                                   GDK_ENTER_NOTIFY_MASK |
    134                                   GDK_LEAVE_NOTIFY_MASK);
    135     gtk_widget_set_can_focus(widget, TRUE);
    136 
    137     g_signal_connect(widget, "expose-event",
    138                      G_CALLBACK(OnExposeEvent), host_view);
    139     g_signal_connect(widget, "realize",
    140                      G_CALLBACK(OnRealize), host_view);
    141     g_signal_connect(widget, "configure-event",
    142                      G_CALLBACK(OnConfigureEvent), host_view);
    143     g_signal_connect(widget, "size-allocate",
    144                      G_CALLBACK(OnSizeAllocate), host_view);
    145     g_signal_connect(widget, "key-press-event",
    146                      G_CALLBACK(OnKeyPressReleaseEvent), host_view);
    147     g_signal_connect(widget, "key-release-event",
    148                      G_CALLBACK(OnKeyPressReleaseEvent), host_view);
    149     g_signal_connect(widget, "focus-in-event",
    150                      G_CALLBACK(OnFocusIn), host_view);
    151     g_signal_connect(widget, "focus-out-event",
    152                      G_CALLBACK(OnFocusOut), host_view);
    153     g_signal_connect(widget, "grab-notify",
    154                      G_CALLBACK(OnGrabNotify), host_view);
    155     g_signal_connect(widget, "button-press-event",
    156                      G_CALLBACK(OnButtonPressReleaseEvent), host_view);
    157     g_signal_connect(widget, "button-release-event",
    158                      G_CALLBACK(OnButtonPressReleaseEvent), host_view);
    159     g_signal_connect(widget, "motion-notify-event",
    160                      G_CALLBACK(OnMouseMoveEvent), host_view);
    161     g_signal_connect(widget, "enter-notify-event",
    162                      G_CALLBACK(OnCrossingEvent), host_view);
    163     g_signal_connect(widget, "leave-notify-event",
    164                      G_CALLBACK(OnCrossingEvent), host_view);
    165     g_signal_connect(widget, "client-event",
    166                      G_CALLBACK(OnClientEvent), host_view);
    167 
    168 
    169     // Connect after so that we are called after the handler installed by the
    170     // WebContentsView which handles zoom events.
    171     g_signal_connect_after(widget, "scroll-event",
    172                            G_CALLBACK(OnMouseScrollEvent), host_view);
    173 
    174     // Route calls to get_accessible to the view.
    175     gtk_preserve_window_set_accessible_factory(
    176         GTK_PRESERVE_WINDOW(widget), GetAccessible, host_view);
    177 
    178     return widget;
    179   }
    180 
    181  private:
    182   static gboolean OnExposeEvent(GtkWidget* widget,
    183                                 GdkEventExpose* expose,
    184                                 RenderWidgetHostViewGtk* host_view) {
    185     if (host_view->host_->is_hidden())
    186       return FALSE;
    187     const gfx::Rect damage_rect(expose->area);
    188     host_view->Paint(damage_rect);
    189     return FALSE;
    190   }
    191 
    192   static gboolean OnRealize(GtkWidget* widget,
    193                             RenderWidgetHostViewGtk* host_view) {
    194     // Use GtkSignalRegistrar to register events on a widget we don't
    195     // control the lifetime of, auto disconnecting at our end of our life.
    196     host_view->signals_.Connect(gtk_widget_get_toplevel(widget),
    197                                 "configure-event",
    198                                 G_CALLBACK(OnConfigureEvent), host_view);
    199     return FALSE;
    200   }
    201 
    202   static gboolean OnConfigureEvent(GtkWidget* widget,
    203                                    GdkEventConfigure* event,
    204                                    RenderWidgetHostViewGtk* host_view) {
    205     host_view->MarkCachedWidgetCenterStale();
    206     host_view->UpdateScreenInfo(host_view->GetNativeView());
    207     return FALSE;
    208   }
    209 
    210   static gboolean OnSizeAllocate(GtkWidget* widget,
    211                                  GdkRectangle* allocation,
    212                                  RenderWidgetHostViewGtk* host_view) {
    213     if (!host_view->IsPopup() && !host_view->is_fullscreen_)
    214       host_view->SetSize(gfx::Size(allocation->width, allocation->height));
    215     return FALSE;
    216   }
    217 
    218   static gboolean OnKeyPressReleaseEvent(GtkWidget* widget,
    219                                          GdkEventKey* event,
    220                                          RenderWidgetHostViewGtk* host_view) {
    221     TRACE_EVENT0("browser",
    222                  "RenderWidgetHostViewGtkWidget::OnKeyPressReleaseEvent");
    223     // Force popups or fullscreen windows to close on Escape so they won't keep
    224     // the keyboard grabbed or be stuck onscreen if the renderer is hanging.
    225     bool should_close_on_escape =
    226         (host_view->IsPopup() && host_view->NeedsInputGrab()) ||
    227         host_view->is_fullscreen_;
    228     if (should_close_on_escape && GDK_Escape == event->keyval) {
    229       host_view->host_->Shutdown();
    230     } else {
    231       // Send key event to input method.
    232       host_view->im_context_->ProcessKeyEvent(event);
    233     }
    234 
    235     // We return TRUE because we did handle the event. If it turns out webkit
    236     // can't handle the event, we'll deal with it in
    237     // RenderView::UnhandledKeyboardEvent().
    238     return TRUE;
    239   }
    240 
    241   static gboolean OnFocusIn(GtkWidget* widget,
    242                             GdkEventFocus* focus,
    243                             RenderWidgetHostViewGtk* host_view) {
    244     host_view->ShowCurrentCursor();
    245     RenderWidgetHostImpl* host =
    246         RenderWidgetHostImpl::From(host_view->GetRenderWidgetHost());
    247     host->GotFocus();
    248     host->SetActive(true);
    249 
    250     // The only way to enable a GtkIMContext object is to call its focus in
    251     // handler.
    252     host_view->im_context_->OnFocusIn();
    253 
    254     return TRUE;
    255   }
    256 
    257   static gboolean OnFocusOut(GtkWidget* widget,
    258                              GdkEventFocus* focus,
    259                              RenderWidgetHostViewGtk* host_view) {
    260     // Whenever we lose focus, set the cursor back to that of our parent window,
    261     // which should be the default arrow.
    262     gdk_window_set_cursor(gtk_widget_get_window(widget), NULL);
    263     // If we are showing a context menu, maintain the illusion that webkit has
    264     // focus.
    265     if (!host_view->IsShowingContextMenu()) {
    266       RenderWidgetHostImpl* host =
    267           RenderWidgetHostImpl::From(host_view->GetRenderWidgetHost());
    268       host->SetActive(false);
    269       host->Blur();
    270     }
    271 
    272     // Prevents us from stealing input context focus in OnGrabNotify() handler.
    273     host_view->was_imcontext_focused_before_grab_ = false;
    274 
    275     // Disable the GtkIMContext object.
    276     host_view->im_context_->OnFocusOut();
    277 
    278     host_view->set_last_mouse_down(NULL);
    279 
    280     return TRUE;
    281   }
    282 
    283   // Called when we are shadowed or unshadowed by a keyboard grab (which will
    284   // occur for activatable popups, such as dropdown menus). Popup windows do not
    285   // take focus, so we never get a focus out or focus in event when they are
    286   // shown, and must rely on this signal instead.
    287   static void OnGrabNotify(GtkWidget* widget, gboolean was_grabbed,
    288                            RenderWidgetHostViewGtk* host_view) {
    289     if (was_grabbed) {
    290       if (host_view->was_imcontext_focused_before_grab_)
    291         host_view->im_context_->OnFocusIn();
    292     } else {
    293       host_view->was_imcontext_focused_before_grab_ =
    294           host_view->im_context_->is_focused();
    295       if (host_view->was_imcontext_focused_before_grab_) {
    296         gdk_window_set_cursor(gtk_widget_get_window(widget), NULL);
    297         host_view->im_context_->OnFocusOut();
    298       }
    299     }
    300   }
    301 
    302   static gboolean OnButtonPressReleaseEvent(
    303       GtkWidget* widget,
    304       GdkEventButton* event,
    305       RenderWidgetHostViewGtk* host_view) {
    306     TRACE_EVENT0("browser",
    307                  "RenderWidgetHostViewGtkWidget::OnButtonPressReleaseEvent");
    308 
    309     if (event->type != GDK_BUTTON_RELEASE)
    310       host_view->set_last_mouse_down(event);
    311 
    312     if (!(event->button == 1 || event->button == 2 || event->button == 3))
    313       return FALSE;  // We do not forward any other buttons to the renderer.
    314     if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS)
    315       return FALSE;
    316 
    317     // If we don't have focus already, this mouse click will focus us.
    318     if (!gtk_widget_is_focus(widget))
    319       host_view->host_->OnPointerEventActivate();
    320 
    321     // Confirm existing composition text on mouse click events, to make sure
    322     // the input caret won't be moved with an ongoing composition session.
    323     if (event->type != GDK_BUTTON_RELEASE)
    324       host_view->im_context_->ConfirmComposition();
    325 
    326     // We want to translate the coordinates of events that do not originate
    327     // from this widget to be relative to the top left of the widget.
    328     GtkWidget* event_widget = gtk_get_event_widget(
    329         reinterpret_cast<GdkEvent*>(event));
    330     if (event_widget != widget) {
    331       int x = 0;
    332       int y = 0;
    333       gtk_widget_get_pointer(widget, &x, &y);
    334       // If the mouse event happens outside our popup, force the popup to
    335       // close.  We do this so a hung renderer doesn't prevent us from
    336       // releasing the x pointer grab.
    337       GtkAllocation allocation;
    338       gtk_widget_get_allocation(widget, &allocation);
    339       bool click_in_popup = x >= 0 && y >= 0 && x < allocation.width &&
    340           y < allocation.height;
    341       // Only Shutdown on mouse downs. Mouse ups can occur outside the render
    342       // view if the user drags for DnD or while using the scrollbar on a select
    343       // dropdown. Don't shutdown if we are not a popup.
    344       if (event->type != GDK_BUTTON_RELEASE && host_view->IsPopup() &&
    345           !host_view->is_popup_first_mouse_release_ && !click_in_popup) {
    346         host_view->host_->Shutdown();
    347         return FALSE;
    348       }
    349       event->x = x;
    350       event->y = y;
    351     }
    352 
    353     // TODO(evanm): why is this necessary here but not in test shell?
    354     // This logic is the same as GtkButton.
    355     if (event->type == GDK_BUTTON_PRESS && !gtk_widget_has_focus(widget))
    356       gtk_widget_grab_focus(widget);
    357 
    358     host_view->is_popup_first_mouse_release_ = false;
    359     RenderWidgetHostImpl* widget_host =
    360         RenderWidgetHostImpl::From(host_view->GetRenderWidgetHost());
    361     if (widget_host)
    362       widget_host->ForwardMouseEvent(WebMouseEventBuilder::Build(event));
    363 
    364     // Although we did handle the mouse event, we need to let other handlers
    365     // run (in particular the one installed by WebContentsViewGtk).
    366     return FALSE;
    367   }
    368 
    369   static gboolean OnMouseMoveEvent(GtkWidget* widget,
    370                                    GdkEventMotion* event,
    371                                    RenderWidgetHostViewGtk* host_view) {
    372     TRACE_EVENT0("browser",
    373                  "RenderWidgetHostViewGtkWidget::OnMouseMoveEvent");
    374     // We want to translate the coordinates of events that do not originate
    375     // from this widget to be relative to the top left of the widget.
    376     GtkWidget* event_widget = gtk_get_event_widget(
    377         reinterpret_cast<GdkEvent*>(event));
    378     if (event_widget != widget) {
    379       int x = 0;
    380       int y = 0;
    381       gtk_widget_get_pointer(widget, &x, &y);
    382       event->x = x;
    383       event->y = y;
    384     }
    385 
    386     host_view->ModifyEventForEdgeDragging(widget, event);
    387 
    388     blink::WebMouseEvent mouse_event = WebMouseEventBuilder::Build(event);
    389 
    390     if (host_view->mouse_locked_) {
    391       gfx::Point center = host_view->GetWidgetCenter();
    392 
    393       bool moved_to_center = MovedToPoint(mouse_event, center);
    394       if (moved_to_center)
    395         host_view->mouse_has_been_warped_to_new_center_ = true;
    396 
    397       host_view->ModifyEventMovementAndCoords(&mouse_event);
    398 
    399       if (!moved_to_center &&
    400           (mouse_event.movementX || mouse_event.movementY)) {
    401         GdkDisplay* display = gtk_widget_get_display(widget);
    402         GdkScreen* screen = gtk_widget_get_screen(widget);
    403         gdk_display_warp_pointer(display, screen, center.x(), center.y());
    404         if (host_view->mouse_has_been_warped_to_new_center_)
    405           RenderWidgetHostImpl::From(
    406               host_view->GetRenderWidgetHost())->ForwardMouseEvent(mouse_event);
    407       }
    408     } else {  // Mouse is not locked.
    409       host_view->ModifyEventMovementAndCoords(&mouse_event);
    410       // Do not send mouse events while the mouse cursor is being warped back
    411       // to the unlocked location.
    412       if (!host_view->mouse_is_being_warped_to_unlocked_position_) {
    413         RenderWidgetHostImpl::From(
    414             host_view->GetRenderWidgetHost())->ForwardMouseEvent(mouse_event);
    415       }
    416     }
    417     return FALSE;
    418   }
    419 
    420   static gboolean OnCrossingEvent(GtkWidget* widget,
    421                                   GdkEventCrossing* event,
    422                                   RenderWidgetHostViewGtk* host_view) {
    423     TRACE_EVENT0("browser",
    424                  "RenderWidgetHostViewGtkWidget::OnCrossingEvent");
    425     const int any_button_mask =
    426         GDK_BUTTON1_MASK |
    427         GDK_BUTTON2_MASK |
    428         GDK_BUTTON3_MASK |
    429         GDK_BUTTON4_MASK |
    430         GDK_BUTTON5_MASK;
    431 
    432     // Only forward crossing events if the mouse button is not down.
    433     // (When the mouse button is down, the proper events are already being
    434     // sent by ButtonPressReleaseEvent and MouseMoveEvent, above, and if we
    435     // additionally send this crossing event with the state indicating the
    436     // button is down, it causes problems with drag and drop in WebKit.)
    437     if (!(event->state & any_button_mask)) {
    438       blink::WebMouseEvent mouse_event = WebMouseEventBuilder::Build(event);
    439       host_view->ModifyEventMovementAndCoords(&mouse_event);
    440       // When crossing out and back into a render view the movement values
    441       // must represent the instantaneous movement of the mouse, not the jump
    442       // from the exit to re-entry point.
    443       mouse_event.movementX = 0;
    444       mouse_event.movementY = 0;
    445       RenderWidgetHostImpl::From(
    446           host_view->GetRenderWidgetHost())->ForwardMouseEvent(mouse_event);
    447     }
    448 
    449     return FALSE;
    450   }
    451 
    452   static gboolean OnClientEvent(GtkWidget* widget,
    453                                 GdkEventClient* event,
    454                                 RenderWidgetHostViewGtk* host_view) {
    455     VLOG(1) << "client event type: " << event->message_type
    456             << " data_format: " << event->data_format
    457             << " data: " << event->data.l;
    458     return TRUE;
    459   }
    460 
    461   // Return the net up / down (or left / right) distance represented by events
    462   // in the  events will be removed from the queue. We only look at the top of
    463   // queue...any other type of event will cause us not to look farther.
    464   // If there is a change to the set of modifier keys or scroll axis
    465   // in the events we will stop looking as well.
    466   static int GetPendingScrollDelta(bool vert, guint current_event_state) {
    467     int num_clicks = 0;
    468     GdkEvent* event;
    469     bool event_coalesced = true;
    470     while ((event = gdk_event_get()) && event_coalesced) {
    471       event_coalesced = false;
    472       if (event->type == GDK_SCROLL) {
    473         GdkEventScroll scroll = event->scroll;
    474         if (scroll.state & GDK_SHIFT_MASK) {
    475           if (scroll.direction == GDK_SCROLL_UP)
    476             scroll.direction = GDK_SCROLL_LEFT;
    477           else if (scroll.direction == GDK_SCROLL_DOWN)
    478             scroll.direction = GDK_SCROLL_RIGHT;
    479         }
    480         if (vert) {
    481           if (scroll.direction == GDK_SCROLL_UP ||
    482               scroll.direction == GDK_SCROLL_DOWN) {
    483             if (scroll.state == current_event_state) {
    484               num_clicks += (scroll.direction == GDK_SCROLL_UP ? 1 : -1);
    485               gdk_event_free(event);
    486               event_coalesced = true;
    487             }
    488           }
    489         } else {
    490           if (scroll.direction == GDK_SCROLL_LEFT ||
    491               scroll.direction == GDK_SCROLL_RIGHT) {
    492             if (scroll.state == current_event_state) {
    493               num_clicks += (scroll.direction == GDK_SCROLL_LEFT ? 1 : -1);
    494               gdk_event_free(event);
    495               event_coalesced = true;
    496             }
    497           }
    498         }
    499       }
    500     }
    501     // If we have an event left we put it back on the queue.
    502     if (event) {
    503       gdk_event_put(event);
    504       gdk_event_free(event);
    505     }
    506     return num_clicks * WebMouseWheelEventBuilder::ScrollbarPixelsPerTick();
    507   }
    508 
    509   static gboolean OnMouseScrollEvent(GtkWidget* widget,
    510                                      GdkEventScroll* event,
    511                                      RenderWidgetHostViewGtk* host_view) {
    512     TRACE_EVENT0("browser",
    513                  "RenderWidgetHostViewGtkWidget::OnMouseScrollEvent");
    514     // If the user is holding shift, translate it into a horizontal scroll. We
    515     // don't care what other modifiers the user may be holding (zooming is
    516     // handled at the WebContentsView level).
    517     if (event->state & GDK_SHIFT_MASK) {
    518       if (event->direction == GDK_SCROLL_UP)
    519         event->direction = GDK_SCROLL_LEFT;
    520       else if (event->direction == GDK_SCROLL_DOWN)
    521         event->direction = GDK_SCROLL_RIGHT;
    522     }
    523 
    524     WebMouseWheelEvent web_event = WebMouseWheelEventBuilder::Build(event);
    525     const float pixelsPerTick =
    526         WebMouseWheelEventBuilder::ScrollbarPixelsPerTick();
    527     // We  peek ahead at the top of the queue to look for additional pending
    528     // scroll events.
    529     if (event->direction == GDK_SCROLL_UP ||
    530         event->direction == GDK_SCROLL_DOWN) {
    531       if (event->direction == GDK_SCROLL_UP)
    532         web_event.deltaY = pixelsPerTick;
    533       else
    534         web_event.deltaY = -pixelsPerTick;
    535       web_event.deltaY += GetPendingScrollDelta(true, event->state);
    536     } else {
    537       if (event->direction == GDK_SCROLL_LEFT)
    538         web_event.deltaX = pixelsPerTick;
    539       else
    540         web_event.deltaX = -pixelsPerTick;
    541       web_event.deltaX += GetPendingScrollDelta(false, event->state);
    542     }
    543     RenderWidgetHostImpl::From(
    544         host_view->GetRenderWidgetHost())->ForwardWheelEvent(web_event);
    545     return FALSE;
    546   }
    547 
    548   DISALLOW_IMPLICIT_CONSTRUCTORS(RenderWidgetHostViewGtkWidget);
    549 };
    550 
    551 RenderWidgetHostViewGtk::RenderWidgetHostViewGtk(RenderWidgetHost* widget_host)
    552     : host_(RenderWidgetHostImpl::From(widget_host)),
    553       about_to_validate_and_paint_(false),
    554       is_loading_(false),
    555       parent_(NULL),
    556       is_popup_first_mouse_release_(true),
    557       was_imcontext_focused_before_grab_(false),
    558       do_x_grab_(false),
    559       is_fullscreen_(false),
    560       made_active_(false),
    561       mouse_is_being_warped_to_unlocked_position_(false),
    562       destroy_handler_id_(0),
    563       dragged_at_horizontal_edge_(0),
    564       dragged_at_vertical_edge_(0),
    565       compositing_surface_(gfx::kNullPluginWindow),
    566       last_mouse_down_(NULL) {
    567   host_->SetView(this);
    568 }
    569 
    570 RenderWidgetHostViewGtk::~RenderWidgetHostViewGtk() {
    571   UnlockMouse();
    572   set_last_mouse_down(NULL);
    573   view_.Destroy();
    574 }
    575 
    576 bool RenderWidgetHostViewGtk::OnMessageReceived(const IPC::Message& message) {
    577   bool handled = true;
    578   IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostViewGtk, message)
    579     IPC_MESSAGE_HANDLER(ViewHostMsg_CreatePluginContainer,
    580                         OnCreatePluginContainer)
    581     IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyPluginContainer,
    582                         OnDestroyPluginContainer)
    583     IPC_MESSAGE_UNHANDLED(handled = false)
    584   IPC_END_MESSAGE_MAP()
    585   return handled;
    586 }
    587 
    588 void RenderWidgetHostViewGtk::InitAsChild(
    589     gfx::NativeView parent_view) {
    590   DoSharedInit();
    591   gtk_widget_show(view_.get());
    592 }
    593 
    594 void RenderWidgetHostViewGtk::InitAsPopup(
    595     RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
    596   // If we aren't a popup, then |window| will be leaked.
    597   DCHECK(IsPopup());
    598 
    599   DoSharedInit();
    600   parent_ = parent_host_view->GetNativeView();
    601   GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_POPUP));
    602   gtk_container_add(GTK_CONTAINER(window), view_.get());
    603   DoPopupOrFullscreenInit(window, pos);
    604 
    605   // Grab all input for the app. If a click lands outside the bounds of the
    606   // popup, WebKit will notice and destroy us. The underlying X window needs to
    607   // be created and mapped by the above code before we can grab the input
    608   // devices.
    609   if (NeedsInputGrab()) {
    610     // If our parent is in a widget hierarchy that ends with a window, add
    611     // ourselves to the same window group to make sure that our GTK grab
    612     // covers it.
    613     GtkWidget* toplevel = gtk_widget_get_toplevel(parent_);
    614     if (toplevel &&
    615         GTK_WIDGET_TOPLEVEL(toplevel) &&
    616         GTK_IS_WINDOW(toplevel)) {
    617       gtk_window_group_add_window(
    618           gtk_window_get_group(GTK_WINDOW(toplevel)), window);
    619     }
    620 
    621     // Install an application-level GTK grab to make sure that we receive all of
    622     // the app's input.
    623     gtk_grab_add(view_.get());
    624 
    625     // We need to install an X grab as well. However if the app already has an X
    626     // grab (as in the case of extension popup), an app grab will suffice.
    627     do_x_grab_ = !gdk_pointer_is_grabbed();
    628     if (do_x_grab_) {
    629       // Install the grab on behalf our parent window if it and all of its
    630       // ancestors are mapped; otherwise, just use ourselves (maybe we're being
    631       // shown on behalf of an inactive tab).
    632       GdkWindow* grab_window = gtk_widget_get_window(parent_);
    633       if (!grab_window || !gdk_window_is_viewable(grab_window))
    634         grab_window = gtk_widget_get_window(view_.get());
    635 
    636       gdk_pointer_grab(
    637           grab_window,
    638           TRUE,  // Only events outside of the window are reported with
    639                  // respect to |parent_->window|.
    640           static_cast<GdkEventMask>(GDK_BUTTON_PRESS_MASK |
    641               GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK),
    642           NULL,
    643           NULL,
    644           GDK_CURRENT_TIME);
    645       // We grab keyboard events too so things like alt+tab are eaten.
    646       gdk_keyboard_grab(grab_window, TRUE, GDK_CURRENT_TIME);
    647     }
    648   }
    649 }
    650 
    651 void RenderWidgetHostViewGtk::InitAsFullscreen(
    652     RenderWidgetHostView* reference_host_view) {
    653   DCHECK(reference_host_view);
    654   DoSharedInit();
    655 
    656   is_fullscreen_ = true;
    657   GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
    658   gtk_window_set_decorated(window, FALSE);
    659   destroy_handler_id_ = g_signal_connect(GTK_WIDGET(window),
    660                                          "destroy",
    661                                          G_CALLBACK(OnDestroyThunk),
    662                                          this);
    663   gtk_container_add(GTK_CONTAINER(window), view_.get());
    664 
    665   // Try to move and resize the window to cover the screen in case the window
    666   // manager doesn't support _NET_WM_STATE_FULLSCREEN.
    667   GdkScreen* screen = gtk_window_get_screen(window);
    668   GdkWindow* ref_gdk_window = gtk_widget_get_window(
    669       reference_host_view->GetNativeView());
    670 
    671   gfx::Rect bounds;
    672   if (ref_gdk_window) {
    673     const int monitor_id = gdk_screen_get_monitor_at_window(screen,
    674                                                             ref_gdk_window);
    675     GdkRectangle monitor_rect;
    676     gdk_screen_get_monitor_geometry(screen, monitor_id, &monitor_rect);
    677     bounds = gfx::Rect(monitor_rect);
    678   } else {
    679     bounds = gfx::Rect(
    680         0, 0, gdk_screen_get_width(screen), gdk_screen_get_height(screen));
    681   }
    682   gtk_window_move(window, bounds.x(), bounds.y());
    683   gtk_window_resize(window, bounds.width(), bounds.height());
    684   gtk_window_fullscreen(window);
    685   DoPopupOrFullscreenInit(window, bounds);
    686 }
    687 
    688 RenderWidgetHost* RenderWidgetHostViewGtk::GetRenderWidgetHost() const {
    689   return host_;
    690 }
    691 
    692 void RenderWidgetHostViewGtk::WasShown() {
    693   if (!host_ || !host_->is_hidden())
    694     return;
    695 
    696   if (web_contents_switch_paint_time_.is_null())
    697     web_contents_switch_paint_time_ = base::TimeTicks::Now();
    698 
    699   host_->WasShown();
    700 }
    701 
    702 void RenderWidgetHostViewGtk::WasHidden() {
    703   if (!host_ || host_->is_hidden())
    704     return;
    705 
    706   // If we have a renderer, then inform it that we are being hidden so it can
    707   // reduce its resource utilization.
    708   host_->WasHidden();
    709 
    710   web_contents_switch_paint_time_ = base::TimeTicks();
    711 }
    712 
    713 void RenderWidgetHostViewGtk::SetSize(const gfx::Size& size) {
    714   int width = std::min(size.width(), kMaxWindowWidth);
    715   int height = std::min(size.height(), kMaxWindowHeight);
    716   if (IsPopup()) {
    717     // We're a popup, honor the size request.
    718     gtk_widget_set_size_request(view_.get(), width, height);
    719   }
    720 
    721   // Update the size of the RWH.
    722   if (requested_size_.width() != width ||
    723       requested_size_.height() != height) {
    724     requested_size_ = gfx::Size(width, height);
    725     host_->SendScreenRects();
    726     host_->WasResized();
    727   }
    728 }
    729 
    730 void RenderWidgetHostViewGtk::SetBounds(const gfx::Rect& rect) {
    731   // This is called when webkit has sent us a Move message.
    732   if (IsPopup()) {
    733     gtk_window_move(GTK_WINDOW(gtk_widget_get_toplevel(view_.get())),
    734                     rect.x(), rect.y());
    735   }
    736 
    737   SetSize(rect.size());
    738 }
    739 
    740 gfx::NativeView RenderWidgetHostViewGtk::GetNativeView() const {
    741   return view_.get();
    742 }
    743 
    744 gfx::NativeViewId RenderWidgetHostViewGtk::GetNativeViewId() const {
    745   return GtkNativeViewManager::GetInstance()->GetIdForWidget(view_.get());
    746 }
    747 
    748 gfx::NativeViewAccessible RenderWidgetHostViewGtk::GetNativeViewAccessible() {
    749   NOTIMPLEMENTED();
    750   return NULL;
    751 }
    752 
    753 void RenderWidgetHostViewGtk::MovePluginWindows(
    754     const gfx::Vector2d& scroll_offset,
    755     const std::vector<WebPluginGeometry>& moves) {
    756   for (size_t i = 0; i < moves.size(); ++i) {
    757     plugin_container_manager_.MovePluginContainer(moves[i]);
    758   }
    759 }
    760 
    761 void RenderWidgetHostViewGtk::Focus() {
    762   gtk_widget_grab_focus(view_.get());
    763 }
    764 
    765 void RenderWidgetHostViewGtk::Blur() {
    766   // TODO(estade): We should be clearing native focus as well, but I know of no
    767   // way to do that without focusing another widget.
    768   host_->Blur();
    769 }
    770 
    771 bool RenderWidgetHostViewGtk::HasFocus() const {
    772   return gtk_widget_has_focus(view_.get());
    773 }
    774 
    775 void RenderWidgetHostViewGtk::ActiveWindowChanged(GdkWindow* window) {
    776   GdkWindow* our_window = gtk_widget_get_parent_window(view_.get());
    777 
    778   if (our_window == window)
    779     made_active_ = true;
    780 
    781   // If the window was previously active, but isn't active anymore, shut it
    782   // down.
    783   if (is_fullscreen_ && our_window != window && made_active_)
    784     host_->Shutdown();
    785 }
    786 
    787 bool RenderWidgetHostViewGtk::Send(IPC::Message* message) {
    788   return host_->Send(message);
    789 }
    790 
    791 bool RenderWidgetHostViewGtk::IsSurfaceAvailableForCopy() const {
    792   return true;
    793 }
    794 
    795 void RenderWidgetHostViewGtk::Show() {
    796   gtk_widget_show(view_.get());
    797   WasShown();
    798 }
    799 
    800 void RenderWidgetHostViewGtk::Hide() {
    801   gtk_widget_hide(view_.get());
    802   WasHidden();
    803 }
    804 
    805 bool RenderWidgetHostViewGtk::IsShowing() {
    806   return gtk_widget_get_visible(view_.get());
    807 }
    808 
    809 gfx::Rect RenderWidgetHostViewGtk::GetViewBounds() const {
    810   GdkWindow* gdk_window = gtk_widget_get_window(view_.get());
    811   if (!gdk_window)
    812     return gfx::Rect(requested_size_);
    813   GdkRectangle window_rect;
    814   gdk_window_get_origin(gdk_window, &window_rect.x, &window_rect.y);
    815   return gfx::Rect(window_rect.x, window_rect.y,
    816                    requested_size_.width(), requested_size_.height());
    817 }
    818 
    819 void RenderWidgetHostViewGtk::UpdateCursor(const WebCursor& cursor) {
    820   // Optimize the common case, where the cursor hasn't changed.
    821   // However, we can switch between different pixmaps, so only on the
    822   // non-pixmap branch.
    823   if (current_cursor_.GetCursorType() != GDK_CURSOR_IS_PIXMAP &&
    824       current_cursor_.GetCursorType() == cursor.GetCursorType()) {
    825     return;
    826   }
    827 
    828   current_cursor_ = cursor;
    829   ShowCurrentCursor();
    830 }
    831 
    832 void RenderWidgetHostViewGtk::SetIsLoading(bool is_loading) {
    833   is_loading_ = is_loading;
    834   // Only call ShowCurrentCursor() when it will actually change the cursor.
    835   if (current_cursor_.GetCursorType() == GDK_LAST_CURSOR)
    836     ShowCurrentCursor();
    837 }
    838 
    839 void RenderWidgetHostViewGtk::TextInputTypeChanged(
    840     ui::TextInputType type,
    841     ui::TextInputMode input_mode,
    842     bool can_compose_inline) {
    843   im_context_->UpdateInputMethodState(type, can_compose_inline);
    844 }
    845 
    846 void RenderWidgetHostViewGtk::ImeCancelComposition() {
    847   im_context_->CancelComposition();
    848 }
    849 
    850 void RenderWidgetHostViewGtk::DidUpdateBackingStore(
    851     const gfx::Rect& scroll_rect,
    852     const gfx::Vector2d& scroll_delta,
    853     const std::vector<gfx::Rect>& copy_rects,
    854     const ui::LatencyInfo& latency_info) {
    855   TRACE_EVENT0("ui::gtk", "RenderWidgetHostViewGtk::DidUpdateBackingStore");
    856   software_latency_info_.MergeWith(latency_info);
    857 
    858   if (host_->is_hidden())
    859     return;
    860 
    861   // TODO(darin): Implement the equivalent of Win32's ScrollWindowEX.  Can that
    862   // be done using XCopyArea?  Perhaps similar to
    863   // BackingStore::ScrollBackingStore?
    864   if (about_to_validate_and_paint_)
    865     invalid_rect_.Union(scroll_rect);
    866   else
    867     Paint(scroll_rect);
    868 
    869   for (size_t i = 0; i < copy_rects.size(); ++i) {
    870     // Avoid double painting.  NOTE: This is only relevant given the call to
    871     // Paint(scroll_rect) above.
    872     gfx::Rect rect = gfx::SubtractRects(copy_rects[i], scroll_rect);
    873     if (rect.IsEmpty())
    874       continue;
    875 
    876     if (about_to_validate_and_paint_)
    877       invalid_rect_.Union(rect);
    878     else
    879       Paint(rect);
    880   }
    881 }
    882 
    883 void RenderWidgetHostViewGtk::RenderProcessGone(base::TerminationStatus status,
    884                                                 int error_code) {
    885   Destroy();
    886   plugin_container_manager_.set_host_widget(NULL);
    887 }
    888 
    889 void RenderWidgetHostViewGtk::Destroy() {
    890   if (compositing_surface_ != gfx::kNullPluginWindow) {
    891     GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
    892     manager->ReleasePermanentXID(compositing_surface_);
    893   }
    894 
    895   if (do_x_grab_) {
    896     // Undo the X grab.
    897     GdkDisplay* display = gtk_widget_get_display(parent_);
    898     gdk_display_pointer_ungrab(display, GDK_CURRENT_TIME);
    899     gdk_display_keyboard_ungrab(display, GDK_CURRENT_TIME);
    900   }
    901 
    902   if (view_.get()) {
    903     // If this is a popup or fullscreen widget, then we need to destroy the
    904     // window that we created to hold it.
    905     if (IsPopup() || is_fullscreen_) {
    906       GtkWidget* window = gtk_widget_get_parent(view_.get());
    907 
    908       ui::ActiveWindowWatcherX::RemoveObserver(this);
    909 
    910       // Disconnect the destroy handler so that we don't try to shutdown twice.
    911       if (is_fullscreen_)
    912         g_signal_handler_disconnect(window, destroy_handler_id_);
    913 
    914       gtk_widget_destroy(window);
    915     }
    916 
    917     // Remove |view_| from all containers now, so nothing else can hold a
    918     // reference to |view_|'s widget except possibly a gtk signal handler if
    919     // this code is currently executing within the context of a gtk signal
    920     // handler.  Note that |view_| is still alive after this call.  It will be
    921     // deallocated in the destructor.
    922     // See http://crbug.com/11847 for details.
    923     gtk_widget_destroy(view_.get());
    924   }
    925 
    926   // The RenderWidgetHost's destruction led here, so don't call it.
    927   host_ = NULL;
    928 
    929   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    930 }
    931 
    932 void RenderWidgetHostViewGtk::SetTooltipText(
    933     const base::string16& tooltip_text) {
    934   // Maximum number of characters we allow in a tooltip.
    935   const int kMaxTooltipLength = 8 << 10;
    936   // Clamp the tooltip length to kMaxTooltipLength so that we don't
    937   // accidentally DOS the user with a mega tooltip (since GTK doesn't do
    938   // this itself).
    939   // I filed https://bugzilla.gnome.org/show_bug.cgi?id=604641 upstream.
    940   const base::string16 clamped_tooltip =
    941       gfx::TruncateString(tooltip_text, kMaxTooltipLength);
    942 
    943   if (clamped_tooltip.empty()) {
    944     gtk_widget_set_has_tooltip(view_.get(), FALSE);
    945   } else {
    946     gtk_widget_set_tooltip_text(view_.get(),
    947                                 UTF16ToUTF8(clamped_tooltip).c_str());
    948   }
    949 }
    950 
    951 void RenderWidgetHostViewGtk::SelectionChanged(const base::string16& text,
    952                                                size_t offset,
    953                                                const gfx::Range& range) {
    954   RenderWidgetHostViewBase::SelectionChanged(text, offset, range);
    955 
    956   if (text.empty() || range.is_empty())
    957     return;
    958   size_t pos = range.GetMin() - offset;
    959   size_t n = range.length();
    960 
    961   DCHECK(pos + n <= text.length()) << "The text can not fully cover range.";
    962   if (pos >= text.length()) {
    963     NOTREACHED() << "The text can not cover range.";
    964     return;
    965   }
    966 
    967   // Set the CLIPBOARD_TYPE SELECTION to the ui::Clipboard.
    968   ui::ScopedClipboardWriter clipboard_writer(
    969       ui::Clipboard::GetForCurrentThread(),
    970       ui::CLIPBOARD_TYPE_SELECTION);
    971   clipboard_writer.WriteText(text.substr(pos, n));
    972 }
    973 
    974 void RenderWidgetHostViewGtk::SelectionBoundsChanged(
    975     const ViewHostMsg_SelectionBounds_Params& params) {
    976   im_context_->UpdateCaretBounds(
    977       gfx::UnionRects(params.anchor_rect, params.focus_rect));
    978 }
    979 
    980 void RenderWidgetHostViewGtk::ScrollOffsetChanged() {
    981 }
    982 
    983 GdkEventButton* RenderWidgetHostViewGtk::GetLastMouseDown() {
    984   return last_mouse_down_;
    985 }
    986 
    987 gfx::NativeView RenderWidgetHostViewGtk::BuildInputMethodsGtkMenu() {
    988   return im_context_->BuildInputMethodsGtkMenu();
    989 }
    990 
    991 void RenderWidgetHostViewGtk::OnDestroy(GtkWidget* widget) {
    992   DCHECK(is_fullscreen_);
    993   host_->Shutdown();
    994 }
    995 
    996 bool RenderWidgetHostViewGtk::NeedsInputGrab() {
    997   return popup_type_ == blink::WebPopupTypeSelect;
    998 }
    999 
   1000 bool RenderWidgetHostViewGtk::IsPopup() const {
   1001   return popup_type_ != blink::WebPopupTypeNone;
   1002 }
   1003 
   1004 void RenderWidgetHostViewGtk::DoSharedInit() {
   1005   view_.Own(RenderWidgetHostViewGtkWidget::CreateNewWidget(this));
   1006   im_context_.reset(new GtkIMContextWrapper(this));
   1007   plugin_container_manager_.set_host_widget(view_.get());
   1008   key_bindings_handler_.reset(new GtkKeyBindingsHandler(view_.get()));
   1009 }
   1010 
   1011 void RenderWidgetHostViewGtk::DoPopupOrFullscreenInit(GtkWindow* window,
   1012                                                       const gfx::Rect& bounds) {
   1013   requested_size_.SetSize(std::min(bounds.width(), kMaxWindowWidth),
   1014                           std::min(bounds.height(), kMaxWindowHeight));
   1015   host_->WasResized();
   1016 
   1017   ui::ActiveWindowWatcherX::AddObserver(this);
   1018 
   1019   // Don't set the size when we're going fullscreen. This can confuse the
   1020   // window manager into thinking we're resizing a fullscreen window and
   1021   // therefore not fullscreen anymore.
   1022   if (!is_fullscreen_) {
   1023     gtk_widget_set_size_request(
   1024         view_.get(), requested_size_.width(), requested_size_.height());
   1025 
   1026     // Don't allow the window to be resized. This also forces the window to
   1027     // shrink down to the size of its child contents.
   1028     gtk_window_set_resizable(window, FALSE);
   1029     gtk_window_set_default_size(window, -1, -1);
   1030     gtk_window_move(window, bounds.x(), bounds.y());
   1031   }
   1032 
   1033   gtk_widget_show_all(GTK_WIDGET(window));
   1034 }
   1035 
   1036 BackingStore* RenderWidgetHostViewGtk::AllocBackingStore(
   1037     const gfx::Size& size) {
   1038   gint depth = gdk_visual_get_depth(gtk_widget_get_visual(view_.get()));
   1039   return new BackingStoreGtk(host_, size,
   1040                              ui::GetVisualFromGtkWidget(view_.get()),
   1041                              depth);
   1042 }
   1043 
   1044 // NOTE: |output| is initialized with the size of |src_subrect|, and |dst_size|
   1045 // is ignored on GTK.
   1046 void RenderWidgetHostViewGtk::CopyFromCompositingSurface(
   1047     const gfx::Rect& src_subrect,
   1048     const gfx::Size& /* dst_size */,
   1049     const base::Callback<void(bool, const SkBitmap&)>& callback) {
   1050   // Grab the snapshot from the renderer as that's the only reliable way to
   1051   // readback from the GPU for this platform right now.
   1052   GetRenderWidgetHost()->GetSnapshotFromRenderer(src_subrect, callback);
   1053 }
   1054 
   1055 void RenderWidgetHostViewGtk::CopyFromCompositingSurfaceToVideoFrame(
   1056       const gfx::Rect& src_subrect,
   1057       const scoped_refptr<media::VideoFrame>& target,
   1058       const base::Callback<void(bool)>& callback) {
   1059   NOTIMPLEMENTED();
   1060   callback.Run(false);
   1061 }
   1062 
   1063 bool RenderWidgetHostViewGtk::CanCopyToVideoFrame() const {
   1064   return false;
   1065 }
   1066 
   1067 void RenderWidgetHostViewGtk::AcceleratedSurfaceInitialized(int host_id,
   1068                                                             int route_id) {
   1069 }
   1070 
   1071 void RenderWidgetHostViewGtk::AcceleratedSurfaceBuffersSwapped(
   1072     const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
   1073     int gpu_host_id) {
   1074   AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
   1075   ack_params.sync_point = 0;
   1076   RenderWidgetHostImpl::AcknowledgeBufferPresent(
   1077       params.route_id, gpu_host_id, ack_params);
   1078   RenderWidgetHostImpl::CompositorFrameDrawn(params.latency_info);
   1079 }
   1080 
   1081 void RenderWidgetHostViewGtk::AcceleratedSurfacePostSubBuffer(
   1082     const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
   1083     int gpu_host_id) {
   1084   AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
   1085   ack_params.sync_point = 0;
   1086   RenderWidgetHostImpl::AcknowledgeBufferPresent(
   1087       params.route_id, gpu_host_id, ack_params);
   1088   RenderWidgetHostImpl::CompositorFrameDrawn(params.latency_info);
   1089 }
   1090 
   1091 void RenderWidgetHostViewGtk::AcceleratedSurfaceSuspend() {
   1092 }
   1093 
   1094 void RenderWidgetHostViewGtk::AcceleratedSurfaceRelease() {
   1095 }
   1096 
   1097 bool RenderWidgetHostViewGtk::HasAcceleratedSurface(
   1098       const gfx::Size& desired_size) {
   1099   // TODO(jbates) Implement this so this view can use GetBackingStore for both
   1100   // software and GPU frames. Defaulting to false just makes GetBackingStore
   1101   // only useable for software frames.
   1102   return false;
   1103 }
   1104 
   1105 void RenderWidgetHostViewGtk::SetBackground(const SkBitmap& background) {
   1106   RenderWidgetHostViewBase::SetBackground(background);
   1107   Send(new ViewMsg_SetBackground(host_->GetRoutingID(), background));
   1108 }
   1109 
   1110 void RenderWidgetHostViewGtk::ModifyEventForEdgeDragging(
   1111     GtkWidget* widget, GdkEventMotion* event) {
   1112   // If the widget is aligned with an edge of the monitor its on and the user
   1113   // attempts to drag past that edge we track the number of times it has
   1114   // occurred, so that we can force the widget to scroll when it otherwise
   1115   // would be unable to, by modifying the (x,y) position in the drag
   1116   // event that we forward on to webkit. If we get a move that's no longer a
   1117   // drag or a drag indicating the user is no longer at that edge we stop
   1118   // altering the drag events.
   1119   int new_dragged_at_horizontal_edge = 0;
   1120   int new_dragged_at_vertical_edge = 0;
   1121   // Used for checking the edges of the monitor. We cache the values to save
   1122   // roundtrips to the X server.
   1123   CR_DEFINE_STATIC_LOCAL(gfx::Size, drag_monitor_size, ());
   1124   if (event->state & GDK_BUTTON1_MASK) {
   1125     if (drag_monitor_size.IsEmpty()) {
   1126       // We can safely cache the monitor size for the duration of a drag.
   1127       GdkScreen* screen = gtk_widget_get_screen(widget);
   1128       int monitor =
   1129           gdk_screen_get_monitor_at_point(screen, event->x_root, event->y_root);
   1130       GdkRectangle geometry;
   1131       gdk_screen_get_monitor_geometry(screen, monitor, &geometry);
   1132       drag_monitor_size.SetSize(geometry.width, geometry.height);
   1133     }
   1134     GtkAllocation allocation;
   1135     gtk_widget_get_allocation(widget, &allocation);
   1136     // Check X and Y independently, as the user could be dragging into a corner.
   1137     if (event->x == 0 && event->x_root == 0) {
   1138       new_dragged_at_horizontal_edge = dragged_at_horizontal_edge_ - 1;
   1139     } else if (allocation.width - 1 == static_cast<gint>(event->x) &&
   1140         drag_monitor_size.width() - 1 == static_cast<gint>(event->x_root)) {
   1141       new_dragged_at_horizontal_edge = dragged_at_horizontal_edge_ + 1;
   1142     }
   1143 
   1144     if (event->y == 0 && event->y_root == 0) {
   1145       new_dragged_at_vertical_edge = dragged_at_vertical_edge_ - 1;
   1146     } else if (allocation.height - 1 == static_cast<gint>(event->y) &&
   1147         drag_monitor_size.height() - 1 == static_cast<gint>(event->y_root)) {
   1148       new_dragged_at_vertical_edge = dragged_at_vertical_edge_ + 1;
   1149     }
   1150 
   1151     event->x_root += new_dragged_at_horizontal_edge;
   1152     event->x += new_dragged_at_horizontal_edge;
   1153     event->y_root += new_dragged_at_vertical_edge;
   1154     event->y += new_dragged_at_vertical_edge;
   1155   } else {
   1156     // Clear whenever we get a non-drag mouse move.
   1157     drag_monitor_size.SetSize(0, 0);
   1158   }
   1159   dragged_at_horizontal_edge_ = new_dragged_at_horizontal_edge;
   1160   dragged_at_vertical_edge_ = new_dragged_at_vertical_edge;
   1161 }
   1162 
   1163 void RenderWidgetHostViewGtk::Paint(const gfx::Rect& damage_rect) {
   1164   TRACE_EVENT0("ui::gtk", "RenderWidgetHostViewGtk::Paint");
   1165 
   1166   // If the GPU process is rendering directly into the View,
   1167   // call the compositor directly.
   1168   RenderWidgetHostImpl* render_widget_host =
   1169       RenderWidgetHostImpl::From(GetRenderWidgetHost());
   1170   if (render_widget_host->is_accelerated_compositing_active()) {
   1171     host_->ScheduleComposite();
   1172     return;
   1173   }
   1174 
   1175   GdkWindow* window = gtk_widget_get_window(view_.get());
   1176   DCHECK(!about_to_validate_and_paint_);
   1177 
   1178   invalid_rect_ = damage_rect;
   1179   about_to_validate_and_paint_ = true;
   1180 
   1181   // If the size of our canvas is (0,0), then we don't want to block here. We
   1182   // are doing one of our first paints and probably have animations going on.
   1183   bool force_create = !host_->empty();
   1184   BackingStoreGtk* backing_store = static_cast<BackingStoreGtk*>(
   1185       host_->GetBackingStore(force_create));
   1186   // Calling GetBackingStore maybe have changed |invalid_rect_|...
   1187   about_to_validate_and_paint_ = false;
   1188 
   1189   gfx::Rect paint_rect = gfx::Rect(0, 0, kMaxWindowWidth, kMaxWindowHeight);
   1190   paint_rect.Intersect(invalid_rect_);
   1191 
   1192   if (backing_store) {
   1193     // Only render the widget if it is attached to a window; there's a short
   1194     // period where this object isn't attached to a window but hasn't been
   1195     // Destroy()ed yet and it receives paint messages...
   1196     if (window) {
   1197       backing_store->XShowRect(gfx::Point(0, 0),
   1198           paint_rect, ui::GetX11WindowFromGtkWidget(view_.get()));
   1199     }
   1200     if (!whiteout_start_time_.is_null()) {
   1201       base::TimeDelta whiteout_duration = base::TimeTicks::Now() -
   1202           whiteout_start_time_;
   1203       UMA_HISTOGRAM_TIMES("MPArch.RWHH_WhiteoutDuration", whiteout_duration);
   1204 
   1205       // Reset the start time to 0 so that we start recording again the next
   1206       // time the backing store is NULL...
   1207       whiteout_start_time_ = base::TimeTicks();
   1208     }
   1209     if (!web_contents_switch_paint_time_.is_null()) {
   1210       base::TimeDelta web_contents_switch_paint_duration =
   1211           base::TimeTicks::Now() - web_contents_switch_paint_time_;
   1212       UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration",
   1213           web_contents_switch_paint_duration);
   1214       // Reset web_contents_switch_paint_time_ to 0 so future tab selections are
   1215       // recorded.
   1216       web_contents_switch_paint_time_ = base::TimeTicks();
   1217     }
   1218     software_latency_info_.AddLatencyNumber(
   1219         ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
   1220     render_widget_host->FrameSwapped(software_latency_info_);
   1221     software_latency_info_.Clear();
   1222   } else {
   1223     if (window)
   1224       gdk_window_clear(window);
   1225     if (whiteout_start_time_.is_null())
   1226       whiteout_start_time_ = base::TimeTicks::Now();
   1227   }
   1228 }
   1229 
   1230 void RenderWidgetHostViewGtk::ShowCurrentCursor() {
   1231   // The widget may not have a window. If that's the case, abort mission. This
   1232   // is the same issue as that explained above in Paint().
   1233   if (!gtk_widget_get_window(view_.get()))
   1234     return;
   1235 
   1236   // TODO(port): WebKit bug https://bugs.webkit.org/show_bug.cgi?id=16388 is
   1237   // that calling gdk_window_set_cursor repeatedly is expensive.  We should
   1238   // avoid it here where possible.
   1239   GdkCursor* gdk_cursor;
   1240   if (current_cursor_.GetCursorType() == GDK_LAST_CURSOR) {
   1241     // Use MOZ_CURSOR_SPINNING if we are showing the default cursor and
   1242     // the page is loading.
   1243     gdk_cursor = is_loading_ ? GetMozSpinningCursor() : NULL;
   1244   } else {
   1245     gdk_cursor = current_cursor_.GetNativeCursor();
   1246   }
   1247   gdk_window_set_cursor(gtk_widget_get_window(view_.get()), gdk_cursor);
   1248 }
   1249 
   1250 void RenderWidgetHostViewGtk::SetHasHorizontalScrollbar(
   1251     bool has_horizontal_scrollbar) {
   1252 }
   1253 
   1254 void RenderWidgetHostViewGtk::SetScrollOffsetPinning(
   1255     bool is_pinned_to_left, bool is_pinned_to_right) {
   1256 }
   1257 
   1258 
   1259 void RenderWidgetHostViewGtk::OnAcceleratedCompositingStateChange() {
   1260   bool activated = host_->is_accelerated_compositing_active();
   1261   GtkPreserveWindow* widget = reinterpret_cast<GtkPreserveWindow*>(view_.get());
   1262 
   1263   gtk_preserve_window_delegate_resize(widget, activated);
   1264 }
   1265 
   1266 void RenderWidgetHostViewGtk::GetScreenInfo(WebScreenInfo* results) {
   1267   GdkWindow* gdk_window = gtk_widget_get_window(view_.get());
   1268   if (!gdk_window) {
   1269     GdkDisplay* display = gdk_display_get_default();
   1270     gdk_window = gdk_display_get_default_group(display);
   1271   }
   1272   if (!gdk_window)
   1273     return;
   1274   GetScreenInfoFromNativeWindow(gdk_window, results);
   1275 }
   1276 
   1277 gfx::Rect RenderWidgetHostViewGtk::GetBoundsInRootWindow() {
   1278   GtkWidget* toplevel = gtk_widget_get_toplevel(view_.get());
   1279   if (!toplevel)
   1280     return GetViewBounds();
   1281 
   1282   GdkRectangle frame_extents;
   1283   GdkWindow* gdk_window = gtk_widget_get_window(toplevel);
   1284   if (!gdk_window)
   1285     return GetViewBounds();
   1286 
   1287   gdk_window_get_frame_extents(gdk_window, &frame_extents);
   1288   return gfx::Rect(frame_extents.x, frame_extents.y,
   1289                    frame_extents.width, frame_extents.height);
   1290 }
   1291 
   1292 gfx::GLSurfaceHandle RenderWidgetHostViewGtk::GetCompositingSurface() {
   1293   if (compositing_surface_ == gfx::kNullPluginWindow) {
   1294     GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
   1295     gfx::NativeViewId view_id = GetNativeViewId();
   1296 
   1297     if (!manager->GetPermanentXIDForId(&compositing_surface_, view_id)) {
   1298       DLOG(ERROR) << "Can't find XID for view id " << view_id;
   1299     }
   1300   }
   1301   return gfx::GLSurfaceHandle(compositing_surface_, gfx::NATIVE_TRANSPORT);
   1302 }
   1303 
   1304 void RenderWidgetHostViewGtk::ResizeCompositingSurface(const gfx::Size& size) {
   1305   GtkWidget* widget = view_.get();
   1306   GdkWindow* window = gtk_widget_get_window(widget);
   1307   if (window) {
   1308     Display* display = GDK_WINDOW_XDISPLAY(window);
   1309     gdk_window_resize(window, size.width(), size.height());
   1310     XSync(display, False);
   1311   }
   1312 }
   1313 
   1314 bool RenderWidgetHostViewGtk::LockMouse() {
   1315   if (mouse_locked_)
   1316     return true;
   1317 
   1318   mouse_locked_ = true;
   1319 
   1320   // Release any current grab.
   1321   GtkWidget* current_grab_window = gtk_grab_get_current();
   1322   if (current_grab_window) {
   1323     gtk_grab_remove(current_grab_window);
   1324     LOG(WARNING) << "Locking Mouse with gdk_pointer_grab, "
   1325                  << "but had to steal grab from another window";
   1326   }
   1327 
   1328   GtkWidget* widget = view_.get();
   1329   GdkWindow* window = gtk_widget_get_window(widget);
   1330   GdkCursor* cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
   1331 
   1332   GdkGrabStatus grab_status =
   1333       gdk_pointer_grab(window,
   1334                        FALSE,  // owner_events
   1335                        static_cast<GdkEventMask>(
   1336                            GDK_POINTER_MOTION_MASK |
   1337                            GDK_BUTTON_PRESS_MASK |
   1338                            GDK_BUTTON_RELEASE_MASK),
   1339                        window,  // confine_to
   1340                        cursor,
   1341                        GDK_CURRENT_TIME);
   1342 
   1343   if (grab_status != GDK_GRAB_SUCCESS) {
   1344     LOG(WARNING) << "Failed to grab pointer for LockMouse. "
   1345                  << "gdk_pointer_grab returned: " << grab_status;
   1346     mouse_locked_ = false;
   1347     return false;
   1348   }
   1349 
   1350   // Clear the tooltip window.
   1351   SetTooltipText(base::string16());
   1352 
   1353   // Ensure that the widget center location will be relevant for this mouse
   1354   // lock session. It is updated whenever the window geometry moves
   1355   // but may be out of date due to switching tabs.
   1356   MarkCachedWidgetCenterStale();
   1357 
   1358   // Ensure that if we were previously warping the cursor to a specific point
   1359   // that we no longer track doing so when entering lock. It should be cleared
   1360   // by the cursor moving to the warp point, and this shouldn't be necessary.
   1361   // But, this is a small effort to ensure robustness in the event a warp isn't
   1362   // completed.
   1363   mouse_is_being_warped_to_unlocked_position_ = false;
   1364 
   1365   return true;
   1366 }
   1367 
   1368 void RenderWidgetHostViewGtk::UnlockMouse() {
   1369   if (!mouse_locked_)
   1370     return;
   1371 
   1372   mouse_locked_ = false;
   1373 
   1374   GtkWidget* widget = view_.get();
   1375   GdkDisplay* display = gtk_widget_get_display(widget);
   1376   GdkScreen* screen = gtk_widget_get_screen(widget);
   1377   gdk_display_pointer_ungrab(display, GDK_CURRENT_TIME);
   1378   gdk_display_warp_pointer(display, screen,
   1379                            unlocked_global_mouse_position_.x(),
   1380                            unlocked_global_mouse_position_.y());
   1381   mouse_is_being_warped_to_unlocked_position_ = true;
   1382 
   1383   if (host_)
   1384     host_->LostMouseLock();
   1385 }
   1386 
   1387 void RenderWidgetHostViewGtk::ForwardKeyboardEvent(
   1388     const NativeWebKeyboardEvent& event) {
   1389   if (!host_)
   1390     return;
   1391 
   1392   EditCommands edit_commands;
   1393   if (!event.skip_in_browser &&
   1394       key_bindings_handler_->Match(event, &edit_commands)) {
   1395     Send(new InputMsg_SetEditCommandsForNextKeyEvent(
   1396         host_->GetRoutingID(), edit_commands));
   1397     NativeWebKeyboardEvent copy_event(event);
   1398     copy_event.match_edit_command = true;
   1399     host_->ForwardKeyboardEvent(copy_event);
   1400     return;
   1401   }
   1402 
   1403   host_->ForwardKeyboardEvent(event);
   1404 }
   1405 
   1406 bool RenderWidgetHostViewGtk::RetrieveSurrounding(std::string* text,
   1407                                                   size_t* cursor_index) {
   1408   if (!selection_range_.IsValid())
   1409     return false;
   1410 
   1411   size_t offset = selection_range_.GetMin() - selection_text_offset_;
   1412   DCHECK(offset <= selection_text_.length());
   1413 
   1414   if (offset == selection_text_.length()) {
   1415     *text = UTF16ToUTF8(selection_text_);
   1416     *cursor_index = text->length();
   1417     return true;
   1418   }
   1419 
   1420   *text = base::UTF16ToUTF8AndAdjustOffset(
   1421       base::StringPiece16(selection_text_), &offset);
   1422   if (offset == base::string16::npos) {
   1423     NOTREACHED() << "Invalid offset in UTF16 string.";
   1424     return false;
   1425   }
   1426   *cursor_index = offset;
   1427   return true;
   1428 }
   1429 
   1430 void RenderWidgetHostViewGtk::set_last_mouse_down(GdkEventButton* event) {
   1431   GdkEventButton* temp = NULL;
   1432   if (event) {
   1433     temp = reinterpret_cast<GdkEventButton*>(
   1434         gdk_event_copy(reinterpret_cast<GdkEvent*>(event)));
   1435   }
   1436 
   1437   if (last_mouse_down_)
   1438     gdk_event_free(reinterpret_cast<GdkEvent*>(last_mouse_down_));
   1439 
   1440   last_mouse_down_ = temp;
   1441 }
   1442 
   1443 void RenderWidgetHostViewGtk::MarkCachedWidgetCenterStale() {
   1444   widget_center_valid_ = false;
   1445   mouse_has_been_warped_to_new_center_ = false;
   1446 }
   1447 
   1448 gfx::Point RenderWidgetHostViewGtk::GetWidgetCenter() {
   1449   if (widget_center_valid_)
   1450     return widget_center_;
   1451 
   1452   GdkWindow* window = gtk_widget_get_window(view_.get());
   1453   gint window_x = 0;
   1454   gint window_y = 0;
   1455   gdk_window_get_origin(window, &window_x, &window_y);
   1456   gint window_w = gdk_window_get_width(window);
   1457   gint window_h = gdk_window_get_height(window);
   1458   widget_center_.SetPoint(window_x + window_w / 2,
   1459                           window_y + window_h / 2);
   1460   widget_center_valid_ = true;
   1461   return widget_center_;
   1462 }
   1463 
   1464 void RenderWidgetHostViewGtk::ModifyEventMovementAndCoords(
   1465     blink::WebMouseEvent* event) {
   1466   // Movement is computed by taking the difference of the new cursor position
   1467   // and the previous. Under mouse lock the cursor will be warped back to the
   1468   // center so that we are not limited by clipping boundaries.
   1469   // We do not measure movement as the delta from cursor to center because
   1470   // we may receive more mouse movement events before our warp has taken
   1471   // effect.
   1472   event->movementX = event->globalX - global_mouse_position_.x();
   1473   event->movementY = event->globalY - global_mouse_position_.y();
   1474 
   1475   // While the cursor is being warped back to the unlocked position, suppress
   1476   // the movement member data.
   1477   if (mouse_is_being_warped_to_unlocked_position_) {
   1478     event->movementX = 0;
   1479     event->movementY = 0;
   1480     if (MovedToPoint(*event, unlocked_global_mouse_position_))
   1481       mouse_is_being_warped_to_unlocked_position_ = false;
   1482   }
   1483 
   1484   global_mouse_position_.SetPoint(event->globalX, event->globalY);
   1485 
   1486   // Under mouse lock, coordinates of mouse are locked to what they were when
   1487   // mouse lock was entered.
   1488   if (mouse_locked_) {
   1489     event->x = unlocked_mouse_position_.x();
   1490     event->y = unlocked_mouse_position_.y();
   1491     event->windowX = unlocked_mouse_position_.x();
   1492     event->windowY = unlocked_mouse_position_.y();
   1493     event->globalX = unlocked_global_mouse_position_.x();
   1494     event->globalY = unlocked_global_mouse_position_.y();
   1495   } else if (!mouse_is_being_warped_to_unlocked_position_) {
   1496     unlocked_mouse_position_.SetPoint(event->windowX, event->windowY);
   1497     unlocked_global_mouse_position_.SetPoint(event->globalX, event->globalY);
   1498   }
   1499 }
   1500 
   1501 ////////////////////////////////////////////////////////////////////////////////
   1502 // RenderWidgetHostView, public:
   1503 
   1504 // static
   1505 RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget(
   1506     RenderWidgetHost* widget) {
   1507   return new RenderWidgetHostViewGtk(widget);
   1508 }
   1509 
   1510 // static
   1511 void RenderWidgetHostViewPort::GetDefaultScreenInfo(WebScreenInfo* results) {
   1512   GdkWindow* gdk_window =
   1513       gdk_display_get_default_group(gdk_display_get_default());
   1514   GetScreenInfoFromNativeWindow(gdk_window, results);
   1515 }
   1516 
   1517 void RenderWidgetHostViewGtk::SetAccessibilityFocus(int acc_obj_id) {
   1518   if (!host_)
   1519     return;
   1520 
   1521   host_->AccessibilitySetFocus(acc_obj_id);
   1522 }
   1523 
   1524 void RenderWidgetHostViewGtk::AccessibilityDoDefaultAction(int acc_obj_id) {
   1525   if (!host_)
   1526     return;
   1527 
   1528   host_->AccessibilityDoDefaultAction(acc_obj_id);
   1529 }
   1530 
   1531 void RenderWidgetHostViewGtk::AccessibilityScrollToMakeVisible(
   1532     int acc_obj_id, gfx::Rect subfocus) {
   1533   if (!host_)
   1534     return;
   1535 
   1536   host_->AccessibilityScrollToMakeVisible(acc_obj_id, subfocus);
   1537 }
   1538 
   1539 void RenderWidgetHostViewGtk::AccessibilityScrollToPoint(
   1540     int acc_obj_id, gfx::Point point) {
   1541   if (!host_)
   1542     return;
   1543 
   1544   host_->AccessibilityScrollToPoint(acc_obj_id, point);
   1545 }
   1546 
   1547 void RenderWidgetHostViewGtk::AccessibilitySetTextSelection(
   1548     int acc_obj_id, int start_offset, int end_offset) {
   1549   if (!host_)
   1550     return;
   1551 
   1552   host_->AccessibilitySetTextSelection(acc_obj_id, start_offset, end_offset);
   1553 }
   1554 
   1555 gfx::Point RenderWidgetHostViewGtk::GetLastTouchEventLocation() const {
   1556   // Not needed on Linux.
   1557   return gfx::Point();
   1558 }
   1559 
   1560 void RenderWidgetHostViewGtk::FatalAccessibilityTreeError() {
   1561   if (host_) {
   1562     host_->FatalAccessibilityTreeError();
   1563     SetBrowserAccessibilityManager(NULL);
   1564   } else {
   1565     CHECK(FALSE);
   1566   }
   1567 }
   1568 
   1569 void RenderWidgetHostViewGtk::OnAccessibilityEvents(
   1570     const std::vector<AccessibilityHostMsg_EventParams>& params) {
   1571   if (!GetBrowserAccessibilityManager()) {
   1572     GtkWidget* parent = gtk_widget_get_parent(view_.get());
   1573     SetBrowserAccessibilityManager(
   1574         new BrowserAccessibilityManagerGtk(
   1575             parent,
   1576             BrowserAccessibilityManagerGtk::GetEmptyDocument(),
   1577             this));
   1578   }
   1579   GetBrowserAccessibilityManager()->OnAccessibilityEvents(params);
   1580 }
   1581 
   1582 AtkObject* RenderWidgetHostViewGtk::GetAccessible() {
   1583   if (!GetBrowserAccessibilityManager()) {
   1584     GtkWidget* parent = gtk_widget_get_parent(view_.get());
   1585     SetBrowserAccessibilityManager(
   1586         new BrowserAccessibilityManagerGtk(
   1587             parent,
   1588             BrowserAccessibilityManagerGtk::GetEmptyDocument(),
   1589             this));
   1590   }
   1591   BrowserAccessibilityGtk* root =
   1592       GetBrowserAccessibilityManager()->GetRoot()->ToBrowserAccessibilityGtk();
   1593 
   1594   atk_object_set_role(root->GetAtkObject(), ATK_ROLE_HTML_CONTAINER);
   1595   return root->GetAtkObject();
   1596 }
   1597 
   1598 void RenderWidgetHostViewGtk::OnCreatePluginContainer(
   1599     gfx::PluginWindowHandle id) {
   1600   plugin_container_manager_.CreatePluginContainer(id);
   1601 }
   1602 
   1603 void RenderWidgetHostViewGtk::OnDestroyPluginContainer(
   1604     gfx::PluginWindowHandle id) {
   1605   plugin_container_manager_.DestroyPluginContainer(id);
   1606 }
   1607 
   1608 }  // namespace content
   1609