1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file. 4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/chromeos/ui/focus_ring_controller.h" 6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ash/system/tray/actionable_view.h" 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ash/system/tray/tray_background_view.h" 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ash/system/tray/tray_popup_header_button.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/wm/window_util.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/chromeos/ui/focus_ring_layer.h" 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/aura/window.h" 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/views/controls/button/label_button.h" 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/views/view.h" 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/views/widget/widget.h" 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace chromeos { 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FocusRingController::FocusRingController() 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : visible_(false), 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) widget_(NULL) { 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FocusRingController::~FocusRingController() { 25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SetVisible(false); 26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FocusRingController::SetVisible(bool visible) { 29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (visible_ == visible) 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) visible_ = visible; 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (visible_) { 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this); 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch aura::Window* active_window = ash::wm::GetActiveWindow(); 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (active_window) 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SetWidget(views::Widget::GetWidgetForNativeWindow(active_window)); 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SetWidget(NULL); 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FocusRingController::UpdateFocusRing() { 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci views::View* view = NULL; 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (widget_ && widget_->GetFocusManager()) 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view = widget_->GetFocusManager()->GetFocusedView(); 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // No focus ring if no focused view or the focused view covers the whole 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // widget content area (such as RenderWidgetHostWidgetAura). 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!view || 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view->ConvertRectToWidget(view->bounds()) == 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) widget_->GetContentsView()->bounds()) { 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) focus_ring_layer_.reset(); 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gfx::Rect view_bounds = view->GetContentsBounds(); 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Workarounds that attempts to pick a better bounds. 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (view->GetClassName() == views::LabelButton::kViewClassName) { 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view_bounds = view->GetLocalBounds(); 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view_bounds.Inset(2, 2, 2, 2); 651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Workarounds for system tray items that have customized focus borders. The 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // insets here must be consistent with the ones used by those classes. 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (view->GetClassName() == ash::ActionableView::kViewClassName) { 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view_bounds = view->GetLocalBounds(); 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view_bounds.Inset(1, 1, 3, 3); 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else if (view->GetClassName() == ash::TrayBackgroundView::kViewClassName) { 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view_bounds.Inset(1, 1, 3, 3); 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else if (view->GetClassName() == 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ash::TrayPopupHeaderButton::kViewClassName) { 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view_bounds = view->GetLocalBounds(); 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view_bounds.Inset(2, 1, 2, 2); 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Convert view bounds to widget/window coordinates. 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view_bounds = view->ConvertRectToWidget(view_bounds); 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Translate window coordinates to root window coordinates. 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(view->GetWidget()); 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci aura::Window* window = view->GetWidget()->GetNativeWindow(); 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci aura::Window* root_window = window->GetRootWindow(); 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gfx::Point origin = view_bounds.origin(); 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci aura::Window::ConvertPointToTarget(window, root_window, &origin); 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view_bounds.set_origin(origin); 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Update the focus ring layer. 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!focus_ring_layer_) 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci focus_ring_layer_.reset(new FocusRingLayer(this)); 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci focus_ring_layer_->Set(root_window, view_bounds); 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid FocusRingController::OnDeviceScaleFactorChanged() { 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci UpdateFocusRing(); 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FocusRingController::SetWidget(views::Widget* widget) { 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (widget_) { 103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) widget_->RemoveObserver(this); 104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (widget_->GetFocusManager()) 105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) widget_->GetFocusManager()->RemoveFocusChangeListener(this); 106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) widget_ = widget; 109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (widget_) { 111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) widget_->AddObserver(this); 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (widget_->GetFocusManager()) 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) widget_->GetFocusManager()->AddFocusChangeListener(this); 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UpdateFocusRing(); 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FocusRingController::OnWidgetDestroying(views::Widget* widget) { 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_EQ(widget_, widget); 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SetWidget(NULL); 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FocusRingController::OnWidgetBoundsChanged(views::Widget* widget, 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const gfx::Rect& new_bounds) { 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_EQ(widget_, widget); 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UpdateFocusRing(); 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FocusRingController::OnNativeFocusChange(gfx::NativeView focused_before, 131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::NativeView focused_now) { 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch views::Widget* widget = 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch focused_now ? views::Widget::GetWidgetForNativeWindow(focused_now) : NULL; 134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SetWidget(widget); 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FocusRingController::OnWillChangeFocus(views::View* focused_before, 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) views::View* focused_now) { 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FocusRingController::OnDidChangeFocus(views::View* focused_before, 142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) views::View* focused_now) { 143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_EQ(focused_now, widget_->GetFocusManager()->GetFocusedView()); 144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UpdateFocusRing(); 145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace chromeos 148