blob: b4c3d299689a59dd293e8c321c2dca3a0c417c97 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/panels/display_settings_provider_win.h"
#include <shellapi.h>
#include "base/logging.h"
#include "ui/views/widget/monitor_win.h"
namespace {
// The thickness of the area of an auto-hiding taskbar that is still visible
// when the taskbar becomes hidden.
const int kHiddenAutoHideTaskbarThickness = 2;
// The polling interval to check auto-hiding taskbars.
const int kCheckTaskbarPollingIntervalMs = 500;
} // namespace
DisplaySettingsProviderWin::DisplaySettingsProviderWin()
: monitor_(NULL) {
memset(taskbars_, 0, sizeof(taskbars_));
}
DisplaySettingsProviderWin::~DisplaySettingsProviderWin() {
}
void DisplaySettingsProviderWin::OnDisplaySettingsChanged() {
DisplaySettingsProvider::OnDisplaySettingsChanged();
RECT rect = work_area().ToRECT();
monitor_ = ::MonitorFromRect(&rect, MONITOR_DEFAULTTOPRIMARY);
DCHECK(monitor_);
bool taskbar_exists = CheckTaskbars(false);
// If no auto-hiding taskbar exists, we do not need to start the polling
// timer. If a taskbar is then set to auto-hiding, UpdateWorkArea will be
// called due to the work area change.
if (taskbar_exists) {
if (!polling_timer_.IsRunning()) {
polling_timer_.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(kCheckTaskbarPollingIntervalMs),
this,
&DisplaySettingsProviderWin::OnPollingTimer);
}
} else {
if (polling_timer_.IsRunning())
polling_timer_.Stop();
}
}
bool DisplaySettingsProviderWin::IsAutoHidingDesktopBarEnabled(
DesktopBarAlignment alignment) {
CheckTaskbars(false);
return taskbars_[static_cast<int>(alignment)].window != NULL;
}
int DisplaySettingsProviderWin::GetDesktopBarThickness(
DesktopBarAlignment alignment) const {
return GetDesktopBarThicknessFromBounds(alignment, GetBounds(alignment));
}
DisplaySettingsProvider::DesktopBarVisibility
DisplaySettingsProviderWin::GetDesktopBarVisibility(
DesktopBarAlignment alignment) const {
return GetDesktopBarVisibilityFromBounds(alignment, GetBounds(alignment));
}
gfx::Rect DisplaySettingsProviderWin::GetBounds(
DesktopBarAlignment alignment) const {
HWND taskbar_window = taskbars_[static_cast<int>(alignment)].window;
if (!taskbar_window)
return gfx::Rect();
RECT rect;
if (!::GetWindowRect(taskbar_window, &rect))
return gfx::Rect();
return gfx::Rect(rect);
}
int DisplaySettingsProviderWin::GetDesktopBarThicknessFromBounds(
DesktopBarAlignment alignment,
const gfx::Rect& taskbar_bounds) const {
switch (alignment) {
case DESKTOP_BAR_ALIGNED_BOTTOM:
return taskbar_bounds.height();
case DESKTOP_BAR_ALIGNED_LEFT:
case DESKTOP_BAR_ALIGNED_RIGHT:
return taskbar_bounds.width();
default:
NOTREACHED();
return 0;
}
}
DisplaySettingsProvider::DesktopBarVisibility
DisplaySettingsProviderWin::GetDesktopBarVisibilityFromBounds(
DesktopBarAlignment alignment,
const gfx::Rect& taskbar_bounds) const {
switch (alignment) {
case DESKTOP_BAR_ALIGNED_BOTTOM:
if (taskbar_bounds.bottom() <= work_area().bottom())
return DESKTOP_BAR_VISIBLE;
else if (taskbar_bounds.y() >=
work_area().bottom() - kHiddenAutoHideTaskbarThickness)
return DESKTOP_BAR_HIDDEN;
else
return DESKTOP_BAR_ANIMATING;
case DESKTOP_BAR_ALIGNED_LEFT:
if (taskbar_bounds.x() >= work_area().x())
return DESKTOP_BAR_VISIBLE;
else if (taskbar_bounds.right() <=
work_area().x() + kHiddenAutoHideTaskbarThickness)
return DESKTOP_BAR_HIDDEN;
else
return DESKTOP_BAR_ANIMATING;
case DESKTOP_BAR_ALIGNED_RIGHT:
if (taskbar_bounds.right() <= work_area().right())
return DESKTOP_BAR_VISIBLE;
else if (taskbar_bounds.x() >=
work_area().right() - kHiddenAutoHideTaskbarThickness)
return DESKTOP_BAR_HIDDEN;
else
return DESKTOP_BAR_ANIMATING;
default:
NOTREACHED();
return DESKTOP_BAR_VISIBLE;
}
}
void DisplaySettingsProviderWin::OnPollingTimer() {
CheckTaskbars(true);
}
bool DisplaySettingsProviderWin::CheckTaskbars(bool notify_observer) {
bool taskbar_exists = false;
UINT edges[] = { ABE_BOTTOM, ABE_LEFT, ABE_RIGHT };
for (size_t i = 0; i < kMaxTaskbars; ++i) {
taskbars_[i].window =
views::GetTopmostAutoHideTaskbarForEdge(edges[i], monitor_);
if (taskbars_[i].window)
taskbar_exists = true;
}
if (!taskbar_exists) {
for (size_t i = 0; i < kMaxTaskbars; ++i) {
taskbars_[i].thickness = 0;
taskbars_[i].visibility = DESKTOP_BAR_HIDDEN;
}
return false;
}
bool thickness_changed = false;
for (size_t i = 0; i < kMaxTaskbars; ++i) {
DesktopBarAlignment alignment = static_cast<DesktopBarAlignment>(i);
gfx::Rect bounds = GetBounds(alignment);
// Check the thickness change.
int thickness = GetDesktopBarThicknessFromBounds(alignment, bounds);
if (thickness != taskbars_[i].thickness) {
taskbars_[i].thickness = thickness;
thickness_changed = true;
}
// Check and notify the visibility change.
DesktopBarVisibility visibility = GetDesktopBarVisibilityFromBounds(
alignment, bounds);
if (visibility != taskbars_[i].visibility) {
taskbars_[i].visibility = visibility;
if (notify_observer) {
FOR_EACH_OBSERVER(
DesktopBarObserver,
desktop_bar_observers(),
OnAutoHidingDesktopBarVisibilityChanged(alignment, visibility));
}
}
}
if (thickness_changed)
OnAutoHidingDesktopBarChanged();
return true;
}
// static
DisplaySettingsProvider* DisplaySettingsProvider::Create() {
return new DisplaySettingsProviderWin();
}