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/constrained_window_views.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 97d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chrome/browser/ui/browser_finder.h" 10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/web_modal/popup_manager.h" 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "components/web_modal/web_contents_modal_dialog_host.h" 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/guest_view/guest_view_base.h" 13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "ui/views/border.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/widget/widget_observer.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/window/dialog_delegate.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using web_modal::ModalDialogHost; 194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using web_modal::ModalDialogHostObserver; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// The name of a key to store on the window handle to associate 234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// BrowserModalDialogHostObserverViews with the Widget. 244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char* const kBrowserModalDialogHostObserverViewsKey = 254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) "__BROWSER_MODAL_DIALOG_HOST_OBSERVER_VIEWS__"; 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Applies positioning changes from the ModalDialogHost to the Widget. 284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class BrowserModalDialogHostObserverViews 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : public views::WidgetObserver, 304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public ModalDialogHostObserver { 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) BrowserModalDialogHostObserverViews(ModalDialogHost* host, 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::Widget* target_widget, 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const char *const native_window_property) 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : host_(host), 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) target_widget_(target_widget), 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) native_window_property_(native_window_property) { 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(host_); 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(target_widget_); 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) host_->AddObserver(this); 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) target_widget_->AddObserver(this); 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) virtual ~BrowserModalDialogHostObserverViews() { 453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (host_) 463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) host_->RemoveObserver(this); 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) target_widget_->RemoveObserver(this); 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) target_widget_->SetNativeWindowProperty(native_window_property_, NULL); 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // WidgetObserver overrides 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE { 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) delete this; 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // WebContentsModalDialogHostObserver overrides 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void OnPositionRequiresUpdate() OVERRIDE { 584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) UpdateBrowserModalDialogPosition(target_widget_, host_); 593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) virtual void OnHostDestroying() OVERRIDE { 623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) host_->RemoveObserver(this); 633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) host_ = NULL; 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ModalDialogHost* host_; 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::Widget* target_widget_; 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const char* const native_window_property_; 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(BrowserModalDialogHostObserverViews); 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void UpdateModalDialogPosition(views::Widget* widget, 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) web_modal::ModalDialogHost* dialog_host, 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const gfx::Size& size) { 778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Do not forcibly update the dialog widget position if it is being dragged. 788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (widget->HasCapture()) 798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return; 808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gfx::Point position = dialog_host->GetDialogPosition(size); 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::Border* border = widget->non_client_view()->frame_view()->border(); 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Border may be null during widget initialization. 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (border) { 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Align the first row of pixels inside the border. This is the apparent 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // top of the dialog. 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) position.set_y(position.y() - border->GetInsets().top()); 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (widget->is_top_level()) { 914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) position += 924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) views::Widget::GetWidgetForNativeView(dialog_host->GetHostView())-> 934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) GetClientAreaBoundsInScreen().OffsetFromOrigin(); 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) widget->SetBounds(gfx::Rect(position, size)); 974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UpdateWebContentsModalDialogPosition( 1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) views::Widget* widget, 1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) web_modal::WebContentsModalDialogHost* dialog_host) { 10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) gfx::Size size = widget->GetRootView()->GetPreferredSize(); 10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) gfx::Size max_size = dialog_host->GetMaximumDialogSize(); 10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Enlarge the max size by the top border, as the dialog will be shifted 1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // outside the area specified by the dialog host by this amount later. 1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) views::Border* border = 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) widget->non_client_view()->frame_view()->border(); 1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // Border may be null during widget initialization. 11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (border) 11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) max_size.Enlarge(0, border->GetInsets().top()); 11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) size.SetToMin(max_size); 1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) UpdateModalDialogPosition(widget, dialog_host, size); 1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void UpdateBrowserModalDialogPosition(views::Widget* widget, 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) web_modal::ModalDialogHost* dialog_host) { 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) UpdateModalDialogPosition(widget, dialog_host, 1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) widget->GetRootView()->GetPreferredSize()); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)views::Widget* ShowWebModalDialogViews( 124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) views::WidgetDelegate* dialog, 125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) content::WebContents* initiator_web_contents) { 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci extensions::GuestViewBase* guest_view = 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci extensions::GuestViewBase::FromWebContents(initiator_web_contents); 128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // For embedded WebContents, use the embedder's WebContents for constrained 129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // window. 130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) content::WebContents* web_contents = 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci guest_view && guest_view->embedder_web_contents() ? 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci guest_view->embedder_web_contents() : initiator_web_contents; 13346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) views::Widget* widget = CreateWebModalDialogViews(dialog, web_contents); 134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch web_modal::PopupManager* popup_manager = 135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch web_modal::PopupManager::FromWebContents(web_contents); 136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch popup_manager->ShowModalDialog(widget->GetNativeWindow(), web_contents); 13746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return widget; 13846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 13946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)views::Widget* CreateWebModalDialogViews(views::WidgetDelegate* dialog, 14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) content::WebContents* web_contents) { 14246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) DCHECK_EQ(ui::MODAL_TYPE_CHILD, dialog->GetModalType()); 143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch web_modal::PopupManager* popup_manager = 144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch web_modal::PopupManager::FromWebContents(web_contents); 145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const gfx::NativeWindow parent = popup_manager->GetHostView(); 14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return views::DialogDelegate::CreateDialogWidget(dialog, NULL, parent); 14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// TODO(gbillock): Replace this with PopupManager calls. 1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog, 1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) gfx::NativeWindow parent) { 1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) views::Widget* widget = 1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) views::DialogDelegate::CreateDialogWidget(dialog, NULL, parent); 1547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!dialog->UseNewStyleForThisDialog()) 1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return widget; 1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Get the browser dialog management and hosting components from |parent|. 1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) Browser* browser = chrome::FindBrowserWithWindow(parent); 1597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (browser) { 1607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ChromeWebModalDialogManagerDelegate* manager = browser; 1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ModalDialogHost* host = manager->GetWebContentsModalDialogHost(); 1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK_EQ(parent, host->GetHostView()); 1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ModalDialogHostObserver* dialog_host_observer = 1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) new BrowserModalDialogHostObserverViews( 1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) host, widget, kBrowserModalDialogHostObserverViewsKey); 1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) dialog_host_observer->OnPositionRequiresUpdate(); 1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 1687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return widget; 1697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 170