app_list_win.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1// Copyright 2013 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/views/app_list/win/app_list_win.h" 6 7#include "chrome/browser/profiles/profile.h" 8#include "ui/app_list/views/app_list_view.h" 9#include "ui/gfx/screen.h" 10#include "ui/views/widget/widget.h" 11 12namespace { 13 14static const wchar_t kTrayClassName[] = L"Shell_TrayWnd"; 15 16// Utility methods for showing the app list. 17// Attempts to find the bounds of the Windows taskbar. Returns true on success. 18// |rect| is in screen coordinates. If the taskbar is in autohide mode and is 19// not visible, |rect| will be outside the current monitor's bounds, except for 20// one pixel of overlap where the edge of the taskbar is shown. 21bool GetTaskbarRect(gfx::Rect* rect) { 22 HWND taskbar_hwnd = FindWindow(kTrayClassName, NULL); 23 if (!taskbar_hwnd) 24 return false; 25 26 RECT win_rect; 27 if (!GetWindowRect(taskbar_hwnd, &win_rect)) 28 return false; 29 30 *rect = gfx::Rect(win_rect); 31 return true; 32} 33 34gfx::Point FindReferencePoint(const gfx::Display& display, 35 const gfx::Point& cursor) { 36 const int kSnapDistance = 50; 37 38 // If we can't find the taskbar, snap to the bottom left. 39 // If the display size is the same as the work area, and does not contain the 40 // taskbar, either the taskbar is hidden or on another monitor, so just snap 41 // to the bottom left. 42 gfx::Rect taskbar_rect; 43 if (!GetTaskbarRect(&taskbar_rect) || 44 (display.work_area() == display.bounds() && 45 !display.work_area().Contains(taskbar_rect))) { 46 return display.work_area().bottom_left(); 47 } 48 49 // Snap to the taskbar edge. If the cursor is greater than kSnapDistance away, 50 // also move to the left (for horizontal taskbars) or top (for vertical). 51 const gfx::Rect& screen_rect = display.bounds(); 52 // First handle taskbar on bottom. 53 // Note on Windows 8 the work area won't include split windows on the left or 54 // right, and neither will |taskbar_rect|. 55 if (taskbar_rect.width() == display.work_area().width()) { 56 if (taskbar_rect.bottom() == screen_rect.bottom()) { 57 if (taskbar_rect.y() - cursor.y() > kSnapDistance) 58 return gfx::Point(screen_rect.x(), taskbar_rect.y()); 59 60 return gfx::Point(cursor.x(), taskbar_rect.y()); 61 } 62 63 // Now try on the top. 64 if (cursor.y() - taskbar_rect.bottom() > kSnapDistance) 65 return gfx::Point(screen_rect.x(), taskbar_rect.bottom()); 66 67 return gfx::Point(cursor.x(), taskbar_rect.bottom()); 68 } 69 70 // Now try the left. 71 if (taskbar_rect.x() == screen_rect.x()) { 72 if (cursor.x() - taskbar_rect.right() > kSnapDistance) 73 return gfx::Point(taskbar_rect.right(), screen_rect.y()); 74 75 return gfx::Point(taskbar_rect.right(), cursor.y()); 76 } 77 78 // Finally, try the right. 79 if (taskbar_rect.x() - cursor.x() > kSnapDistance) 80 return gfx::Point(taskbar_rect.x(), screen_rect.y()); 81 82 return gfx::Point(taskbar_rect.x(), cursor.y()); 83} 84 85gfx::Point FindAnchorPoint( 86 const gfx::Size view_size, 87 const gfx::Display& display, 88 const gfx::Point& cursor) { 89 const int kSnapOffset = 3; 90 91 gfx::Rect bounds_rect(display.work_area()); 92 // Always subtract the taskbar area since work_area() will not subtract it 93 // if the taskbar is set to auto-hide, and the app list should never overlap 94 // the taskbar. 95 gfx::Rect taskbar_rect; 96 if (GetTaskbarRect(&taskbar_rect)) 97 bounds_rect.Subtract(taskbar_rect); 98 99 bounds_rect.Inset(view_size.width() / 2 + kSnapOffset, 100 view_size.height() / 2 + kSnapOffset); 101 102 gfx::Point anchor = FindReferencePoint(display, cursor); 103 anchor.SetToMax(bounds_rect.origin()); 104 anchor.SetToMin(bounds_rect.bottom_right()); 105 return anchor; 106} 107 108} // namespace 109 110AppListWin::AppListWin(app_list::AppListView* view, 111 const base::Closure& on_should_dismiss) 112 : view_(view), 113 activation_tracker_(view, on_should_dismiss), 114 window_icon_updated_(false) { 115} 116 117AppListWin::~AppListWin() { 118} 119 120void AppListWin::Show() { 121 view_->GetWidget()->Show(); 122 if (!window_icon_updated_) { 123 view_->GetWidget()->GetTopLevelWidget()->UpdateWindowIcon(); 124 window_icon_updated_ = true; 125 } 126 view_->GetWidget()->Activate(); 127} 128 129void AppListWin::Hide() { 130 view_->GetWidget()->Hide(); 131 activation_tracker_.OnViewHidden(); 132} 133 134void AppListWin::MoveNearCursor() { 135 gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint(); 136 gfx::Screen* screen = 137 gfx::Screen::GetScreenFor(view_->GetWidget()->GetNativeView()); 138 gfx::Display display = screen->GetDisplayNearestPoint(cursor); 139 140 view_->SetBubbleArrow(views::BubbleBorder::FLOAT); 141 view_->SetAnchorPoint(FindAnchorPoint( 142 view_->GetPreferredSize(), display, cursor)); 143} 144 145bool AppListWin::IsVisible() { 146 return view_->GetWidget()->IsVisible(); 147} 148 149void AppListWin::Prerender() { 150 view_->Prerender(); 151} 152 153void AppListWin::RegainNextLostFocus() { 154 activation_tracker_.RegainNextLostFocus(); 155} 156 157gfx::NativeWindow AppListWin::GetWindow() { 158 return view_->GetWidget()->GetNativeWindow(); 159} 160 161void AppListWin::SetProfile(Profile* profile) { 162 view_->SetProfileByPath(profile->GetPath()); 163} 164