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