Home | History | Annotate | Download | only in panels
      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