15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/speech/speech_recognition_bubble.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_finder.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/browser_toolbar_gtk.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/browser_window_gtk.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_theme_service.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_util.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/location_bar_view_gtk.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/resource_context.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/speech_recognition_manager.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents_view.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gtk_hig_constants.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/owned_widget_gtk.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/gtk_util.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBubbleControlVerticalSpacing = 5; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBubbleControlHorizontalSpacing = 20; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kIconHorizontalPadding = 10; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kButtonBarHorizontalSpacing = 10; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use black for text labels since the bubble has white background. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GdkColor& kLabelTextColor = ui::kGdkBlack; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implementation of SpeechRecognitionBubble for GTK. This shows a speech 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// recognition bubble on screen. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SpeechRecognitionBubbleGtk : public SpeechRecognitionBubbleBase, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public BubbleDelegateGtk { 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 48f5859ba46034e02ada5ef522d9d9c09fbbddccd8Ben Murdoch SpeechRecognitionBubbleGtk(int render_process_id, int render_view_id, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Delegate* delegate, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& element_rect); 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~SpeechRecognitionBubbleGtk(); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SpeechRecognitionBubbleBase: 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Show() OVERRIDE; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Hide() OVERRIDE; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void UpdateLayout() OVERRIDE; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void UpdateImage() OVERRIDE; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // BubbleDelegateGtk: 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void BubbleClosing(BubbleGtk* bubble, bool closed_by_escape) OVERRIDE; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHROMEGTK_CALLBACK_0(SpeechRecognitionBubbleGtk, void, OnCancelClicked); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHROMEGTK_CALLBACK_0(SpeechRecognitionBubbleGtk, void, OnTryAgainClicked); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHROMEGTK_CALLBACK_0(SpeechRecognitionBubbleGtk, void, OnMicSettingsClicked); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Delegate* delegate_; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BubbleGtk* bubble_; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect element_rect_; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool did_invoke_close_; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* label_; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* cancel_button_; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* try_again_button_; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* icon_; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* icon_container_; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* mic_settings_; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(SpeechRecognitionBubbleGtk); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpeechRecognitionBubbleGtk::SpeechRecognitionBubbleGtk( 83f5859ba46034e02ada5ef522d9d9c09fbbddccd8Ben Murdoch int render_process_id, int render_view_id, Delegate* delegate, 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& element_rect) 85f5859ba46034e02ada5ef522d9d9c09fbbddccd8Ben Murdoch : SpeechRecognitionBubbleBase(render_process_id, render_process_id), 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate_(delegate), 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bubble_(NULL), 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) element_rect_(element_rect), 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) did_invoke_close_(false), 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) label_(NULL), 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_button_(NULL), 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try_again_button_(NULL), 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_(NULL), 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_container_(NULL), 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mic_settings_(NULL) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpeechRecognitionBubbleGtk::~SpeechRecognitionBubbleGtk() { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The |Close| call below invokes our |BubbleClosing| method. Since we were 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // destroyed by the caller we don't need to call them back, hence set this 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // flag here. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) did_invoke_close_ = true; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Hide(); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpeechRecognitionBubbleGtk::OnCancelClicked(GtkWidget* widget) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate_->InfoBubbleButtonClicked(BUTTON_CANCEL); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpeechRecognitionBubbleGtk::OnTryAgainClicked(GtkWidget* widget) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate_->InfoBubbleButtonClicked(BUTTON_TRY_AGAIN); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpeechRecognitionBubbleGtk::OnMicSettingsClicked(GtkWidget* widget) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::SpeechRecognitionManager::GetInstance()->ShowAudioInputSettings(); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Hide(); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpeechRecognitionBubbleGtk::Show() { 120f5859ba46034e02ada5ef522d9d9c09fbbddccd8Ben Murdoch if (bubble_ || !GetWebContents()) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Nothing further to do since the bubble is already visible. 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use a vbox to arrange the controls (label, image, button bar) vertically 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and the button bar is a hbox holding the 2 buttons (try again and cancel). 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To get horizontal space around them we place this vbox with padding in a 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GtkAlignment below. 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* vbox = gtk_vbox_new(FALSE, 0); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The icon with a some padding on the left and right. 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_container_ = gtk_alignment_new(0, 0, 0, 0); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_ = gtk_image_new(); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_container_add(GTK_CONTAINER(icon_container_), icon_); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_box_pack_start(GTK_BOX(vbox), icon_container_, FALSE, FALSE, 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kBubbleControlVerticalSpacing); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) label_ = gtk_label_new(NULL); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_util::SetLabelColor(label_, &kLabelTextColor); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_box_pack_start(GTK_BOX(vbox), label_, FALSE, FALSE, 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kBubbleControlVerticalSpacing); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile = Profile::FromBrowserContext( 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetWebContents()->GetBrowserContext()); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(tommi): The audio_manager property can only be accessed from the 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IO thread, so we can't call CanShowAudioInputSettings directly here if 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we can show the input settings. For now, we always show the link (like 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we do on other platforms). 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (true) { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mic_settings_ = gtk_chrome_link_button_new( 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_SPEECH_INPUT_MIC_SETTINGS).c_str()); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_box_pack_start(GTK_BOX(vbox), mic_settings_, FALSE, FALSE, 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kBubbleControlVerticalSpacing); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(mic_settings_, "clicked", 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(&OnMicSettingsClickedThunk), this); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* button_bar = gtk_hbox_new(FALSE, kButtonBarHorizontalSpacing); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_box_pack_start(GTK_BOX(vbox), button_bar, FALSE, FALSE, 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kBubbleControlVerticalSpacing); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_button_ = gtk_button_new_with_label( 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_CANCEL).c_str()); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_box_pack_start(GTK_BOX(button_bar), cancel_button_, TRUE, FALSE, 0); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(cancel_button_, "clicked", 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(&OnCancelClickedThunk), this); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try_again_button_ = gtk_button_new_with_label( 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_SPEECH_INPUT_TRY_AGAIN).c_str()); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_box_pack_start(GTK_BOX(button_bar), try_again_button_, TRUE, FALSE, 0); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(try_again_button_, "clicked", 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(&OnTryAgainClickedThunk), this); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* content = gtk_alignment_new(0, 0, 0, 0); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_alignment_set_padding(GTK_ALIGNMENT(content), 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kBubbleControlVerticalSpacing, kBubbleControlVerticalSpacing, 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kBubbleControlHorizontalSpacing, kBubbleControlHorizontalSpacing); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_container_add(GTK_CONTAINER(content), vbox); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkThemeService* theme_provider = GtkThemeService::GetFrom(profile); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GtkWidget* reference_widget = GetWebContents()->GetView()->GetNativeView(); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect container_rect; 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetWebContents()->GetView()->GetContainerBounds(&container_rect); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect target_rect(element_rect_.right() - kBubbleTargetOffsetX, 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) element_rect_.bottom(), 1, 1); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (target_rect.x() < 0 || target_rect.y() < 0 || 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_rect.x() > container_rect.width() || 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_rect.y() > container_rect.height()) { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Target is not in screen view, so point to wrench. 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Browser* browser = chrome::FindBrowserWithWebContents(GetWebContents()); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserWindowGtk* browser_window = 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserWindowGtk::GetBrowserWindowForNativeWindow( 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) browser->window()->GetNativeWindow()); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reference_widget = browser_window->GetToolbar()->GetLocationBarView() 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ->location_icon_widget(); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_rect = gtk_util::WidgetBounds(reference_widget); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bubble_ = BubbleGtk::Show(reference_widget, 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &target_rect, 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content, 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BubbleGtk::ANCHOR_TOP_LEFT, 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) theme_provider, 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateLayout(); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpeechRecognitionBubbleGtk::Hide() { 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bubble_) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bubble_->Close(); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpeechRecognitionBubbleGtk::UpdateLayout() { 215f5859ba46034e02ada5ef522d9d9c09fbbddccd8Ben Murdoch if (!bubble_ || !GetWebContents()) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (display_mode() == DISPLAY_MODE_MESSAGE) { 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Message text and the Try Again + Cancel buttons are visible, hide the 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // icon. 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_label_set_text(GTK_LABEL(label_), 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UTF16ToUTF8(message_text()).c_str()); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show(label_); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show(try_again_button_); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mic_settings_) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show(mic_settings_); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_hide(icon_); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Heading text, icon and cancel button are visible, hide the Try Again 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // button. 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_label_set_text(GTK_LABEL(label_), 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_SPEECH_INPUT_BUBBLE_HEADING).c_str()); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (display_mode() == DISPLAY_MODE_RECORDING) { 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show(label_); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_hide(label_); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateImage(); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show(icon_); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_hide(try_again_button_); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mic_settings_) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_hide(mic_settings_); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (display_mode() == DISPLAY_MODE_WARM_UP) { 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_hide(cancel_button_); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The text label and cancel button are hidden in this mode, but we want 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the popup to appear the same size as it would once recording starts, 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so as to reduce UI jank when recording starts. So we calculate the 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // difference in size between the two sets of controls and add that as 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // padding around the icon here. 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkRequisition cancel_size; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_child_requisition(cancel_button_, &cancel_size); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkRequisition label_size; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_child_requisition(label_, &label_size); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia* volume = ResourceBundle::GetSharedInstance(). 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetImageSkiaNamed(IDR_SPEECH_INPUT_MIC_EMPTY); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int desired_width = std::max(volume->width(), cancel_size.width) + 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kIconHorizontalPadding * 2; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int desired_height = volume->height() + label_size.height + 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_size.height + 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kBubbleControlVerticalSpacing * 2; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int diff_width = desired_width - icon_image().width(); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int diff_height = desired_height - icon_image().height(); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_alignment_set_padding(GTK_ALIGNMENT(icon_container_), 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) diff_height / 2, diff_height - diff_height / 2, 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) diff_width / 2, diff_width - diff_width / 2); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reset the padding done above. 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_alignment_set_padding(GTK_ALIGNMENT(icon_container_), 0, 0, 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kIconHorizontalPadding, kIconHorizontalPadding); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show(cancel_button_); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpeechRecognitionBubbleGtk::UpdateImage() { 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia image = icon_image(); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (image.isNull() || !bubble_) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(*image.bitmap()); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), pixbuf); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_unref(pixbuf); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpeechRecognitionBubbleGtk::BubbleClosing(BubbleGtk* bubble, 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool closed_by_escape) { 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bubble_ = NULL; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!did_invoke_close_) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate_->InfoBubbleFocusChanged(); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpeechRecognitionBubble* SpeechRecognitionBubble::CreateNativeBubble( 296f5859ba46034e02ada5ef522d9d9c09fbbddccd8Ben Murdoch int render_process_id, int render_view_id, 297f5859ba46034e02ada5ef522d9d9c09fbbddccd8Ben Murdoch SpeechRecognitionBubble::Delegate* delegate, 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& element_rect) { 299f5859ba46034e02ada5ef522d9d9c09fbbddccd8Ben Murdoch return new SpeechRecognitionBubbleGtk(render_process_id, render_view_id, 300f5859ba46034e02ada5ef522d9d9c09fbbddccd8Ben Murdoch delegate, element_rect); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 302