1 // Copyright (c) 2012 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/web_dialog_gtk.h" 6 7 #include <gtk/gtk.h> 8 9 #include "base/strings/utf_string_conversions.h" 10 #include "chrome/browser/ui/browser_dialogs.h" 11 #include "chrome/browser/ui/gtk/gtk_util.h" 12 #include "chrome/browser/ui/webui/chrome_web_contents_handler.h" 13 #include "content/public/browser/native_web_keyboard_event.h" 14 #include "content/public/browser/web_contents.h" 15 #include "content/public/browser/web_contents_view.h" 16 #include "ui/web_dialogs/web_dialog_ui.h" 17 18 using content::NativeWebKeyboardEvent; 19 using content::WebContents; 20 using content::WebUIMessageHandler; 21 using ui::WebDialogDelegate; 22 using ui::WebDialogUI; 23 using ui::WebDialogWebContentsDelegate; 24 25 namespace chrome { 26 27 gfx::NativeWindow ShowWebDialog(gfx::NativeWindow parent, 28 content::BrowserContext* context, 29 WebDialogDelegate* delegate) { 30 WebDialogGtk* web_dialog = new WebDialogGtk(context, delegate, parent); 31 return web_dialog->InitDialog(); 32 } 33 34 } // namespace chrome 35 36 namespace { 37 38 void SetDialogStyle() { 39 static bool style_was_set = false; 40 41 if (style_was_set) 42 return; 43 style_was_set = true; 44 45 gtk_rc_parse_string( 46 "style \"chrome-html-dialog\" {\n" 47 " GtkDialog::action-area-border = 0\n" 48 " GtkDialog::content-area-border = 0\n" 49 " GtkDialog::content-area-spacing = 0\n" 50 "}\n" 51 "widget \"*chrome-html-dialog\" style \"chrome-html-dialog\""); 52 } 53 54 } // namespace 55 56 //////////////////////////////////////////////////////////////////////////////// 57 // WebDialogGtk, public: 58 59 WebDialogGtk::WebDialogGtk(content::BrowserContext* context, 60 WebDialogDelegate* delegate, 61 gfx::NativeWindow parent_window) 62 : WebDialogWebContentsDelegate(context, new ChromeWebContentsHandler), 63 delegate_(delegate), 64 parent_window_(parent_window), 65 dialog_(NULL) { 66 } 67 68 WebDialogGtk::~WebDialogGtk() { 69 } 70 71 //////////////////////////////////////////////////////////////////////////////// 72 // WebDialogDelegate implementation: 73 74 ui::ModalType WebDialogGtk::GetDialogModalType() const { 75 return delegate_ ? delegate_->GetDialogModalType() : ui::MODAL_TYPE_NONE; 76 } 77 78 base::string16 WebDialogGtk::GetDialogTitle() const { 79 return delegate_ ? delegate_->GetDialogTitle() : base::string16(); 80 } 81 82 GURL WebDialogGtk::GetDialogContentURL() const { 83 if (delegate_) 84 return delegate_->GetDialogContentURL(); 85 else 86 return GURL(); 87 } 88 89 void WebDialogGtk::GetWebUIMessageHandlers( 90 std::vector<WebUIMessageHandler*>* handlers) const { 91 if (delegate_) 92 delegate_->GetWebUIMessageHandlers(handlers); 93 else 94 handlers->clear(); 95 } 96 97 void WebDialogGtk::GetDialogSize(gfx::Size* size) const { 98 if (delegate_) 99 delegate_->GetDialogSize(size); 100 else 101 *size = gfx::Size(); 102 } 103 104 void WebDialogGtk::GetMinimumDialogSize(gfx::Size* size) const { 105 if (delegate_) 106 delegate_->GetMinimumDialogSize(size); 107 else 108 *size = gfx::Size(); 109 } 110 111 std::string WebDialogGtk::GetDialogArgs() const { 112 if (delegate_) 113 return delegate_->GetDialogArgs(); 114 else 115 return std::string(); 116 } 117 118 void WebDialogGtk::OnDialogClosed(const std::string& json_retval) { 119 DCHECK(dialog_); 120 121 Detach(); 122 if (delegate_) { 123 WebDialogDelegate* dialog_delegate = delegate_; 124 delegate_ = NULL; // We will not communicate further with the delegate. 125 126 // Store the dialog bounds. 127 gfx::Rect dialog_bounds = gtk_util::GetDialogBounds(GTK_WIDGET(dialog_)); 128 dialog_delegate->StoreDialogSize(dialog_bounds.size()); 129 130 dialog_delegate->OnDialogClosed(json_retval); 131 } 132 133 gtk_widget_destroy(dialog_); 134 delete this; 135 } 136 137 void WebDialogGtk::OnCloseContents(WebContents* source, 138 bool* out_close_dialog) { 139 if (delegate_) 140 delegate_->OnCloseContents(source, out_close_dialog); 141 } 142 143 void WebDialogGtk::CloseContents(WebContents* source) { 144 DCHECK(dialog_); 145 146 bool close_dialog = false; 147 OnCloseContents(source, &close_dialog); 148 if (close_dialog) 149 OnDialogClosed(std::string()); 150 } 151 152 content::WebContents* WebDialogGtk::OpenURLFromTab( 153 content::WebContents* source, 154 const content::OpenURLParams& params) { 155 content::WebContents* new_contents = NULL; 156 if (delegate_ && 157 delegate_->HandleOpenURLFromTab(source, params, &new_contents)) { 158 return new_contents; 159 } 160 return WebDialogWebContentsDelegate::OpenURLFromTab(source, params); 161 } 162 163 void WebDialogGtk::AddNewContents(content::WebContents* source, 164 content::WebContents* new_contents, 165 WindowOpenDisposition disposition, 166 const gfx::Rect& initial_pos, 167 bool user_gesture, 168 bool* was_blocked) { 169 if (delegate_ && delegate_->HandleAddNewContents( 170 source, new_contents, disposition, initial_pos, user_gesture)) { 171 return; 172 } 173 WebDialogWebContentsDelegate::AddNewContents( 174 source, new_contents, disposition, initial_pos, user_gesture, 175 was_blocked); 176 } 177 178 void WebDialogGtk::LoadingStateChanged(content::WebContents* source) { 179 if (delegate_) 180 delegate_->OnLoadingStateChanged(source); 181 } 182 183 bool WebDialogGtk::ShouldShowDialogTitle() const { 184 return true; 185 } 186 187 //////////////////////////////////////////////////////////////////////////////// 188 // content::WebContentsDelegate implementation: 189 190 // A simplified version of BrowserWindowGtk::HandleKeyboardEvent(). 191 // We don't handle global keyboard shortcuts here, but that's fine since 192 // they're all browser-specific. (This may change in the future.) 193 void WebDialogGtk::HandleKeyboardEvent(content::WebContents* source, 194 const NativeWebKeyboardEvent& event) { 195 GdkEventKey* os_event = &event.os_event->key; 196 if (!os_event || event.type == blink::WebInputEvent::Char) 197 return; 198 199 // To make sure the default key bindings can still work, such as Escape to 200 // close the dialog. 201 gtk_bindings_activate_event(GTK_OBJECT(dialog_), os_event); 202 } 203 204 //////////////////////////////////////////////////////////////////////////////// 205 // WebDialogGtk: 206 207 gfx::NativeWindow WebDialogGtk::InitDialog() { 208 web_contents_.reset(WebContents::Create( 209 WebContents::CreateParams(browser_context()))); 210 web_contents_->SetDelegate(this); 211 212 // This must be done before loading the page; see the comments in 213 // WebDialogUI. 214 WebDialogUI::SetDelegate(web_contents_.get(), this); 215 216 web_contents_->GetController().LoadURL( 217 GetDialogContentURL(), 218 content::Referrer(), 219 content::PAGE_TRANSITION_AUTO_TOPLEVEL, 220 std::string()); 221 GtkDialogFlags flags = GTK_DIALOG_NO_SEPARATOR; 222 if (delegate_->GetDialogModalType() != ui::MODAL_TYPE_NONE) 223 flags = static_cast<GtkDialogFlags>(flags | GTK_DIALOG_MODAL); 224 225 dialog_ = gtk_dialog_new_with_buttons( 226 UTF16ToUTF8(delegate_->GetDialogTitle()).c_str(), 227 parent_window_, 228 flags, 229 NULL); 230 231 SetDialogStyle(); 232 gtk_widget_set_name(dialog_, "chrome-html-dialog"); 233 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this); 234 235 GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog_)); 236 gfx::NativeView web_contents_widget = 237 web_contents_->GetView()->GetNativeView(); 238 gtk_box_pack_start(GTK_BOX(content_area), web_contents_widget, TRUE, TRUE, 0); 239 240 gfx::Size dialog_size; 241 delegate_->GetDialogSize(&dialog_size); 242 if (!dialog_size.IsEmpty()) { 243 gtk_window_set_default_size(GTK_WINDOW(dialog_), 244 dialog_size.width(), 245 dialog_size.height()); 246 } 247 gfx::Size minimum_dialog_size; 248 delegate_->GetMinimumDialogSize(&minimum_dialog_size); 249 if (!minimum_dialog_size.IsEmpty()) { 250 gtk_widget_set_size_request(GTK_WIDGET(web_contents_widget), 251 minimum_dialog_size.width(), 252 minimum_dialog_size.height()); 253 } 254 255 gtk_widget_show_all(dialog_); 256 257 web_contents_->GetView()->SetInitialFocus(); 258 259 return GTK_WINDOW(dialog_); 260 } 261 262 void WebDialogGtk::OnResponse(GtkWidget* dialog, int response_id) { 263 OnDialogClosed(std::string()); 264 } 265