1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127

ash / shelf / shelf_window_targeter.cc [blame]

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/shelf/shelf_window_targeter.h"

#include "ash/public/cpp/session/session_types.h"
#include "ash/public/cpp/shelf_config.h"
#include "ash/public/cpp/shelf_types.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
#include "ui/aura/window.h"

namespace ash {

namespace {

gfx::Insets GetInsetsForAlignment(int distance, ShelfAlignment alignment) {
  if (alignment == ShelfAlignment::kLeft) {
    return gfx::Insets::TLBR(0, 0, 0, distance);
  }

  if (alignment == ShelfAlignment::kRight) {
    return gfx::Insets::TLBR(0, distance, 0, 0);
  }

  return gfx::Insets::TLBR(distance, 0, 0, 0);
}

}  // namespace

ShelfWindowTargeter::ShelfWindowTargeter(aura::Window* container, Shelf* shelf)
    : ::wm::EasyResizeWindowTargeter(gfx::Insets(), gfx::Insets()),
      shelf_(shelf) {
  UpdateInsetsForVisibilityState(shelf_->GetVisibilityState());
  container->AddObserver(this);
  shelf_->AddObserver(this);
  Shell::Get()->AddShellObserver(this);
}

ShelfWindowTargeter::~ShelfWindowTargeter() {
  // Ensure that the observers were removed and the shelf pointer was cleared.
  DCHECK(!shelf_);

  Shell::Get()->RemoveShellObserver(this);
}

bool ShelfWindowTargeter::ShouldUseExtendedBounds(const aura::Window* w) const {
  // Use extended bounds only for direct child of the container.
  return window() == w->parent();
}

bool ShelfWindowTargeter::GetHitTestRects(
    aura::Window* target,
    gfx::Rect* hit_test_rect_mouse,
    gfx::Rect* hit_test_rect_touch) const {
  bool target_is_shelf_widget =
      target == shelf_->shelf_widget()->GetNativeWindow();
  *hit_test_rect_mouse = *hit_test_rect_touch = target->bounds();

  if (ShouldUseExtendedBounds(target)) {
    hit_test_rect_mouse->Inset(mouse_extend());

    // Whether the touch hit area should be extended beyond the window top when
    // the shelf is in auto-hide state (to make targeting hidden shelf easier).
    // This should be applied for shelf widget  only, to prevent other widgets
    // positioned below display bounds (e.g. hidden hotseat widget) from
    // handling touch events instead of the shelf.
    if (target_is_shelf_widget)
      hit_test_rect_touch->Inset(touch_extend());
  }
  return true;
}

void ShelfWindowTargeter::OnWindowDestroying(aura::Window* window) {
  window->RemoveObserver(this);
  shelf_->RemoveObserver(this);
  shelf_ = nullptr;
}

void ShelfWindowTargeter::OnShelfAlignmentChanged(
    aura::Window* root_window,
    ShelfAlignment old_alignment) {
  if (!shelf_) {
    return;
  }
  if (shelf_->shelf_widget()->GetNativeWindow()->GetRootWindow() !=
      root_window) {
    return;
  }

  UpdateInsets();
}

void ShelfWindowTargeter::OnShelfVisibilityStateChanged(
    ShelfVisibilityState new_state) {
  UpdateInsetsForVisibilityState(new_state);
}

void ShelfWindowTargeter::UpdateInsetsForVisibilityState(
    ShelfVisibilityState state) {
  mouse_inset_size_for_shelf_visibility_ =
      state == SHELF_VISIBLE
          ? ShelfConfig::Get()->workspace_area_visible_inset()
          : 0;
  touch_inset_size_for_shelf_visibility_ =
      state == SHELF_AUTO_HIDE
          ? -ShelfConfig::Get()->workspace_area_auto_hide_inset()
          : 0;

  UpdateInsets();
}

void ShelfWindowTargeter::UpdateInsets() {
  const gfx::Insets mouse_insets = GetInsetsForAlignment(
      mouse_inset_size_for_shelf_visibility_, shelf_->alignment());
  const gfx::Insets touch_insets = GetInsetsForAlignment(
      touch_inset_size_for_shelf_visibility_, shelf_->alignment());

  // Remember the insets. See GetHitTestsRects when they're actually used.
  SetInsets(mouse_insets, touch_insets);
}

}  // namespace ash