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/panels/display_settings_provider_win.h" 6 7 #include <shellapi.h> 8 9 #include "base/logging.h" 10 #include "ui/views/widget/monitor_win.h" 11 12 namespace { 13 // The thickness of the area of an auto-hiding taskbar that is still visible 14 // when the taskbar becomes hidden. 15 const int kHiddenAutoHideTaskbarThickness = 2; 16 17 // The polling interval to check auto-hiding taskbars. 18 const int kCheckTaskbarPollingIntervalMs = 500; 19 } // namespace 20 21 DisplaySettingsProviderWin::DisplaySettingsProviderWin() 22 : monitor_(NULL) { 23 memset(taskbars_, 0, sizeof(taskbars_)); 24 } 25 26 DisplaySettingsProviderWin::~DisplaySettingsProviderWin() { 27 } 28 29 void DisplaySettingsProviderWin::OnDisplaySettingsChanged() { 30 DisplaySettingsProvider::OnDisplaySettingsChanged(); 31 32 gfx::Rect primary_work_area = GetPrimaryWorkArea(); 33 RECT rect = primary_work_area.ToRECT(); 34 monitor_ = ::MonitorFromRect(&rect, MONITOR_DEFAULTTOPRIMARY); 35 DCHECK(monitor_); 36 37 bool taskbar_exists = CheckTaskbars(false); 38 39 // If no auto-hiding taskbar exists, we do not need to start the polling 40 // timer. If a taskbar is then set to auto-hiding, UpdateWorkArea will be 41 // called due to the work area change. 42 if (taskbar_exists) { 43 if (!polling_timer_.IsRunning()) { 44 polling_timer_.Start(FROM_HERE, 45 base::TimeDelta::FromMilliseconds(kCheckTaskbarPollingIntervalMs), 46 this, 47 &DisplaySettingsProviderWin::OnPollingTimer); 48 } 49 } else { 50 if (polling_timer_.IsRunning()) 51 polling_timer_.Stop(); 52 } 53 } 54 55 bool DisplaySettingsProviderWin::IsAutoHidingDesktopBarEnabled( 56 DesktopBarAlignment alignment) { 57 CheckTaskbars(false); 58 return taskbars_[static_cast<int>(alignment)].window != NULL; 59 } 60 61 int DisplaySettingsProviderWin::GetDesktopBarThickness( 62 DesktopBarAlignment alignment) const { 63 return GetDesktopBarThicknessFromBounds(alignment, GetBounds(alignment)); 64 } 65 66 DisplaySettingsProvider::DesktopBarVisibility 67 DisplaySettingsProviderWin::GetDesktopBarVisibility( 68 DesktopBarAlignment alignment) const { 69 return GetDesktopBarVisibilityFromBounds(alignment, GetBounds(alignment)); 70 } 71 72 gfx::Rect DisplaySettingsProviderWin::GetBounds( 73 DesktopBarAlignment alignment) const { 74 HWND taskbar_window = taskbars_[static_cast<int>(alignment)].window; 75 if (!taskbar_window) 76 return gfx::Rect(); 77 78 RECT rect; 79 if (!::GetWindowRect(taskbar_window, &rect)) 80 return gfx::Rect(); 81 return gfx::Rect(rect); 82 } 83 84 int DisplaySettingsProviderWin::GetDesktopBarThicknessFromBounds( 85 DesktopBarAlignment alignment, 86 const gfx::Rect& taskbar_bounds) const { 87 switch (alignment) { 88 case DESKTOP_BAR_ALIGNED_BOTTOM: 89 return taskbar_bounds.height(); 90 case DESKTOP_BAR_ALIGNED_LEFT: 91 case DESKTOP_BAR_ALIGNED_RIGHT: 92 return taskbar_bounds.width(); 93 default: 94 NOTREACHED(); 95 return 0; 96 } 97 } 98 99 DisplaySettingsProvider::DesktopBarVisibility 100 DisplaySettingsProviderWin::GetDesktopBarVisibilityFromBounds( 101 DesktopBarAlignment alignment, 102 const gfx::Rect& taskbar_bounds) const { 103 gfx::Rect primary_work_area = GetPrimaryWorkArea(); 104 switch (alignment) { 105 case DESKTOP_BAR_ALIGNED_BOTTOM: 106 if (taskbar_bounds.bottom() <= primary_work_area.bottom()) 107 return DESKTOP_BAR_VISIBLE; 108 else if (taskbar_bounds.y() >= 109 primary_work_area.bottom() - kHiddenAutoHideTaskbarThickness) 110 return DESKTOP_BAR_HIDDEN; 111 else 112 return DESKTOP_BAR_ANIMATING; 113 114 case DESKTOP_BAR_ALIGNED_LEFT: 115 if (taskbar_bounds.x() >= primary_work_area.x()) 116 return DESKTOP_BAR_VISIBLE; 117 else if (taskbar_bounds.right() <= 118 primary_work_area.x() + kHiddenAutoHideTaskbarThickness) 119 return DESKTOP_BAR_HIDDEN; 120 else 121 return DESKTOP_BAR_ANIMATING; 122 123 case DESKTOP_BAR_ALIGNED_RIGHT: 124 if (taskbar_bounds.right() <= primary_work_area.right()) 125 return DESKTOP_BAR_VISIBLE; 126 else if (taskbar_bounds.x() >= 127 primary_work_area.right() - kHiddenAutoHideTaskbarThickness) 128 return DESKTOP_BAR_HIDDEN; 129 else 130 return DESKTOP_BAR_ANIMATING; 131 132 default: 133 NOTREACHED(); 134 return DESKTOP_BAR_VISIBLE; 135 } 136 } 137 138 void DisplaySettingsProviderWin::OnPollingTimer() { 139 CheckTaskbars(true); 140 } 141 142 bool DisplaySettingsProviderWin::CheckTaskbars(bool notify_observer) { 143 bool taskbar_exists = false; 144 UINT edges[] = { ABE_BOTTOM }; 145 for (size_t i = 0; i < kMaxTaskbars; ++i) { 146 taskbars_[i].window = 147 views::GetTopmostAutoHideTaskbarForEdge(edges[i], monitor_); 148 if (taskbars_[i].window) 149 taskbar_exists = true; 150 } 151 if (!taskbar_exists) { 152 for (size_t i = 0; i < kMaxTaskbars; ++i) { 153 taskbars_[i].thickness = 0; 154 taskbars_[i].visibility = DESKTOP_BAR_HIDDEN; 155 } 156 return false; 157 } 158 159 for (size_t i = 0; i < kMaxTaskbars; ++i) { 160 DesktopBarAlignment alignment = static_cast<DesktopBarAlignment>(i); 161 162 gfx::Rect bounds = GetBounds(alignment); 163 164 // Check the thickness change. 165 int thickness = GetDesktopBarThicknessFromBounds(alignment, bounds); 166 if (thickness != taskbars_[i].thickness) { 167 taskbars_[i].thickness = thickness; 168 if (notify_observer) { 169 FOR_EACH_OBSERVER( 170 DesktopBarObserver, 171 desktop_bar_observers(), 172 OnAutoHidingDesktopBarThicknessChanged(alignment, thickness)); 173 } 174 } 175 176 // Check and notify the visibility change. 177 DesktopBarVisibility visibility = GetDesktopBarVisibilityFromBounds( 178 alignment, bounds); 179 if (visibility != taskbars_[i].visibility) { 180 taskbars_[i].visibility = visibility; 181 if (notify_observer) { 182 FOR_EACH_OBSERVER( 183 DesktopBarObserver, 184 desktop_bar_observers(), 185 OnAutoHidingDesktopBarVisibilityChanged(alignment, visibility)); 186 } 187 } 188 } 189 190 return true; 191 } 192 193 // static 194 DisplaySettingsProvider* DisplaySettingsProvider::Create() { 195 return new DisplaySettingsProviderWin(); 196 } 197