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