172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/constrained_window_gtk.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <gdk/gdkkeysyms.h>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_list.h"
1072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_util.h"
11dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
12dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
13201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
14201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#if defined(TOUCH_UI)
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h"
16201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#else
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_contents_view_gtk.h"
18201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#endif
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickConstrainedWindowGtkDelegate::~ConstrainedWindowGtkDelegate() {
21731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
22731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
23731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ConstrainedWindowGtkDelegate::GetBackgroundColor(GdkColor* color) {
24731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return false;
25731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
26731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ConstrainedWindowGtkDelegate::ShouldHaveBorderPadding() const {
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochConstrainedWindowGtk::ConstrainedWindowGtk(
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabContents* owner, ConstrainedWindowGtkDelegate* delegate)
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : owner_(owner),
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delegate_(delegate),
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      visible_(false),
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      factory_(this) {
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(owner);
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(delegate);
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkWidget* dialog = delegate->GetWidgetRoot();
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Unlike other users of CreateBorderBin, we need a dedicated frame around
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // our "window".
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkWidget* ebox = gtk_event_box_new();
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkWidget* frame = gtk_frame_new(NULL);
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
46731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (delegate->ShouldHaveBorderPadding()) {
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        gtk_util::kContentAreaBorder, gtk_util::kContentAreaBorder,
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        gtk_util::kContentAreaBorder, gtk_util::kContentAreaBorder);
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
54731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  GdkColor background;
55731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (delegate->GetBackgroundColor(&background)) {
56731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    gtk_widget_modify_base(ebox, GTK_STATE_NORMAL, &background);
57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    gtk_widget_modify_fg(ebox, GTK_STATE_NORMAL, &background);
58731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, &background);
59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (gtk_widget_get_parent(dialog))
624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    gtk_widget_reparent(dialog, alignment);
634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  else
644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    gtk_container_add(GTK_CONTAINER(alignment), dialog);
654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_container_add(GTK_CONTAINER(frame), alignment);
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_container_add(GTK_CONTAINER(ebox), frame);
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  border_.Own(ebox);
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  gtk_widget_add_events(widget(), GDK_KEY_PRESS_MASK);
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_signal_connect(widget(), "key-press-event", G_CALLBACK(OnKeyPressThunk),
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   this);
73dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  g_signal_connect(widget(), "hierarchy-changed",
74dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                   G_CALLBACK(OnHierarchyChangedThunk), this);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochConstrainedWindowGtk::~ConstrainedWindowGtk() {
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  border_.Destroy();
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ConstrainedWindowGtk::ShowConstrainedWindow() {
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_show_all(border_.get());
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
84201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // We collaborate with TabContentsView and stick ourselves in the
85201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // TabContentsView's floating container.
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ContainingView()->AttachConstrainedWindow(this);
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  visible_ = true;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ConstrainedWindowGtk::CloseConstrainedWindow() {
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (visible_)
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ContainingView()->RemoveConstrainedWindow(this);
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_->DeleteDelegate();
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  owner_->WillClose(this);
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete this;
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
100dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid ConstrainedWindowGtk::FocusConstrainedWindow() {
101dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  GtkWidget* focus_widget = delegate_->GetFocusWidget();
102dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!focus_widget)
103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
104dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
105dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // The user may have focused another tab. In this case do not grab focus
106dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // until this tab is refocused.
107dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if ((!owner_->delegate() ||
108dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          owner_->delegate()->ShouldFocusConstrainedWindow()) &&
109dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      gtk_util::IsWidgetAncestryVisible(focus_widget)) {
110dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    gtk_widget_grab_focus(focus_widget);
111dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else {
112dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // TODO(estade): this define should not need to be here because this class
113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // should not be used on linux/views.
114dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(TOOLKIT_GTK)
115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    static_cast<TabContentsViewGtk*>(owner_->view())->
116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        SetFocusedWidget(focus_widget);
117dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif
118dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
120dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
121201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochConstrainedWindowGtk::TabContentsViewType*
122201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    ConstrainedWindowGtk::ContainingView() {
123201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return static_cast<TabContentsViewType*>(owner_->view());
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickgboolean ConstrainedWindowGtk::OnKeyPress(GtkWidget* sender,
1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                          GdkEventKey* key) {
1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (key->keyval == GDK_Escape) {
1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Let the stack unwind so the event handler can release its ref
1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // on widget().
1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    MessageLoop::current()->PostTask(FROM_HERE,
1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        factory_.NewRunnableMethod(
1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            &ConstrainedWindowGtk::CloseConstrainedWindow));
1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return TRUE;
1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return FALSE;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
140dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid ConstrainedWindowGtk::OnHierarchyChanged(GtkWidget* sender,
141dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                              GtkWidget* previous_toplevel) {
142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(widget())))
144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  FocusConstrainedWindow();
147dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochConstrainedWindow* ConstrainedWindow::CreateConstrainedDialog(
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabContents* parent,
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ConstrainedWindowGtkDelegate* delegate) {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new ConstrainedWindowGtk(parent, delegate);
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
155