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/fullscreen/fullscreen_exit_bubble.h" 6 7 #include "base/strings/utf_string_conversions.h" 8 #include "chrome/app/chrome_command_ids.h" 9 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/ui/browser.h" 11 #include "chrome/browser/ui/browser_commands.h" 12 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h" 13 #include "grit/generated_resources.h" 14 #include "grit/ui_strings.h" 15 #include "ui/base/l10n/l10n_util.h" 16 #include "ui/gfx/rect.h" 17 18 // NOTE(koz): Linux doesn't use the thick shadowed border, so we add padding 19 // here. 20 #if defined(OS_LINUX) 21 const int FullscreenExitBubble::kPaddingPx = 8; 22 #else 23 const int FullscreenExitBubble::kPaddingPx = 15; 24 #endif 25 const int FullscreenExitBubble::kInitialDelayMs = 3800; 26 const int FullscreenExitBubble::kIdleTimeMs = 2300; 27 const int FullscreenExitBubble::kPositionCheckHz = 10; 28 const int FullscreenExitBubble::kSlideInRegionHeightPx = 4; 29 const int FullscreenExitBubble::kSlideInDurationMs = 350; 30 const int FullscreenExitBubble::kSlideOutDurationMs = 700; 31 const int FullscreenExitBubble::kPopupTopPx = 15; 32 33 FullscreenExitBubble::FullscreenExitBubble(Browser* browser, 34 const GURL& url, 35 FullscreenExitBubbleType bubble_type) 36 : browser_(browser), 37 url_(url), 38 bubble_type_(bubble_type) { 39 DCHECK_NE(FEB_TYPE_NONE, bubble_type_); 40 } 41 42 FullscreenExitBubble::~FullscreenExitBubble() { 43 } 44 45 void FullscreenExitBubble::StartWatchingMouse() { 46 // Start the initial delay timer and begin watching the mouse. 47 initial_delay_.Start(FROM_HERE, 48 base::TimeDelta::FromMilliseconds(kInitialDelayMs), this, 49 &FullscreenExitBubble::CheckMousePosition); 50 gfx::Point cursor_pos = GetCursorScreenPoint(); 51 last_mouse_pos_ = cursor_pos; 52 mouse_position_checker_.Start(FROM_HERE, 53 base::TimeDelta::FromMilliseconds(1000 / kPositionCheckHz), this, 54 &FullscreenExitBubble::CheckMousePosition); 55 } 56 57 void FullscreenExitBubble::StopWatchingMouse() { 58 initial_delay_.Stop(); 59 idle_timeout_.Stop(); 60 mouse_position_checker_.Stop(); 61 } 62 63 bool FullscreenExitBubble::IsWatchingMouse() const { 64 return mouse_position_checker_.IsRunning(); 65 } 66 67 void FullscreenExitBubble::CheckMousePosition() { 68 // Desired behavior: 69 // 70 // +------------+-----------------------------+------------+ 71 // | _ _ _ _ | Exit full screen mode (F11) | _ _ _ _ | Slide-in region 72 // | _ _ _ _ \_____________________________/ _ _ _ _ | Neutral region 73 // | | Slide-out region 74 // : : 75 // 76 // * If app is not active, we hide the popup. 77 // * If the mouse is offscreen or in the slide-out region, we hide the popup. 78 // * If the mouse goes idle, we hide the popup. 79 // * If the mouse is in the slide-in-region and not idle, we show the popup. 80 // * If the mouse is in the neutral region and not idle, and the popup is 81 // currently sliding out, we show it again. This facilitates users 82 // correcting us if they try to mouse horizontally towards the popup and 83 // unintentionally drop too low. 84 // * Otherwise, we do nothing, because the mouse is in the neutral region and 85 // either the popup is hidden or the mouse is not idle, so we don't want to 86 // change anything's state. 87 88 gfx::Point cursor_pos = GetCursorScreenPoint(); 89 90 // Check to see whether the mouse is idle. 91 if (cursor_pos != last_mouse_pos_) { 92 // The mouse moved; reset the idle timer. 93 idle_timeout_.Stop(); // If the timer isn't running, this is a no-op. 94 idle_timeout_.Start(FROM_HERE, 95 base::TimeDelta::FromMilliseconds(kIdleTimeMs), this, 96 &FullscreenExitBubble::CheckMousePosition); 97 } 98 last_mouse_pos_ = cursor_pos; 99 100 if (!IsWindowActive() || 101 !WindowContainsPoint(cursor_pos) || 102 (cursor_pos.y() >= GetPopupRect(true).bottom()) || 103 !idle_timeout_.IsRunning()) { 104 // The cursor is offscreen, in the slide-out region, or idle. 105 if (!initial_delay_.IsRunning()) { 106 Hide(); 107 } 108 } else if (cursor_pos.y() < kSlideInRegionHeightPx && 109 CanMouseTriggerSlideIn()) { 110 Show(); 111 } else if (IsAnimating()) { 112 // The cursor is not idle and either it's in the slide-in region or it's in 113 // the neutral region and we're sliding in or out. 114 Show(); 115 } 116 } 117 118 void FullscreenExitBubble::ToggleFullscreen() { 119 browser_->fullscreen_controller()-> 120 ExitTabOrBrowserFullscreenToPreviousState(); 121 } 122 123 void FullscreenExitBubble::Accept() { 124 browser_->fullscreen_controller()->OnAcceptFullscreenPermission(); 125 } 126 127 void FullscreenExitBubble::Cancel() { 128 browser_->fullscreen_controller()->OnDenyFullscreenPermission(); 129 } 130 131 base::string16 FullscreenExitBubble::GetCurrentMessageText() const { 132 return fullscreen_bubble::GetLabelTextForType( 133 bubble_type_, url_, browser_->profile()->GetExtensionService()); 134 } 135 136 base::string16 FullscreenExitBubble::GetCurrentDenyButtonText() const { 137 return fullscreen_bubble::GetDenyButtonTextForType(bubble_type_); 138 } 139 140 base::string16 FullscreenExitBubble::GetAllowButtonText() const { 141 return l10n_util::GetStringUTF16(IDS_FULLSCREEN_ALLOW); 142 } 143 144 base::string16 FullscreenExitBubble::GetInstructionText() const { 145 return l10n_util::GetStringFUTF16(IDS_FULLSCREEN_PRESS_ESC_TO_EXIT, 146 l10n_util::GetStringUTF16(IDS_APP_ESC_KEY)); 147 } 148