1// Copyright (c) 2011 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 "chrome/browser/ui/views/tab_contents/native_tab_contents_container_gtk.h"
6
7#include "chrome/browser/ui/view_ids.h"
8#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
9#include "content/browser/renderer_host/render_widget_host_view.h"
10#include "content/browser/tab_contents/interstitial_page.h"
11#include "content/browser/tab_contents/tab_contents.h"
12#include "ui/base/accessibility/accessible_view_state.h"
13#include "views/focus/focus_manager.h"
14
15////////////////////////////////////////////////////////////////////////////////
16// NativeTabContentsContainerGtk, public:
17
18NativeTabContentsContainerGtk::NativeTabContentsContainerGtk(
19    TabContentsContainer* container)
20    : container_(container),
21      focus_callback_id_(0) {
22  SetID(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW);
23}
24
25NativeTabContentsContainerGtk::~NativeTabContentsContainerGtk() {
26}
27
28////////////////////////////////////////////////////////////////////////////////
29// NativeTabContentsContainerGtk, NativeTabContentsContainer overrides:
30
31void NativeTabContentsContainerGtk::AttachContents(TabContents* contents) {
32  Attach(contents->GetNativeView());
33}
34
35void NativeTabContentsContainerGtk::DetachContents(TabContents* contents) {
36  gtk_widget_hide(contents->GetNativeView());
37
38  // Now detach the TabContents.
39  Detach();
40}
41
42void NativeTabContentsContainerGtk::SetFastResize(bool fast_resize) {
43  set_fast_resize(fast_resize);
44}
45
46void NativeTabContentsContainerGtk::RenderViewHostChanged(
47    RenderViewHost* old_host,
48    RenderViewHost* new_host) {
49  // If we are focused, we need to pass the focus to the new RenderViewHost.
50  views::FocusManager* focus_manager = GetFocusManager();
51  if (focus_manager->GetFocusedView() == this)
52    OnFocus();
53}
54
55views::View* NativeTabContentsContainerGtk::GetView() {
56  return this;
57}
58
59void NativeTabContentsContainerGtk::TabContentsFocused(
60    TabContents* tab_contents) {
61#if !defined(TOUCH_UI)
62  // Called when the tab contents native view gets focused (typically through a
63  // user click).  We make ourself the focused view, so the focus is restored
64  // properly when the browser window is deactivated/reactivated.
65  views::FocusManager* focus_manager = GetFocusManager();
66  if (!focus_manager) {
67    NOTREACHED();
68    return;
69  }
70  focus_manager->SetFocusedView(this);
71#else
72  // no native views in TOUCH_UI, so don't steal the focus
73#endif
74}
75
76////////////////////////////////////////////////////////////////////////////////
77// NativeTabContentsContainerGtk, views::View overrides:
78
79bool NativeTabContentsContainerGtk::SkipDefaultKeyEventProcessing(
80    const views::KeyEvent& e) {
81  // Don't look-up accelerators or tab-traverse if we are showing a non-crashed
82  // TabContents.
83  // We'll first give the page a chance to process the key events.  If it does
84  // not process them, they'll be returned to us and we'll treat them as
85  // accelerators then.
86  return container_->tab_contents() &&
87         !container_->tab_contents()->is_crashed();
88}
89
90views::FocusTraversable* NativeTabContentsContainerGtk::GetFocusTraversable() {
91  return NULL;
92}
93
94bool NativeTabContentsContainerGtk::IsFocusable() const {
95  // We need to be focusable when our contents is not a view hierarchy, as
96  // clicking on the contents needs to focus us.
97  return container_->tab_contents() != NULL;
98}
99
100void NativeTabContentsContainerGtk::OnFocus() {
101  if (container_->tab_contents())
102    container_->tab_contents()->Focus();
103}
104
105void NativeTabContentsContainerGtk::RequestFocus() {
106  // This is a hack to circumvent the fact that a view does not explicitly get
107  // a call to set the focus if it already has the focus. This causes a problem
108  // with tabs such as the TabContents that instruct the RenderView that it got
109  // focus when they actually get the focus. When switching from one TabContents
110  // tab that has focus to another TabContents tab that had focus, since the
111  // TabContentsContainerView already has focus, OnFocus() would not be called
112  // and the RenderView would not get notified it got focused.
113  // By clearing the focused view before-hand, we ensure OnFocus() will be
114  // called.
115  views::FocusManager* focus_manager = GetFocusManager();
116  if (focus_manager)
117    focus_manager->SetFocusedView(NULL);
118  View::RequestFocus();
119}
120
121void NativeTabContentsContainerGtk::AboutToRequestFocusFromTabTraversal(
122    bool reverse) {
123  if (!container_->tab_contents())
124    return;
125  // Give an opportunity to the tab to reset its focus.
126  if (container_->tab_contents()->interstitial_page()) {
127    container_->tab_contents()->interstitial_page()->FocusThroughTabTraversal(
128        reverse);
129    return;
130  }
131  container_->tab_contents()->FocusThroughTabTraversal(reverse);
132}
133
134void NativeTabContentsContainerGtk::GetAccessibleState(
135    ui::AccessibleViewState* state) {
136  state->role = ui::AccessibilityTypes::ROLE_GROUPING;
137}
138
139////////////////////////////////////////////////////////////////////////////////
140// NativeTabContentsContainer, public:
141
142// static
143NativeTabContentsContainer* NativeTabContentsContainer::CreateNativeContainer(
144    TabContentsContainer* container) {
145  return new NativeTabContentsContainerGtk(container);
146}
147