Home | History | Annotate | Download | only in gtk
      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 string16 WebDialogGtk::GetDialogTitle() const {
     79   return delegate_ ? delegate_->GetDialogTitle() : 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 == WebKit::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