panel_view.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/panels/panel_view.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map> 8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/logging.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/message_loop.h" 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/utf_string_conversions.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/app/chrome_command_ids.h" 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/panels/panel.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/panels/panel_bounds_animation.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/panels/panel_manager.h" 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/ui/panels/stacked_panel_collection.h" 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/ui/views/panels/panel_frame_view.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_widget_host_view.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/web_contents_view.h" 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/gfx/image/image.h" 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/gfx/path.h" 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/gfx/screen.h" 25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/views/controls/button/image_button.h" 26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/views/controls/webview/webview.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/win/windows_version.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/shell_integration.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/win/shell.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/icon_util.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/win/hwnd_util.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If the height of a stacked panel shrinks below this threshold during the 410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// user resizing, it will be treated as minimized. 42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst int kStackedPanelHeightShrinkThresholdToBecomeMinimized = 43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch panel::kTitlebarHeight + 20; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Supported accelerators. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: We can't use the acclerator table defined in chrome/browser/ui/views 470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// due to checkdeps violation. 48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstruct AcceleratorMapping { 49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch ui::KeyboardCode keycode; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int modifiers; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst AcceleratorMapping kPanelAcceleratorMap[] = { 540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch { ui::VKEY_W, ui::EF_CONTROL_DOWN, IDC_CLOSE_WINDOW }, 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) { ui::VKEY_W, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, IDC_CLOSE_WINDOW }, 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) { ui::VKEY_F4, ui::EF_ALT_DOWN, IDC_CLOSE_WINDOW }, 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) { ui::VKEY_R, ui::EF_CONTROL_DOWN, IDC_RELOAD }, 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) { ui::VKEY_F5, ui::EF_NONE, IDC_RELOAD }, 590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch { ui::VKEY_R, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, 60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch IDC_RELOAD_IGNORING_CACHE }, 61c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch { ui::VKEY_F5, ui::EF_CONTROL_DOWN, IDC_RELOAD_IGNORING_CACHE }, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { ui::VKEY_F5, ui::EF_SHIFT_DOWN, IDC_RELOAD_IGNORING_CACHE }, 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { ui::VKEY_ESCAPE, ui::EF_NONE, IDC_STOP }, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { ui::VKEY_OEM_MINUS, ui::EF_CONTROL_DOWN, IDC_ZOOM_MINUS }, 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { ui::VKEY_SUBTRACT, ui::EF_CONTROL_DOWN, IDC_ZOOM_MINUS }, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { ui::VKEY_0, ui::EF_CONTROL_DOWN, IDC_ZOOM_NORMAL }, 670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch { ui::VKEY_NUMPAD0, ui::EF_CONTROL_DOWN, IDC_ZOOM_NORMAL }, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { ui::VKEY_OEM_PLUS, ui::EF_CONTROL_DOWN, IDC_ZOOM_PLUS }, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { ui::VKEY_ADD, ui::EF_CONTROL_DOWN, IDC_ZOOM_PLUS }, 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { ui::VKEY_I, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, IDC_DEV_TOOLS }, 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { ui::VKEY_J, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, 720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch IDC_DEV_TOOLS_CONSOLE }, 730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const std::map<ui::Accelerator, int>& GetAcceleratorTable() { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::map<ui::Accelerator, int>* accelerators = NULL; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!accelerators) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerators = new std::map<ui::Accelerator, int>(); 790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch for (size_t i = 0; i < arraysize(kPanelAcceleratorMap); ++i) { 800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch ui::Accelerator accelerator(kPanelAcceleratorMap[i].keycode, 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kPanelAcceleratorMap[i].modifiers); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*accelerators)[accelerator] = kPanelAcceleratorMap[i].command_id; 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return *accelerators; 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// NativePanelTesting implementation. 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class NativePanelTestingWin : public NativePanelTesting { 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public: 915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) explicit NativePanelTestingWin(PanelView* panel_view); 925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) private: 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual void PressLeftMouseButtonTitlebar( 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const gfx::Point& mouse_location, panel::ClickModifier modifier) OVERRIDE; 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual void ReleaseMouseButtonTitlebar( 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) panel::ClickModifier modifier) OVERRIDE; 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual void DragTitlebar(const gfx::Point& mouse_location) OVERRIDE; 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual void CancelDragTitlebar() OVERRIDE; 1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual void FinishDragTitlebar() OVERRIDE; 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual bool VerifyDrawingAttention() const OVERRIDE; 1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual bool VerifyActiveState(bool is_active) OVERRIDE; 1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual bool VerifyAppIcon() const OVERRIDE; 1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual bool VerifySystemMinimizeState() const OVERRIDE; 1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual bool IsWindowSizeKnown() const OVERRIDE; 1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual bool IsAnimatingBounds() const OVERRIDE; 1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual bool IsButtonVisible( 1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) panel::TitlebarButtonType button_type) const OVERRIDE; 1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual panel::CornerStyle GetWindowCornerStyle() const OVERRIDE; 1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PanelView* panel_view_; 1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)NativePanelTestingWin::NativePanelTestingWin(PanelView* panel_view) 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : panel_view_(panel_view) { 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void NativePanelTestingWin::PressLeftMouseButtonTitlebar( 1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const gfx::Point& mouse_location, panel::ClickModifier modifier) { 1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) panel_view_->OnTitlebarMousePressed(mouse_location); 1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void NativePanelTestingWin::ReleaseMouseButtonTitlebar( 1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) panel::ClickModifier modifier) { 1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) panel_view_->OnTitlebarMouseReleased(modifier); 1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void NativePanelTestingWin::DragTitlebar(const gfx::Point& mouse_location) { 1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) panel_view_->OnTitlebarMouseDragged(mouse_location); 1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void NativePanelTestingWin::CancelDragTitlebar() { 1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) panel_view_->OnTitlebarMouseCaptureLost(); 1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void NativePanelTestingWin::FinishDragTitlebar() { 1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) panel_view_->OnTitlebarMouseReleased(panel::NO_MODIFIER); 1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool NativePanelTestingWin::VerifyDrawingAttention() const { 1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::MessageLoop::current()->RunUntilIdle(); 1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return panel_view_->GetFrameView()->GetPaintState() == 1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PanelFrameView::PAINT_FOR_ATTENTION; 1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool NativePanelTestingWin::VerifyActiveState(bool is_active) { 1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return panel_view_->GetFrameView()->GetPaintState() == 1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (is_active ? PanelFrameView::PAINT_AS_ACTIVE 1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : PanelFrameView::PAINT_AS_INACTIVE); 1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool NativePanelTestingWin::VerifyAppIcon() const { 1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_WIN) 1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // We only care about Windows 7 and later. 1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (base::win::GetVersion() < base::win::VERSION_WIN7) 1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; 1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HWND native_window = views::HWNDForWidget(panel_view_->window()); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HICON app_icon = reinterpret_cast<HICON>( 160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ::SendMessage(native_window, WM_GETICON, ICON_BIG, 0L)); 161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!app_icon) 162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_ptr<SkBitmap> bitmap(IconUtil::CreateSkBitmapFromHICON(app_icon)); 164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return bitmap.get() && 165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bitmap->width() == panel::kPanelAppIconSize && 166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bitmap->height() == panel::kPanelAppIconSize; 167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#else 168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return true; 169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif 170c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 171c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool NativePanelTestingWin::VerifySystemMinimizeState() const { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 1740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch HWND native_window = views::HWNDForWidget(panel_view_->window()); 1750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch WINDOWPLACEMENT placement; 1760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (!::GetWindowPlacement(native_window, &placement)) 1770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return false; 1780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (placement.showCmd == SW_MINIMIZE || placement.showCmd == SW_SHOWMINIMIZED) 1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return true; 1800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // If the panel window has owner window, as in stacked mode, check its owner 1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // window. Note that owner window, instead of parent window, is returned 1830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // though GWL_HWNDPARENT contains 'parent'. 1840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch HWND owner_window = 1850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch reinterpret_cast<HWND>(::GetWindowLongPtr(native_window, 1860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch GWLP_HWNDPARENT)); 187010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!owner_window || !::GetWindowPlacement(owner_window, &placement)) 188010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return false; 189010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return placement.showCmd == SW_MINIMIZE || 1900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch placement.showCmd == SW_SHOWMINIMIZED; 1910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#else 192c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return true; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NativePanelTestingWin::IsWindowSizeKnown() const { 1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return true; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NativePanelTestingWin::IsAnimatingBounds() const { 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return panel_view_->IsAnimatingBounds(); 202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool NativePanelTestingWin::IsButtonVisible( 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) panel::TitlebarButtonType button_type) const { 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PanelFrameView* frame_view = panel_view_->GetFrameView(); 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) switch (button_type) { 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case panel::CLOSE_BUTTON: 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return frame_view->close_button()->visible(); 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case panel::MINIMIZE_BUTTON: 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return frame_view->minimize_button()->visible(); 2130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch case panel::RESTORE_BUTTON: 2140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return frame_view->restore_button()->visible(); 215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch default: 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochpanel::CornerStyle NativePanelTestingWin::GetWindowCornerStyle() const { 2220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return panel_view_->GetFrameView()->corner_style(); 2230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch} 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NativePanel* Panel::CreateNativePanel(Panel* panel, const gfx::Rect& bounds) { 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return new PanelView(panel, bounds); 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The panel window has to be created as always-on-top. We cannot create it 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// as non-always-on-top and then change it to always-on-top because Windows 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// system might deny making a window always-on-top if the application is not 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// a foreground application. In addition, we do not know if the panel should 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// be created as always-on-top at its creation time. To solve this issue, 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// always_on_top_ is default to true because we can always change from 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// always-on-top to not always-on-top but not the other way around. 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PanelView::PanelView(Panel* panel, const gfx::Rect& bounds) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : panel_(panel), 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_(bounds), 242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) window_(NULL), 243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) window_closed_(false), 244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) web_view_(NULL), 245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) always_on_top_(true), 246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) focused_(false), 247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) user_resizing_(false), 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN) 249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) user_resizing_interior_stacked_panel_edge_(false), 250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif 251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mouse_pressed_(false), 252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) mouse_dragging_state_(NO_DRAGGING), 253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) is_drawing_attention_(false), 254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) force_to_paint_as_inactive_(false), 255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) old_focused_view_(NULL) { 256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) window_ = new views::Widget; 2570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); 2580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch params.delegate = this; 259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) params.remove_standard_frame = true; 260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) params.keep_on_top = true; 261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) params.bounds = bounds; 262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) window_->Init(params); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM); 2640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch window_->set_focus_on_creation(false); 2650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch window_->AddObserver(this); 2660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_view_ = new views::WebView(NULL); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddChildView(web_view_); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnViewWasResized(); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 272c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Register accelarators supported by panels. 273c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch views::FocusManager* focus_manager = GetFocusManager(); 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::map<ui::Accelerator, int>& accelerator_table = 2750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch GetAcceleratorTable(); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::map<ui::Accelerator, int>::const_iterator iter = 277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) accelerator_table.begin(); 278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) iter != accelerator_table.end(); ++iter) { 279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) focus_manager->RegisterAccelerator( 280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) iter->first, ui::AcceleratorManager::kNormalPriority, this); 281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_WIN) 2840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch ui::win::SetAppIdForWindow( 285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ShellIntegration::GetAppModelIdForProfile(UTF8ToWide(panel->app_name()), 2860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch panel->profile()->GetPath()), 287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) views::HWNDForWidget(window_)); 288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif 289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this); 291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PanelView::~PanelView() { 294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PanelView::ShowPanel() { 297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ShowPanelInactive(); 298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ActivatePanel(); 299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PanelView::ShowPanelInactive() { 302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (window_->IsVisible()) 303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) window_->ShowInactive(); 305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // No animation is used for initial creation of a panel on Win. 306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Signal immediately that pending actions can be performed. 307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch panel_->manager()->OnPanelAnimationEnded(panel_.get()); 308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 310116680a4aac90f2aa7413d9095a592090648e557Ben Murdochgfx::Rect PanelView::GetPanelBounds() const { 311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return bounds_; 312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PanelView::SetPanelBounds(const gfx::Rect& bounds) { 315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetBoundsInternal(bounds, true); 316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PanelView::SetPanelBoundsInstantly(const gfx::Rect& bounds) { 319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetBoundsInternal(bounds, false); 320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 322116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid PanelView::SetBoundsInternal(const gfx::Rect& new_bounds, bool animate) { 323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (bounds_ == new_bounds) 324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bounds_ = new_bounds; 327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!animate) { 329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // If no animation is in progress, apply bounds change instantly. Otherwise, 330116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // continue the animation with new target bounds. 331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!IsAnimatingBounds()) 332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetWidgetBounds(bounds_); 333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) animation_start_bounds_ = window_->GetWindowBoundsInScreen(); 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.reset(new PanelBoundsAnimation( 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, panel_.get(), animation_start_bounds_, new_bounds)); 340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bounds_animator_->Start(); 341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 342a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_WIN) 344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool PanelView::FilterMessage(HWND hwnd, 345a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) UINT message, 346a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) WPARAM w_param, 347a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LPARAM l_param, 348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LRESULT* l_result) { 349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) switch (message) { 350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case WM_SIZING: 351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (w_param == WMSZ_BOTTOM) 352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) user_resizing_interior_stacked_panel_edge_ = true; 353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) break; 354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif 358a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 359a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PanelView::AnimationEnded(const ui::Animation* animation) { 360a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) panel_->manager()->OnPanelAnimationEnded(panel_.get()); 361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 362a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PanelView::AnimationProgressed(const ui::Animation* animation) { 364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Rect new_bounds = bounds_animator_->CurrentValueBetween( 365a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) animation_start_bounds_, bounds_); 366a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetWidgetBounds(new_bounds); 367a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 368a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 369a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PanelView::SetWidgetBounds(const gfx::Rect& new_bounds) { 370a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_WIN) 371a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // An overlapped window is a top-level window that has a titlebar, border, 372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // and client area. The Windows system will automatically put the shadow 373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // around the whole window. Also the system will enforce the minimum height 374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // (38 pixels based on observation) for the overlapped window such that it 375a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // will always has the space for the titlebar. 376a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // 377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // On contrast, a popup window is a bare minimum window without border and 378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // titlebar by default. It is often used for the popup menu and the window 379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // with short life. The Windows system does not add the shadow around the 380a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // whole window though CS_DROPSHADOW class style could be passed to add the 381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // drop shadow which is only around the right and bottom edges. 382a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // 383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The height of the title-only or minimized panel is smaller than the minimum 384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // overlapped window height. If the panel still uses the overlapped window 385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // style, Windows system will automatically increase the window height. To 386a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // work around this limitation, we temporarily change the window style to 387a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // popup when the height to set is smaller than the minimum overlapped window 388a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // height and then restore the window style to overlapped when the height 389a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // grows. 390a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static const int kMinimumOverlappedWindowHeight = 38; 391a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Rect old_bounds = GetWidget()->GetRestoredBounds(); 392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (old_bounds.height() > kMinimumOverlappedWindowHeight && 393a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new_bounds.height() <= kMinimumOverlappedWindowHeight) { 394a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // When the panel height shrinks below the minimum overlapped window height, 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // change the window style to popup such that we can show the title-only 396c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // and minimized panel without additional height being added by the system. 397c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch UpdateWindowAttribute(GWL_STYLE, 398c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch WS_POPUP, 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU, 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) true); 401a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else if (old_bounds.height() <= kMinimumOverlappedWindowHeight && 402a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new_bounds.height() > kMinimumOverlappedWindowHeight) { 403a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Change the window style back to overlappped when the panel height grow 404a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // taller than the minimum overlapped window height. 405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) UpdateWindowAttribute(GWL_STYLE, 406a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU, 407a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) WS_POPUP, 408a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) true); 409a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 410a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif 411a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 412a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GetWidget()->SetBounds(new_bounds); 413a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 414a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 415a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PanelView::ClosePanel() { 416a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // We're already closing. Do nothing. 417a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (window_closed_) 418a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!panel_->ShouldCloseWindow()) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cancel any currently running animation since we're closing down. 424 if (bounds_animator_.get()) 425 bounds_animator_.reset(); 426 427 if (panel_->GetWebContents()) { 428 // Still have web contents. Allow renderer to shut down. 429 // When web contents are destroyed, we will be called back again. 430 panel_->OnWindowClosing(); 431 return; 432 } 433 434 views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); 435 436 panel_->OnNativePanelClosed(); 437 if (window_) 438 window_->Close(); 439 window_closed_ = true; 440} 441 442void PanelView::ActivatePanel() { 443 window_->Activate(); 444} 445 446void PanelView::DeactivatePanel() { 447 if (!focused_) 448 return; 449 450#if defined(OS_WIN) 451 // Need custom behavior for always-on-top panels to avoid 452 // the OS activating a minimized panel when this one is 453 // deactivated. 454 if (always_on_top_) { 455 ::SetForegroundWindow(::GetDesktopWindow()); 456 return; 457 } 458#endif 459 460 window_->Deactivate(); 461} 462 463bool PanelView::IsPanelActive() const { 464 return focused_; 465} 466 467void PanelView::PreventActivationByOS(bool prevent_activation) { 468#if defined(OS_WIN) 469 // Set the flags "NoActivate" to make sure the minimized panels do not get 470 // activated by the OS. In addition, set "AppWindow" to make sure the 471 // minimized panels do appear in the taskbar and Alt-Tab menu if it is not 472 // in a stack. 473 int value_to_change = WS_EX_NOACTIVATE; 474 if (!panel_->stack()) 475 value_to_change |= WS_EX_APPWINDOW; 476 if (prevent_activation) 477 UpdateWindowAttribute(GWL_EXSTYLE, value_to_change, 0, false); 478 else 479 UpdateWindowAttribute(GWL_EXSTYLE, 0, value_to_change, false); 480#endif 481} 482 483gfx::NativeWindow PanelView::GetNativePanelWindow() { 484 return window_->GetNativeWindow(); 485} 486 487void PanelView::UpdatePanelTitleBar() { 488 UpdateWindowTitle(); 489 UpdateWindowIcon(); 490} 491 492void PanelView::UpdatePanelLoadingAnimations(bool should_animate) { 493 GetFrameView()->UpdateThrobber(); 494} 495 496void PanelView::PanelWebContentsFocused(content::WebContents* contents) { 497 web_view_->OnWebContentsFocused(contents); 498} 499 500void PanelView::PanelCut() { 501 // Nothing to do since we do not have panel-specific system menu. 502 NOTREACHED(); 503} 504 505void PanelView::PanelCopy() { 506 // Nothing to do since we do not have panel-specific system menu. 507 NOTREACHED(); 508} 509 510void PanelView::PanelPaste() { 511 // Nothing to do since we do not have panel-specific system menu. 512 NOTREACHED(); 513} 514 515void PanelView::DrawAttention(bool draw_attention) { 516 DCHECK((panel_->attention_mode() & Panel::USE_PANEL_ATTENTION) != 0); 517 518 if (is_drawing_attention_ == draw_attention) 519 return; 520 is_drawing_attention_ = draw_attention; 521 GetFrameView()->SchedulePaint(); 522 523 if ((panel_->attention_mode() & Panel::USE_SYSTEM_ATTENTION) != 0) { 524#if defined(OS_WIN) 525 // The default implementation of Widget::FlashFrame only flashes 5 times. 526 // We need more than that. 527 FLASHWINFO fwi; 528 fwi.cbSize = sizeof(fwi); 529 fwi.hwnd = views::HWNDForWidget(window_); 530 if (draw_attention) { 531 fwi.dwFlags = FLASHW_ALL; 532 fwi.uCount = panel::kNumberOfTimesToFlashPanelForAttention; 533 fwi.dwTimeout = 0; 534 } else { 535 // TODO(jianli): calling FlashWindowEx with FLASHW_STOP flag for the 536 // panel window has the same problem as the stack window. However, 537 // we cannot take the similar fix since there is no background window 538 // to replace for the regular panel window. More investigation is needed. 539 fwi.dwFlags = FLASHW_STOP; 540 } 541 ::FlashWindowEx(&fwi); 542#else 543 window_->FlashFrame(draw_attention); 544#endif 545 } 546} 547 548bool PanelView::IsDrawingAttention() const { 549 return is_drawing_attention_; 550} 551 552void PanelView::HandlePanelKeyboardEvent( 553 const content::NativeWebKeyboardEvent& event) { 554 views::FocusManager* focus_manager = GetFocusManager(); 555 if (focus_manager->shortcut_handling_suspended()) 556 return; 557 558 ui::Accelerator accelerator( 559 static_cast<ui::KeyboardCode>(event.windowsKeyCode), 560 content::GetModifiersFromNativeWebKeyboardEvent(event)); 561 if (event.type == WebKit::WebInputEvent::KeyUp) 562 accelerator.set_type(ui::ET_KEY_RELEASED); 563 focus_manager->ProcessAccelerator(accelerator); 564} 565 566void PanelView::FullScreenModeChanged(bool is_full_screen) { 567 if (is_full_screen) { 568 if (window_->IsVisible()) 569 window_->Hide(); 570 } else { 571 ShowPanelInactive(); 572 } 573} 574 575bool PanelView::IsPanelAlwaysOnTop() const { 576 return always_on_top_; 577} 578 579void PanelView::SetPanelAlwaysOnTop(bool on_top) { 580 if (always_on_top_ == on_top) 581 return; 582 always_on_top_ = on_top; 583 584 window_->SetAlwaysOnTop(on_top); 585 window_->non_client_view()->Layout(); 586 window_->client_view()->Layout(); 587} 588 589void PanelView::EnableResizeByMouse(bool enable) { 590 // Nothing to do since we use system resizing. 591} 592 593void PanelView::UpdatePanelMinimizeRestoreButtonVisibility() { 594 GetFrameView()->UpdateTitlebarMinimizeRestoreButtonVisibility(); 595} 596 597void PanelView::SetWindowCornerStyle(panel::CornerStyle corner_style) { 598 GetFrameView()->SetWindowCornerStyle(corner_style); 599} 600 601void PanelView::PanelExpansionStateChanging(Panel::ExpansionState old_state, 602 Panel::ExpansionState new_state) { 603#if defined(OS_WIN) 604 // Live preview is only available since Windows 7. 605 if (base::win::GetVersion() < base::win::VERSION_WIN7) 606 return; 607 608 bool is_minimized = old_state != Panel::EXPANDED; 609 bool will_be_minimized = new_state != Panel::EXPANDED; 610 if (is_minimized == will_be_minimized) 611 return; 612 613 HWND native_window = views::HWNDForWidget(window_); 614 615 if (!thumbnailer_.get()) { 616 DCHECK(native_window); 617 thumbnailer_.reset(new TaskbarWindowThumbnailerWin(native_window)); 618 ui::HWNDSubclass::AddFilterToTarget(native_window, thumbnailer_.get()); 619 } 620 621 // Cache the image at this point. 622 if (will_be_minimized) { 623 // If the panel is still active (we will deactivate the minimizd panel at 624 // later time), we need to paint it immediately as inactive so that we can 625 // take a snapshot of inactive panel. 626 if (focused_) { 627 force_to_paint_as_inactive_ = true; 628 ::RedrawWindow(native_window, NULL, NULL, 629 RDW_NOCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW); 630 } 631 632 std::vector<HWND> snapshot_hwnds; 633 thumbnailer_->Start(snapshot_hwnds); 634 } else { 635 force_to_paint_as_inactive_ = false; 636 thumbnailer_->Stop(); 637 } 638 639#endif 640} 641 642gfx::Size PanelView::WindowSizeFromContentSize( 643 const gfx::Size& content_size) const { 644 gfx::Size frame = GetFrameView()->NonClientAreaSize(); 645 return gfx::Size(content_size.width() + frame.width(), 646 content_size.height() + frame.height()); 647} 648 649gfx::Size PanelView::ContentSizeFromWindowSize( 650 const gfx::Size& window_size) const { 651 gfx::Size frame = GetFrameView()->NonClientAreaSize(); 652 return gfx::Size(window_size.width() - frame.width(), 653 window_size.height() - frame.height()); 654} 655 656int PanelView::TitleOnlyHeight() const { 657 return panel::kTitlebarHeight; 658} 659 660void PanelView::MinimizePanelBySystem() { 661 window_->Minimize(); 662} 663 664bool PanelView::IsPanelMinimizedBySystem() const { 665 return window_->IsMinimized(); 666} 667 668void PanelView::ShowShadow(bool show) { 669#if defined(OS_WIN) 670 // The overlapped window has the shadow while the popup window does not have 671 // the shadow. 672 int overlap_style = WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU; 673 int popup_style = WS_POPUP; 674 UpdateWindowAttribute(GWL_STYLE, 675 show ? overlap_style : popup_style, 676 show ? popup_style : overlap_style, 677 true); 678#endif 679} 680 681void PanelView::AttachWebContents(content::WebContents* contents) { 682 web_view_->SetWebContents(contents); 683} 684 685void PanelView::DetachWebContents(content::WebContents* contents) { 686 web_view_->SetWebContents(NULL); 687} 688 689NativePanelTesting* PanelView::CreateNativePanelTesting() { 690 return new NativePanelTestingWin(this); 691} 692 693void PanelView::OnDisplayChanged() { 694 panel_->manager()->display_settings_provider()->OnDisplaySettingsChanged(); 695} 696 697void PanelView::OnWorkAreaChanged() { 698 panel_->manager()->display_settings_provider()->OnDisplaySettingsChanged(); 699} 700 701bool PanelView::WillProcessWorkAreaChange() const { 702 return true; 703} 704 705views::View* PanelView::GetContentsView() { 706 return this; 707} 708 709views::NonClientFrameView* PanelView::CreateNonClientFrameView( 710 views::Widget* widget) { 711 PanelFrameView* frame_view = new PanelFrameView(this); 712 frame_view->Init(); 713 return frame_view; 714} 715 716bool PanelView::CanResize() const { 717 return true; 718} 719 720bool PanelView::CanMaximize() const { 721 return false; 722} 723 724string16 PanelView::GetWindowTitle() const { 725 return panel_->GetWindowTitle(); 726} 727 728gfx::ImageSkia PanelView::GetWindowAppIcon() { 729 gfx::Image app_icon = panel_->app_icon(); 730 if (app_icon.IsEmpty()) 731 return GetWindowIcon(); 732 else 733 return *app_icon.ToImageSkia(); 734} 735 736gfx::ImageSkia PanelView::GetWindowIcon() { 737 gfx::Image icon = panel_->GetCurrentPageIcon(); 738 return icon.IsEmpty() ? gfx::ImageSkia() : *icon.ToImageSkia(); 739} 740 741void PanelView::WindowClosing() { 742 // When closing a panel via window.close, API or the close button, 743 // ClosePanel() is called first, destroying the native |window_| 744 // which results in this method being called. ClosePanel() sets 745 // |window_closed_| to NULL. 746 // If we still have a |window_closed_| here, the close was triggered by the 747 // OS, (e.g. clicking on taskbar menu), which destroys the native |window_| 748 // without invoking ClosePanel() beforehand. 749 if (!window_closed_) { 750 panel_->OnWindowClosing(); 751 ClosePanel(); 752 DCHECK(window_closed_); 753 } 754} 755 756void PanelView::DeleteDelegate() { 757 delete this; 758} 759 760void PanelView::OnWindowBeginUserBoundsChange() { 761 user_resizing_ = true; 762 panel_->OnPanelStartUserResizing(); 763 764#if defined(OS_WIN) 765 StackedPanelCollection* stack = panel_->stack(); 766 if (stack) { 767 // Listen to WM_SIZING message in order to find out whether the interior 768 // edge is being resized such that the specific maximum size could be 769 // passed to the system. 770 if (panel_->stack()->GetPanelBelow(panel_.get())) { 771 ui::HWNDSubclass::AddFilterToTarget(views::HWNDForWidget(window_), this); 772 user_resizing_interior_stacked_panel_edge_ = false; 773 } 774 775 // Keep track of the original full size of the resizing panel such that it 776 // can be restored to this size once it is shrunk to minimized state. 777 original_full_size_of_resizing_panel_ = panel_->full_size(); 778 779 // Keep track of the original full size of the panel below the resizing 780 // panel such that it can be restored to this size once it is shrunk to 781 // minimized state. 782 Panel* below_panel = stack->GetPanelBelow(panel_.get()); 783 if (below_panel && !below_panel->IsMinimized()) { 784 original_full_size_of_panel_below_resizing_panel_ = 785 below_panel->full_size(); 786 } 787 } 788#endif 789} 790 791void PanelView::OnWindowEndUserBoundsChange() { 792 user_resizing_ = false; 793 panel_->OnPanelEndUserResizing(); 794 795 // No need to proceed with post-resizing update when there is no size change. 796 gfx::Rect new_bounds = window_->GetWindowBoundsInScreen(); 797 if (bounds_ == new_bounds) 798 return; 799 bounds_ = new_bounds; 800 801 panel_->IncreaseMaxSize(bounds_.size()); 802 panel_->set_full_size(bounds_.size()); 803 804#if defined(OS_WIN) 805 StackedPanelCollection* stack = panel_->stack(); 806 if (stack) { 807 // No need to listen to WM_SIZING message any more. 808 ui::HWNDSubclass::RemoveFilterFromAllTargets(this); 809 810 // If the height of resizing panel shrinks close to the titlebar height, 811 // treate it as minimized. This could occur when the user is dragging 812 // 1) the top edge of the top panel downward to shrink it; or 813 // 2) the bottom edge of any panel upward to shrink it. 814 if (panel_->GetBounds().height() < 815 kStackedPanelHeightShrinkThresholdToBecomeMinimized) { 816 stack->MinimizePanel(panel_.get()); 817 panel_->set_full_size(original_full_size_of_resizing_panel_); 818 } 819 820 // If the height of panel below the resizing panel shrinks close to the 821 // titlebar height, treat it as minimized. This could occur when the user 822 // is dragging the bottom edge of non-bottom panel downward to expand it 823 // and also shrink the panel below. 824 Panel* below_panel = stack->GetPanelBelow(panel_.get()); 825 if (below_panel && !below_panel->IsMinimized() && 826 below_panel->GetBounds().height() < 827 kStackedPanelHeightShrinkThresholdToBecomeMinimized) { 828 stack->MinimizePanel(below_panel); 829 below_panel->set_full_size( 830 original_full_size_of_panel_below_resizing_panel_); 831 } 832 } 833#endif 834 835 panel_->collection()->RefreshLayout(); 836} 837 838views::Widget* PanelView::GetWidget() { 839 return window_; 840} 841 842const views::Widget* PanelView::GetWidget() const { 843 return window_; 844} 845 846void PanelView::UpdateLoadingAnimations(bool should_animate) { 847 GetFrameView()->UpdateThrobber(); 848} 849 850void PanelView::UpdateWindowTitle() { 851 window_->UpdateWindowTitle(); 852 GetFrameView()->UpdateTitle(); 853} 854 855void PanelView::UpdateWindowIcon() { 856 window_->UpdateWindowIcon(); 857 GetFrameView()->UpdateIcon(); 858} 859 860void PanelView::Layout() { 861 // |web_view_| might not be created yet when the window is first created. 862 if (web_view_) 863 web_view_->SetBounds(0, 0, width(), height()); 864 OnViewWasResized(); 865} 866 867gfx::Size PanelView::GetMinimumSize() { 868 // If the panel is minimized, it can be rendered to very small size, like 869 // 4-pixel lines when it is docked. Otherwise, its size should not be less 870 // than its minimum size. 871 return panel_->IsMinimized() ? gfx::Size() : 872 gfx::Size(panel::kPanelMinWidth, panel::kPanelMinHeight); 873} 874 875gfx::Size PanelView::GetMaximumSize() { 876 // If the user is resizing a stacked panel by its bottom edge, make sure its 877 // height cannot grow more than what the panel below it could offer. This is 878 // because growing a stacked panel by y amount will shrink the panel below it 879 // by same amount and we do not want the panel below it being shrunk to be 880 // smaller than the titlebar. 881#if defined(OS_WIN) 882 if (panel_->stack() && user_resizing_interior_stacked_panel_edge_) { 883 Panel* below_panel = panel_->stack()->GetPanelBelow(panel_.get()); 884 if (below_panel && !below_panel->IsMinimized()) { 885 return gfx::Size(0, below_panel->GetBounds().bottom() - 886 panel_->GetBounds().y() - panel::kTitlebarHeight); 887 } 888 } 889#endif 890 return gfx::Size(); 891} 892 893bool PanelView::AcceleratorPressed(const ui::Accelerator& accelerator) { 894 if (mouse_pressed_ && accelerator.key_code() == ui::VKEY_ESCAPE) { 895 OnTitlebarMouseCaptureLost(); 896 return true; 897 } 898 899 // No other accelerator is allowed when the drag begins. 900 if (mouse_dragging_state_ == DRAGGING_STARTED) 901 return true; 902 903 const std::map<ui::Accelerator, int>& accelerator_table = 904 GetAcceleratorTable(); 905 std::map<ui::Accelerator, int>::const_iterator iter = 906 accelerator_table.find(accelerator); 907 DCHECK(iter != accelerator_table.end()); 908 return panel_->ExecuteCommandIfEnabled(iter->second); 909} 910 911void PanelView::OnWidgetDestroying(views::Widget* widget) { 912 window_ = NULL; 913} 914 915void PanelView::OnWidgetActivationChanged(views::Widget* widget, bool active) { 916#if defined(OS_WIN) 917 // The panel window is in focus (actually accepting keystrokes) if it is 918 // active and belongs to a foreground application. 919 bool focused = active && 920 views::HWNDForWidget(widget) == ::GetForegroundWindow(); 921#else 922 NOTIMPLEMENTED(); 923 bool focused = active; 924#endif 925 926 if (focused_ == focused) 927 return; 928 focused_ = focused; 929 930 // Expand the panel if the minimized panel is activated by means other than 931 // clicking on its titlebar. This is the workaround to support restoring the 932 // minimized panel by other means, like alt-tabbing, win-tabbing, or clicking 933 // the taskbar icon. Note that this workaround does not work for one edge 934 // case: the mouse happens to be at the minimized panel when the user tries to 935 // bring up the panel with the above alternatives. 936 // When the user clicks on the minimized panel, the panel expansion will be 937 // done when we process the mouse button pressed message. 938 if (focused_ && panel_->IsMinimized() && 939 panel_->collection()->type() == PanelCollection::DOCKED && 940 gfx::Screen::GetScreenFor(widget->GetNativeWindow())-> 941 GetWindowAtCursorScreenPoint() != widget->GetNativeWindow()) { 942 panel_->Restore(); 943 } 944 945 panel()->OnActiveStateChanged(focused); 946} 947 948void PanelView::OnWidgetBoundsChanged(views::Widget* widget, 949 const gfx::Rect& new_bounds) { 950 if (user_resizing_) 951 panel()->collection()->OnPanelResizedByMouse(panel(), new_bounds); 952} 953 954void PanelView::OnNativeFocusChange(gfx::NativeView focused_before, 955 gfx::NativeView focused_now) { 956 if (focused_now != window_->GetNativeView()) 957 return; 958 959 // Give web contents view a chance to set focus to the appropriate element. 960 content::WebContents* web_contents = panel_->GetWebContents(); 961 if (web_contents) 962 web_contents->GetView()->RestoreFocus(); 963} 964 965bool PanelView::OnTitlebarMousePressed(const gfx::Point& mouse_location) { 966 mouse_pressed_ = true; 967 mouse_dragging_state_ = NO_DRAGGING; 968 last_mouse_location_ = mouse_location; 969 return true; 970} 971 972bool PanelView::OnTitlebarMouseDragged(const gfx::Point& mouse_location) { 973 if (!mouse_pressed_) 974 return false; 975 976 if (mouse_dragging_state_ == NO_DRAGGING && 977 ExceededDragThreshold(mouse_location - last_mouse_location_)) { 978 // When a drag begins, we do not want to the client area to still receive 979 // the focus. We do not need to do this for the unfocused minimized panel. 980 if (!panel_->IsMinimized()) { 981 old_focused_view_ = GetFocusManager()->GetFocusedView(); 982 GetFocusManager()->SetFocusedView(GetFrameView()); 983 } 984 985 panel_->manager()->StartDragging(panel_.get(), last_mouse_location_); 986 mouse_dragging_state_ = DRAGGING_STARTED; 987 } 988 if (mouse_dragging_state_ == DRAGGING_STARTED) { 989 panel_->manager()->Drag(mouse_location); 990 991 // Once in drag, update |last_mouse_location_| on each drag fragment, since 992 // we already dragged the panel up to the current mouse location. 993 last_mouse_location_ = mouse_location; 994 } 995 return true; 996} 997 998bool PanelView::OnTitlebarMouseReleased(panel::ClickModifier modifier) { 999 if (mouse_dragging_state_ != NO_DRAGGING) { 1000 // Ensure dragging a minimized panel does not leave it activated. 1001 // Windows activates a panel on mouse-down, regardless of our attempts 1002 // to prevent activation of a minimized panel. Now that we know mouse-down 1003 // resulted in a mouse-drag, we need to ensure the minimized panel is 1004 // deactivated. 1005 if (panel_->IsMinimized() && focused_) 1006 panel_->Deactivate(); 1007 1008 if (mouse_dragging_state_ == DRAGGING_STARTED) { 1009 // When a drag ends, restore the focus. 1010 if (old_focused_view_) { 1011 GetFocusManager()->SetFocusedView(old_focused_view_); 1012 old_focused_view_ = NULL; 1013 } 1014 return EndDragging(false); 1015 } 1016 1017 // The panel drag was cancelled before the mouse is released. Do not 1018 // treat this as a click. 1019 return true; 1020 } 1021 1022 panel_->OnTitlebarClicked(modifier); 1023 return true; 1024} 1025 1026bool PanelView::OnTitlebarMouseCaptureLost() { 1027 if (mouse_dragging_state_ == DRAGGING_STARTED) 1028 return EndDragging(true); 1029 return true; 1030} 1031 1032bool PanelView::EndDragging(bool cancelled) { 1033 // Only handle clicks that started in our window. 1034 if (!mouse_pressed_) 1035 return false; 1036 mouse_pressed_ = false; 1037 1038 mouse_dragging_state_ = DRAGGING_ENDED; 1039 panel_->manager()->EndDragging(cancelled); 1040 return true; 1041} 1042 1043PanelFrameView* PanelView::GetFrameView() const { 1044 return static_cast<PanelFrameView*>(window_->non_client_view()->frame_view()); 1045} 1046 1047bool PanelView::IsAnimatingBounds() const { 1048 if (bounds_animator_.get() && bounds_animator_->is_animating()) 1049 return true; 1050 StackedPanelCollection* stack = panel_->stack(); 1051 if (!stack) 1052 return false; 1053 return stack->IsAnimatingPanelBounds(panel_.get()); 1054} 1055 1056bool PanelView::IsWithinResizingArea(const gfx::Point& mouse_location) const { 1057 gfx::Rect bounds = window_->GetWindowBoundsInScreen(); 1058 DCHECK(bounds.Contains(mouse_location)); 1059 return mouse_location.x() < bounds.x() + kResizeInsideBoundsSize || 1060 mouse_location.x() >= bounds.right() - kResizeInsideBoundsSize || 1061 mouse_location.y() < bounds.y() + kResizeInsideBoundsSize || 1062 mouse_location.y() >= bounds.bottom() - kResizeInsideBoundsSize; 1063} 1064 1065#if defined(OS_WIN) 1066void PanelView::UpdateWindowAttribute(int attribute_index, 1067 int attribute_value_to_set, 1068 int attribute_value_to_reset, 1069 bool update_frame) { 1070 HWND native_window = views::HWNDForWidget(window_); 1071 int value = ::GetWindowLong(native_window, attribute_index); 1072 int expected_value = value; 1073 if (attribute_value_to_set) 1074 expected_value |= attribute_value_to_set; 1075 if (attribute_value_to_reset) 1076 expected_value &= ~attribute_value_to_reset; 1077 if (value != expected_value) 1078 ::SetWindowLong(native_window, attribute_index, expected_value); 1079 1080 // Per MSDN, if any of the frame styles is changed, SetWindowPos with the 1081 // SWP_FRAMECHANGED flag must be called in order for the cached window data 1082 // to be updated properly. 1083 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms633591(v=vs.85).aspx 1084 if (update_frame) { 1085 ::SetWindowPos(native_window, NULL, 0, 0, 0, 0, 1086 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | 1087 SWP_NOZORDER | SWP_NOACTIVATE); 1088 } 1089} 1090#endif 1091 1092void PanelView::OnViewWasResized() { 1093#if defined(OS_WIN) && !defined(USE_AURA) 1094 content::WebContents* web_contents = panel_->GetWebContents(); 1095 if (!web_view_ || !web_contents) 1096 return; 1097 1098 // When the panel is frameless or has thin frame, the mouse resizing should 1099 // also be triggered from the part of client area that is close to the window 1100 // frame. 1101 int width = web_view_->size().width(); 1102 int height = web_view_->size().height(); 1103 // Compute the thickness of the client area that needs to be counted towards 1104 // mouse resizing. 1105 int thickness_for_mouse_resizing = 1106 kResizeInsideBoundsSize - GetFrameView()->BorderThickness(); 1107 DCHECK(thickness_for_mouse_resizing > 0); 1108 SkRegion* region = new SkRegion; 1109 region->op(0, 0, thickness_for_mouse_resizing, height, SkRegion::kUnion_Op); 1110 region->op(width - thickness_for_mouse_resizing, 0, width, height, 1111 SkRegion::kUnion_Op); 1112 region->op(0, height - thickness_for_mouse_resizing, width, height, 1113 SkRegion::kUnion_Op); 1114 web_contents->GetRenderViewHost()->GetView()->SetClickthroughRegion(region); 1115#endif 1116} 1117