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/fullscreen_exit_bubble_gtk.h"
      6 
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "chrome/browser/chrome_notification_types.h"
      9 #include "chrome/browser/ui/browser.h"
     10 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
     11 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
     12 #include "chrome/browser/ui/gtk/gtk_util.h"
     13 #include "chrome/browser/ui/gtk/rounded_window.h"
     14 #include "content/public/browser/notification_source.h"
     15 #include "content/public/browser/render_widget_host_view.h"
     16 #include "grit/generated_resources.h"
     17 #include "grit/ui_strings.h"
     18 #include "ui/base/gtk/gtk_floating_container.h"
     19 #include "ui/base/gtk/gtk_hig_constants.h"
     20 #include "ui/base/l10n/l10n_util.h"
     21 
     22 namespace {
     23 
     24 const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xff, 0xff, 0xff);
     25 const GdkColor kFrameColor = GDK_COLOR_RGB(0x63, 0x63, 0x63);
     26 const int kMiddlePaddingPx = 30;
     27 
     28 }  // namespace
     29 
     30 FullscreenExitBubbleGtk::FullscreenExitBubbleGtk(
     31     GtkFloatingContainer* container,
     32     Browser* browser,
     33     const GURL& url,
     34     FullscreenExitBubbleType bubble_type)
     35     : FullscreenExitBubble(browser, url, bubble_type),
     36       theme_service_(NULL),
     37       bubble_(NULL),
     38       container_(container) {
     39   InitWidgets();
     40 }
     41 
     42 FullscreenExitBubbleGtk::~FullscreenExitBubbleGtk() {
     43 }
     44 
     45 void FullscreenExitBubbleGtk::UpdateContent(
     46     const GURL& url,
     47     FullscreenExitBubbleType bubble_type) {
     48   if (bubble_type == FEB_TYPE_NONE) {
     49     NOTREACHED();
     50     bubble_type = FEB_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION;
     51   }
     52 
     53   url_ = url;
     54   bubble_type_ = bubble_type;
     55 
     56   gtk_label_set_text(GTK_LABEL(message_label_),
     57                      UTF16ToUTF8(GetCurrentMessageText()).c_str());
     58   if (fullscreen_bubble::ShowButtonsForType(bubble_type)) {
     59     gtk_widget_hide(link_);
     60     gtk_widget_hide(instruction_label_);
     61     gtk_widget_show(allow_button_);
     62     gtk_button_set_label(GTK_BUTTON(deny_button_),
     63                          UTF16ToUTF8(GetCurrentDenyButtonText()).c_str());
     64     gtk_widget_show(deny_button_);
     65   } else {
     66     bool link_visible = true;
     67     string16 accelerator;
     68     if (bubble_type == FEB_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION ||
     69         bubble_type ==
     70             FEB_TYPE_BROWSER_EXTENSION_FULLSCREEN_EXIT_INSTRUCTION) {
     71       accelerator = l10n_util::GetStringUTF16(IDS_APP_F11_KEY);
     72     } else if (bubble_type == FEB_TYPE_FULLSCREEN_EXIT_INSTRUCTION) {
     73       accelerator = l10n_util::GetStringUTF16(IDS_APP_ESC_KEY);
     74     } else {
     75       link_visible = false;
     76     }
     77     if (link_visible) {
     78       std::string exit_link_text(
     79           l10n_util::GetStringUTF8(IDS_EXIT_FULLSCREEN_MODE) + " " +
     80           l10n_util::GetStringFUTF8(IDS_EXIT_FULLSCREEN_MODE_ACCELERATOR,
     81               accelerator));
     82       gtk_chrome_link_button_set_label(GTK_CHROME_LINK_BUTTON(link_),
     83           exit_link_text.c_str());
     84       gtk_widget_show(link_);
     85       gtk_widget_hide(instruction_label_);
     86     } else {
     87       gtk_widget_hide(link_);
     88       gtk_widget_show(instruction_label_);
     89     }
     90     gtk_widget_hide(allow_button_);
     91     gtk_widget_hide(deny_button_);
     92   }
     93 
     94   Show();
     95   StopWatchingMouse();
     96   StartWatchingMouseIfNecessary();
     97 }
     98 
     99 void FullscreenExitBubbleGtk::InitWidgets() {
    100   theme_service_ = GtkThemeService::GetFrom(browser_->profile());
    101 
    102   hbox_ = gtk_hbox_new(false, ui::kControlSpacing);
    103 
    104   message_label_ = theme_service_->BuildLabel(GetMessage(url_).c_str(),
    105                                               ui::kGdkBlack);
    106   gtk_box_pack_start(GTK_BOX(hbox_), message_label_, FALSE, FALSE, 0);
    107 
    108   allow_button_ = gtk_button_new_with_label(
    109       l10n_util::GetStringUTF8(IDS_FULLSCREEN_ALLOW).c_str());
    110   gtk_widget_set_can_focus(allow_button_, FALSE);
    111   gtk_widget_set_no_show_all(allow_button_, FALSE);
    112   gtk_box_pack_start(GTK_BOX(hbox_), allow_button_, FALSE, FALSE, 0);
    113 
    114   deny_button_ = gtk_button_new_with_label(
    115       l10n_util::GetStringUTF8(IDS_FULLSCREEN_DENY).c_str());
    116   gtk_widget_set_can_focus(deny_button_, FALSE);
    117   gtk_widget_set_no_show_all(deny_button_, FALSE);
    118   gtk_box_pack_start(GTK_BOX(hbox_), deny_button_, FALSE, FALSE, 0);
    119 
    120   link_ = gtk_chrome_link_button_new("");
    121   gtk_widget_set_can_focus(link_, FALSE);
    122   gtk_widget_set_no_show_all(link_, FALSE);
    123   gtk_chrome_link_button_set_use_gtk_theme(GTK_CHROME_LINK_BUTTON(link_),
    124                                            FALSE);
    125   gtk_box_pack_start(GTK_BOX(hbox_), link_, FALSE, FALSE, 0);
    126 
    127   instruction_label_ = gtk_label_new(UTF16ToUTF8(GetInstructionText()).c_str());
    128   gtk_widget_set_no_show_all(instruction_label_, FALSE);
    129   gtk_box_pack_start(GTK_BOX(hbox_), instruction_label_, FALSE, FALSE, 0);
    130 
    131   bubble_ = gtk_util::CreateGtkBorderBin(
    132       hbox_, &ui::kGdkWhite,
    133       kPaddingPx, kPaddingPx, kPaddingPx, kPaddingPx);
    134   gtk_util::ActAsRoundedWindow(bubble_, kFrameColor, 3,
    135       gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL);
    136   GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
    137   gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 5, 0, 0, 0);
    138   gtk_container_add(GTK_CONTAINER(alignment), bubble_);
    139   ui_container_.Own(alignment);
    140 
    141   slide_widget_.reset(new SlideAnimatorGtk(ui_container_.get(),
    142       SlideAnimatorGtk::DOWN, kSlideOutDurationMs, false, false, NULL));
    143   gtk_widget_set_name(widget(), "exit-fullscreen-bubble");
    144   gtk_widget_show_all(ui_container_.get());
    145   gtk_widget_show(widget());
    146   slide_widget_->OpenWithoutAnimation();
    147 
    148   gtk_floating_container_add_floating(GTK_FLOATING_CONTAINER(container_),
    149                                       widget());
    150 
    151   signals_.Connect(container_, "set-floating-position",
    152                    G_CALLBACK(OnSetFloatingPositionThunk), this);
    153   signals_.Connect(link_, "clicked", G_CALLBACK(OnLinkClickedThunk), this);
    154   signals_.Connect(allow_button_, "clicked",
    155                    G_CALLBACK(&OnAllowClickedThunk), this);
    156   signals_.Connect(deny_button_, "clicked",
    157                    G_CALLBACK(&OnDenyClickedThunk), this);
    158 
    159   UpdateContent(url_, bubble_type_);
    160 
    161   theme_service_->InitThemesFor(this);
    162   registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
    163                  content::Source<ThemeService>(theme_service_));
    164 }
    165 
    166 std::string FullscreenExitBubbleGtk::GetMessage(const GURL& url) {
    167   if (url.is_empty())
    168     return l10n_util::GetStringUTF8(IDS_FULLSCREEN_USER_ENTERED_FULLSCREEN);
    169 
    170   if (url.SchemeIsFile())
    171     return l10n_util::GetStringUTF8(IDS_FULLSCREEN_ENTERED_FULLSCREEN);
    172   return l10n_util::GetStringFUTF8(IDS_FULLSCREEN_SITE_ENTERED_FULLSCREEN,
    173       UTF8ToUTF16(url.host()));
    174 }
    175 
    176 gfx::Rect FullscreenExitBubbleGtk::GetPopupRect(
    177     bool ignore_animation_state) const {
    178   GtkRequisition bubble_size;
    179   if (ignore_animation_state) {
    180     gtk_widget_size_request(ui_container_.get(), &bubble_size);
    181   } else {
    182     gtk_widget_size_request(widget(), &bubble_size);
    183   }
    184   return gfx::Rect(bubble_size.width, bubble_size.height);
    185 }
    186 
    187 gfx::Point FullscreenExitBubbleGtk::GetCursorScreenPoint() {
    188   GdkDisplay* display = gtk_widget_get_display(widget());
    189 
    190   // Get cursor position.
    191   // TODO: this hits the X server, so we may want to consider decreasing
    192   // kPositionCheckHz if we detect that we're running remotely.
    193   int x, y;
    194   gdk_display_get_pointer(display, NULL, &x, &y, NULL);
    195 
    196   return gfx::Point(x, y);
    197 }
    198 
    199 bool FullscreenExitBubbleGtk::WindowContainsPoint(gfx::Point pos) {
    200   GtkWindow* window = GTK_WINDOW(
    201       gtk_widget_get_ancestor(widget(), GTK_TYPE_WINDOW));
    202   int width, height, x, y;
    203   gtk_window_get_size(window, &width, &height);
    204   gtk_window_get_position(window, &x, &y);
    205   return gfx::Rect(x, y, width, height).Contains(pos);
    206 }
    207 
    208 bool FullscreenExitBubbleGtk::IsWindowActive() {
    209   if (!gtk_widget_get_parent(widget()))
    210     return false;
    211   GtkWindow* window = GTK_WINDOW(
    212       gtk_widget_get_ancestor(widget(), GTK_TYPE_WINDOW));
    213   return gtk_window_is_active(window);
    214 }
    215 
    216 void FullscreenExitBubbleGtk::Hide() {
    217   slide_widget_->Close();
    218 }
    219 
    220 void FullscreenExitBubbleGtk::Show() {
    221   slide_widget_->Open();
    222 }
    223 
    224 bool FullscreenExitBubbleGtk::IsAnimating() {
    225   return slide_widget_->IsAnimating();
    226 }
    227 
    228 bool FullscreenExitBubbleGtk::CanMouseTriggerSlideIn() const {
    229   return true;
    230 }
    231 
    232 void FullscreenExitBubbleGtk::StartWatchingMouseIfNecessary() {
    233   if (!fullscreen_bubble::ShowButtonsForType(bubble_type_))
    234     StartWatchingMouse();
    235 }
    236 
    237 void FullscreenExitBubbleGtk::OnSetFloatingPosition(
    238     GtkWidget* floating_container,
    239     GtkAllocation* allocation) {
    240   GtkRequisition bubble_size;
    241   gtk_widget_size_request(widget(), &bubble_size);
    242 
    243   // Position the bubble at the top center of the screen.
    244   GValue value = { 0, };
    245   g_value_init(&value, G_TYPE_INT);
    246   g_value_set_int(&value, (allocation->width - bubble_size.width) / 2);
    247   gtk_container_child_set_property(GTK_CONTAINER(floating_container),
    248                                    widget(), "x", &value);
    249 
    250   g_value_set_int(&value, 0);
    251   gtk_container_child_set_property(GTK_CONTAINER(floating_container),
    252                                    widget(), "y", &value);
    253   g_value_unset(&value);
    254 }
    255 
    256 void FullscreenExitBubbleGtk::OnLinkClicked(GtkWidget* link) {
    257   ToggleFullscreen();
    258 }
    259 
    260 void FullscreenExitBubbleGtk::OnAllowClicked(GtkWidget* button) {
    261   Accept();
    262 }
    263 
    264 void FullscreenExitBubbleGtk::OnDenyClicked(GtkWidget* button) {
    265   Cancel();
    266 }
    267 
    268 void FullscreenExitBubbleGtk::Observe(
    269     int type,
    270     const content::NotificationSource& source,
    271     const content::NotificationDetails& details) {
    272   DCHECK_EQ(type, chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
    273   if (theme_service_->UsingNativeTheme())
    274     gtk_widget_modify_bg(bubble_, GTK_STATE_NORMAL, NULL);
    275   else
    276     gtk_widget_modify_bg(bubble_, GTK_STATE_NORMAL, &kBackgroundColor);
    277 }
    278