constrained_window_gtk.cc revision dc0f95d653279beabeb9817299e2902918ba123e
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/gtk/constrained_window_gtk.h"
6
7#include <gdk/gdkkeysyms.h>
8
9#include "chrome/browser/browser_list.h"
10#include "chrome/browser/ui/gtk/gtk_util.h"
11#include "content/browser/browser_thread.h"
12#include "content/browser/tab_contents/tab_contents.h"
13
14#if defined(TOUCH_UI)
15#include "chrome/browser/ui/views/tab_contents/tab_contents_view_views.h"
16#else
17#include "chrome/browser/tab_contents/tab_contents_view_gtk.h"
18#endif
19
20ConstrainedWindowGtkDelegate::~ConstrainedWindowGtkDelegate() {
21}
22
23bool ConstrainedWindowGtkDelegate::GetBackgroundColor(GdkColor* color) {
24  return false;
25}
26
27ConstrainedWindowGtk::ConstrainedWindowGtk(
28    TabContents* owner, ConstrainedWindowGtkDelegate* delegate)
29    : owner_(owner),
30      delegate_(delegate),
31      visible_(false),
32      factory_(this) {
33  DCHECK(owner);
34  DCHECK(delegate);
35  GtkWidget* dialog = delegate->GetWidgetRoot();
36
37  // Unlike other users of CreateBorderBin, we need a dedicated frame around
38  // our "window".
39  GtkWidget* ebox = gtk_event_box_new();
40  GtkWidget* frame = gtk_frame_new(NULL);
41  gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
42
43  GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
44  gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
45      gtk_util::kContentAreaBorder, gtk_util::kContentAreaBorder,
46      gtk_util::kContentAreaBorder, gtk_util::kContentAreaBorder);
47  GdkColor background;
48  if (delegate->GetBackgroundColor(&background)) {
49    gtk_widget_modify_base(ebox, GTK_STATE_NORMAL, &background);
50    gtk_widget_modify_fg(ebox, GTK_STATE_NORMAL, &background);
51    gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, &background);
52  }
53
54  if (gtk_widget_get_parent(dialog))
55    gtk_widget_reparent(dialog, alignment);
56  else
57    gtk_container_add(GTK_CONTAINER(alignment), dialog);
58
59  gtk_container_add(GTK_CONTAINER(frame), alignment);
60  gtk_container_add(GTK_CONTAINER(ebox), frame);
61  border_.Own(ebox);
62
63  gtk_widget_add_events(widget(), GDK_KEY_PRESS_MASK);
64  g_signal_connect(widget(), "key-press-event", G_CALLBACK(OnKeyPressThunk),
65                   this);
66  g_signal_connect(widget(), "hierarchy-changed",
67                   G_CALLBACK(OnHierarchyChangedThunk), this);
68}
69
70ConstrainedWindowGtk::~ConstrainedWindowGtk() {
71  border_.Destroy();
72}
73
74void ConstrainedWindowGtk::ShowConstrainedWindow() {
75  gtk_widget_show_all(border_.get());
76
77  // We collaborate with TabContentsView and stick ourselves in the
78  // TabContentsView's floating container.
79  ContainingView()->AttachConstrainedWindow(this);
80
81  visible_ = true;
82}
83
84void ConstrainedWindowGtk::CloseConstrainedWindow() {
85  if (visible_)
86    ContainingView()->RemoveConstrainedWindow(this);
87  delegate_->DeleteDelegate();
88  owner_->WillClose(this);
89
90  delete this;
91}
92
93void ConstrainedWindowGtk::FocusConstrainedWindow() {
94  GtkWidget* focus_widget = delegate_->GetFocusWidget();
95  if (!focus_widget)
96    return;
97
98  // The user may have focused another tab. In this case do not grab focus
99  // until this tab is refocused.
100  if ((!owner_->delegate() ||
101          owner_->delegate()->ShouldFocusConstrainedWindow()) &&
102      gtk_util::IsWidgetAncestryVisible(focus_widget)) {
103    gtk_widget_grab_focus(focus_widget);
104  } else {
105  // TODO(estade): this define should not need to be here because this class
106  // should not be used on linux/views.
107#if defined(TOOLKIT_GTK)
108    static_cast<TabContentsViewGtk*>(owner_->view())->
109        SetFocusedWidget(focus_widget);
110#endif
111  }
112}
113
114ConstrainedWindowGtk::TabContentsViewType*
115    ConstrainedWindowGtk::ContainingView() {
116  return static_cast<TabContentsViewType*>(owner_->view());
117}
118
119gboolean ConstrainedWindowGtk::OnKeyPress(GtkWidget* sender,
120                                          GdkEventKey* key) {
121  if (key->keyval == GDK_Escape) {
122    // Let the stack unwind so the event handler can release its ref
123    // on widget().
124    MessageLoop::current()->PostTask(FROM_HERE,
125        factory_.NewRunnableMethod(
126            &ConstrainedWindowGtk::CloseConstrainedWindow));
127    return TRUE;
128  }
129
130  return FALSE;
131}
132
133void ConstrainedWindowGtk::OnHierarchyChanged(GtkWidget* sender,
134                                              GtkWidget* previous_toplevel) {
135  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
136  if (!GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(widget())))
137    return;
138
139  FocusConstrainedWindow();
140}
141
142// static
143ConstrainedWindow* ConstrainedWindow::CreateConstrainedDialog(
144    TabContents* parent,
145    ConstrainedWindowGtkDelegate* delegate) {
146  return new ConstrainedWindowGtk(parent, delegate);
147}
148