diff options
-rw-r--r-- | chrome/browser/views/html_dialog_view_browsertest.cc | 204 | ||||
-rw-r--r-- | chrome/browser/views/tab_contents/tab_contents_view_gtk.cc | 11 | ||||
-rw-r--r-- | chrome/browser/views/tabs/dragged_tab_view.cc | 3 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 2 | ||||
-rw-r--r-- | views/controls/native/native_view_host_gtk.cc | 14 | ||||
-rw-r--r-- | views/controls/tabbed_pane/tabbed_pane_unittest.cc | 5 | ||||
-rw-r--r-- | views/widget/gtk_views_fixed.cc | 37 | ||||
-rw-r--r-- | views/widget/gtk_views_fixed.h | 16 | ||||
-rw-r--r-- | views/widget/widget_gtk.cc | 18 | ||||
-rw-r--r-- | views/widget/widget_gtk.h | 5 |
10 files changed, 287 insertions, 28 deletions
diff --git a/chrome/browser/views/html_dialog_view_browsertest.cc b/chrome/browser/views/html_dialog_view_browsertest.cc new file mode 100644 index 0000000..7bb9977 --- /dev/null +++ b/chrome/browser/views/html_dialog_view_browsertest.cc @@ -0,0 +1,204 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/test/ui/ui_test.h" + +#include "base/file_path.h" +#include "base/message_loop.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/dom_ui/html_dialog_ui.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/renderer_host/render_widget_host_view.h" +#include "chrome/browser/views/html_dialog_view.h" +#include "chrome/common/url_constants.h" +#include "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "views/widget/widget.h" +#include "views/window/window.h" + +using testing::Eq; + +namespace { + +// Window non-client-area means that the minimum size for the window +// won't be the actual minimum size - our layout and resizing code +// makes sure the chrome is always visible. +const int kMinimumWidthToTestFor = 20; +const int kMinimumHeightToTestFor = 30; + +class TestHtmlDialogUIDelegate : public HtmlDialogUIDelegate { + public: + TestHtmlDialogUIDelegate() {} + virtual ~TestHtmlDialogUIDelegate() {} + + // HTMLDialogUIDelegate implementation: + virtual bool IsDialogModal() const { + return true; + } + virtual std::wstring GetDialogTitle() const { + return std::wstring(L"Test"); + } + virtual GURL GetDialogContentURL() const { + return GURL(chrome::kAboutBlankURL); + } + virtual void GetDOMMessageHandlers( + std::vector<DOMMessageHandler*>* handlers) const { } + virtual void GetDialogSize(gfx::Size* size) const { + size->set_width(40); + size->set_height(40); + } + virtual std::string GetDialogArgs() const { + return std::string(); + } + virtual void OnDialogClosed(const std::string& json_retval) { } + virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) { + if (out_close_dialog) + *out_close_dialog = true; + } +}; + +} // namespace + +class HtmlDialogBrowserTest : public InProcessBrowserTest { + public: + HtmlDialogBrowserTest() {} + +#if defined(OS_WIN) + class WindowChangedObserver : public base::MessagePumpForUI::Observer { + public: + WindowChangedObserver() {} + + static WindowChangedObserver* Get() { + return Singleton<WindowChangedObserver>::get(); + } + + // This method is called before processing a message. + virtual void WillProcessMessage(const MSG& msg) {} + + // This method is called after processing a message. + virtual void DidProcessMessage(const MSG& msg) { + // Either WM_PAINT or WM_TIMER indicates the actual work of + // pushing through the window resizing messages is done since + // they are lower priority (we don't get to see the + // WM_WINDOWPOSCHANGED message here). + if (msg.message == WM_PAINT || msg.message == WM_TIMER) + MessageLoop::current()->Quit(); + } + }; +#elif !defined(OS_MACOSX) + class WindowChangedObserver : public base::MessagePumpForUI::Observer { + public: + WindowChangedObserver() {} + + static WindowChangedObserver* Get() { + return Singleton<WindowChangedObserver>::get(); + } + + // This method is called before processing a message. + virtual void WillProcessEvent(GdkEvent* event) {} + + // This method is called after processing a message. + virtual void DidProcessEvent(GdkEvent* event) { + // Quit once the GDK_CONFIGURE event has been processed - seeing + // this means the window sizing request that was made actually + // happened. + if (event->type == GDK_CONFIGURE) + MessageLoop::current()->Quit(); + } + }; +#endif +}; + +#if defined(OS_LINUX) +#define MAYBE_SizeWindow SizeWindow +#else +// http://code.google.com/p/chromium/issues/detail?id=52602 +// Windows has some issues resizing windows- an off by one problem, +// and a minimum size that seems too big. This file isn't included in +// Mac builds yet. +#define MAYBE_SizeWindow DISABLED_SizeWindow +#endif + +IN_PROC_BROWSER_TEST_F(HtmlDialogBrowserTest, MAYBE_SizeWindow) { + HtmlDialogUIDelegate* delegate = new TestHtmlDialogUIDelegate(); + + HtmlDialogView* html_view = + new HtmlDialogView(browser()->profile(), delegate); + TabContents* tab_contents = browser()->GetSelectedTabContents(); + ASSERT_TRUE(tab_contents != NULL); + views::Window::CreateChromeWindow(tab_contents->GetMessageBoxRootWindow(), + gfx::Rect(), html_view); + html_view->InitDialog(); + html_view->window()->Show(); + + MessageLoopForUI::current()->AddObserver(WindowChangedObserver::Get()); + + gfx::Rect bounds; + html_view->GetWidget()->GetBounds(&bounds, false); + + gfx::Rect set_bounds = bounds; + gfx::Rect actual_bounds, rwhv_bounds; + + // Bigger than the default in both dimensions. + set_bounds.set_width(400); + set_bounds.set_height(300); + + html_view->MoveContents(tab_contents, set_bounds); + ui_test_utils::RunMessageLoop(); + html_view->GetWidget()->GetBounds(&actual_bounds, false); + EXPECT_EQ(set_bounds, actual_bounds); + + rwhv_bounds = + html_view->tab_contents()->GetRenderWidgetHostView()->GetViewBounds(); + EXPECT_LT(0, rwhv_bounds.width()); + EXPECT_LT(0, rwhv_bounds.height()); + EXPECT_GE(set_bounds.width(), rwhv_bounds.width()); + EXPECT_GE(set_bounds.height(), rwhv_bounds.height()); + + // Larger in one dimension and smaller in the other. + set_bounds.set_width(550); + set_bounds.set_height(250); + + html_view->MoveContents(tab_contents, set_bounds); + ui_test_utils::RunMessageLoop(); + html_view->GetWidget()->GetBounds(&actual_bounds, false); + EXPECT_EQ(set_bounds, actual_bounds); + + rwhv_bounds = + html_view->tab_contents()->GetRenderWidgetHostView()->GetViewBounds(); + EXPECT_LT(0, rwhv_bounds.width()); + EXPECT_LT(0, rwhv_bounds.height()); + EXPECT_GE(set_bounds.width(), rwhv_bounds.width()); + EXPECT_GE(set_bounds.height(), rwhv_bounds.height()); + + // Get very small. + set_bounds.set_width(kMinimumWidthToTestFor); + set_bounds.set_height(kMinimumHeightToTestFor); + + html_view->MoveContents(tab_contents, set_bounds); + ui_test_utils::RunMessageLoop(); + html_view->GetWidget()->GetBounds(&actual_bounds, false); + EXPECT_EQ(set_bounds, actual_bounds); + + rwhv_bounds = + html_view->tab_contents()->GetRenderWidgetHostView()->GetViewBounds(); + EXPECT_LT(0, rwhv_bounds.width()); + EXPECT_LT(0, rwhv_bounds.height()); + EXPECT_GE(set_bounds.width(), rwhv_bounds.width()); + EXPECT_GE(set_bounds.height(), rwhv_bounds.height()); + + // Check to make sure we can't get to 0x0 + set_bounds.set_width(0); + set_bounds.set_height(0); + + html_view->MoveContents(tab_contents, set_bounds); + ui_test_utils::RunMessageLoop(); + html_view->GetWidget()->GetBounds(&actual_bounds, false); + EXPECT_LT(0, actual_bounds.width()); + EXPECT_LT(0, actual_bounds.height()); + + MessageLoopForUI::current()->RemoveObserver(WindowChangedObserver::Get()); +} diff --git a/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc index e8265cb..c261600 100644 --- a/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc +++ b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc @@ -213,14 +213,13 @@ gfx::NativeWindow TabContentsViewGtk::GetTopLevelNativeWindow() const { } void TabContentsViewGtk::GetContainerBounds(gfx::Rect* out) const { - GetBounds(out, false); - // Callers expect the requested bounds not the actual bounds. For example, // during init callers expect 0x0, but Gtk layout enforces a min size of 1x1. - GtkRequisition requisition; - gtk_widget_get_child_requisition(GetNativeView(), &requisition); - out->set_width(requisition.width); - out->set_height(requisition.height); + GetBounds(out, false); + + gfx::Size size; + WidgetGtk::GetRequestedSize(&size); + out->set_size(size); } void TabContentsViewGtk::StartDragging(const WebDropData& drop_data, diff --git a/chrome/browser/views/tabs/dragged_tab_view.cc b/chrome/browser/views/tabs/dragged_tab_view.cc index 5ee2626..8f77a87 100644 --- a/chrome/browser/views/tabs/dragged_tab_view.cc +++ b/chrome/browser/views/tabs/dragged_tab_view.cc @@ -163,8 +163,7 @@ void DraggedTabView::PaintDetachedView(gfx::Canvas* canvas) { int image_x = kDragFrameBorderSize; int image_y = tab_size_.height(); int image_w = ps.width() - kTwiceDragFrameBorderSize; - int image_h = - ps.height() - kTwiceDragFrameBorderSize - tab_size_.height(); + int image_h = contents_size_.height(); scale_canvas.FillRectInt(SK_ColorBLACK, image_x, image_y, image_w, image_h); photobooth_->PaintScreenshotIntoCanvas( &scale_canvas, diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 1f60543..6323db8 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1764,6 +1764,7 @@ 'browser/ssl/ssl_browser_tests.cc', 'browser/task_manager_browsertest.cc', 'browser/views/browser_actions_container_browsertest.cc', + 'browser/views/html_dialog_view_browsertest.cc', 'renderer/form_autocomplete_browsertest.cc', 'renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc', 'test/automation/dom_automation_browsertest.cc', @@ -1897,6 +1898,7 @@ 'sources!': [ 'browser/extensions/browser_action_test_util_views.cc', 'browser/views/browser_actions_container_browsertest.cc', + 'browser/views/html_dialog_view_browsertest.cc', ], }], ], # conditions diff --git a/views/controls/native/native_view_host_gtk.cc b/views/controls/native/native_view_host_gtk.cc index 79a144d..2ba10b8 100644 --- a/views/controls/native/native_view_host_gtk.cc +++ b/views/controls/native/native_view_host_gtk.cc @@ -10,6 +10,7 @@ #include "base/logging.h" #include "views/controls/native/native_view_host.h" #include "views/focus/focus_manager.h" +#include "views/widget/gtk_views_fixed.h" #include "views/widget/widget_gtk.h" namespace views { @@ -228,13 +229,16 @@ void NativeViewHostGtk::ShowWidget(int x, int y, int w, int h) { fixed_h = std::min(installed_clip_bounds_.height(), h); } + // Don't call gtk_widget_size_allocate now, as we're possibly in the + // middle of a re-size, and it kicks off another re-size, and you + // get flashing. Instead, we'll set the desired size as properties + // on the widget and queue the re-size. + gtk_views_fixed_set_widget_size(host_->native_view(), child_w, child_h); + gtk_fixed_move(GTK_FIXED(fixed_), host_->native_view(), child_x, child_y); + // Size and place the fixed_. GetHostWidget()->PositionChild(fixed_, fixed_x, fixed_y, fixed_w, fixed_h); - // Size and place the hosted NativeView. - gtk_widget_set_size_request(host_->native_view(), child_w, child_h); - gtk_fixed_move(GTK_FIXED(fixed_), host_->native_view(), child_x, child_y); - gtk_widget_show(fixed_); gtk_widget_show(host_->native_view()); } @@ -272,7 +276,7 @@ void NativeViewHostGtk::CreateFixed(bool needs_window) { DestroyFixed(); - fixed_ = gtk_fixed_new(); + fixed_ = gtk_views_fixed_new(); gtk_widget_set_name(fixed_, "views-native-view-host-fixed"); gtk_fixed_set_has_window(GTK_FIXED(fixed_), needs_window); // Defeat refcounting. We need to own the fixed. diff --git a/views/controls/tabbed_pane/tabbed_pane_unittest.cc b/views/controls/tabbed_pane/tabbed_pane_unittest.cc index 51a4acb..1ceef86 100644 --- a/views/controls/tabbed_pane/tabbed_pane_unittest.cc +++ b/views/controls/tabbed_pane/tabbed_pane_unittest.cc @@ -32,6 +32,10 @@ class TabbedPaneTest : public testing::Test, WindowDelegate { TabbedPane* tabbed_pane_; + void RunAllPending() { + message_loop_.RunAllPending(); + } + private: virtual void SetUp() { tabbed_pane_ = new TabbedPane(); @@ -69,6 +73,7 @@ TEST_F(TabbedPaneTest, SizeAndLayout) { // The bounds of our children should be smaller than the tabbed pane's bounds. tabbed_pane_->SetBounds(0, 0, 100, 200); + RunAllPending(); gfx::Rect bounds(child1->bounds()); EXPECT_GT(bounds.width(), 0); EXPECT_LT(bounds.width(), 100); diff --git a/views/widget/gtk_views_fixed.cc b/views/widget/gtk_views_fixed.cc index 0b322bb..a2a3f2f 100644 --- a/views/widget/gtk_views_fixed.cc +++ b/views/widget/gtk_views_fixed.cc @@ -4,12 +4,16 @@ #include "views/widget/gtk_views_fixed.h" +#include "base/logging.h" + // We store whether we use the widget's allocated size as a property. Ideally // we would stash this in GtkFixedChild, but GtkFixed doesn't allow subclassing // gtk_fixed_put. Alternatively we could subclass GtkContainer and use our own // API (effectively duplicating GtkFixed), but that means folks could no longer // use the GtkFixed API else where in Chrome. For now I'm going with this route. static const char* kUseAllocatedSize = "__VIEWS_USE_ALLOCATED_SIZE__"; +static const char* kRequisitionWidth = "__VIEWS_REQUISITION_WIDTH__"; +static const char* kRequisitionHeight = "__VIEWS_REQUISITION_HEIGHT__"; G_BEGIN_DECLS @@ -32,13 +36,14 @@ static void gtk_views_fixed_size_allocate(GtkWidget* widget, if (GTK_WIDGET_VISIBLE(child->widget)) { GtkAllocation child_allocation; - gpointer use_allocated_size = g_object_get_data(G_OBJECT(child->widget), - kUseAllocatedSize); + int width, height; + bool use_allocated_size = + gtk_views_fixed_get_widget_size(child->widget, &width, &height); if (use_allocated_size) { // NOTE: even though the size isn't changing, we have to call // size_allocate, otherwise things like buttons won't repaint. - child_allocation.width = child->widget->allocation.width; - child_allocation.height = child->widget->allocation.height; + child_allocation.width = width; + child_allocation.height = height; } else { GtkRequisition child_requisition; gtk_widget_get_child_requisition(child->widget, &child_requisition); @@ -71,9 +76,29 @@ GtkWidget* gtk_views_fixed_new(void) { return GTK_WIDGET(g_object_new(GTK_TYPE_VIEWS_FIXED, NULL)); } -void gtk_views_fixed_set_use_allocated_size(GtkWidget* widget, bool value) { +void gtk_views_fixed_set_widget_size(GtkWidget* widget, + int width, int height) { + // Remember the allocation request, and set this widget up to use it. + bool use_requested_size = (width != 0 && height != 0); g_object_set_data(G_OBJECT(widget), kUseAllocatedSize, - reinterpret_cast<gpointer>(value ? 1 : 0)); + reinterpret_cast<gpointer>(use_requested_size ? 1 : 0)); + g_object_set_data(G_OBJECT(widget), kRequisitionWidth, + reinterpret_cast<gpointer>(width)); + g_object_set_data(G_OBJECT(widget), kRequisitionHeight, + reinterpret_cast<gpointer>(height)); + + gtk_widget_queue_resize(widget); +} + +bool gtk_views_fixed_get_widget_size(GtkWidget* widget, + int* width, int* height) { + DCHECK(width); + DCHECK(height); + *width = reinterpret_cast<glong>(g_object_get_data(G_OBJECT(widget), + kRequisitionWidth)); + *height = reinterpret_cast<glong>(g_object_get_data(G_OBJECT(widget), + kRequisitionHeight)); + return (g_object_get_data(G_OBJECT(widget), kUseAllocatedSize) != 0); } G_END_DECLS diff --git a/views/widget/gtk_views_fixed.h b/views/widget/gtk_views_fixed.h index a03c67b..e9f3fe7 100644 --- a/views/widget/gtk_views_fixed.h +++ b/views/widget/gtk_views_fixed.h @@ -9,10 +9,11 @@ #include <gdk/gdk.h> #include <gtk/gtkfixed.h> -// GtkViewsFixed is a subclass of GtkFixed that can give child widgets their -// current size rather than their requested size. This behavior is controlled -// by gtk_views_fixed_set_use_allocated_size; the default is to use the -// Widget's requested size. +// GtkViewsFixed is a subclass of GtkFixed that can give child widgets +// a set size rather than their requisitioned size (which is actually +// a minimum size, and that can cause issues). This behavior is +// controlled by gtk_views_fixed_set_widget_size; the default is to +// use the Widget's requisitioned size. G_BEGIN_DECLS @@ -43,7 +44,12 @@ GtkWidget* gtk_views_fixed_new(); GType gtk_views_fixed_get_type(); -void gtk_views_fixed_set_use_allocated_size(GtkWidget* widget, bool value); +// If width and height are 0, go back to using the requisitioned size. +// Queues up a re-size on the widget. +void gtk_views_fixed_set_widget_size(GtkWidget* widget, int width, int height); + +bool gtk_views_fixed_get_widget_size(GtkWidget* widget, + int* width, int* height); G_END_DECLS diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc index 1f7afb2..f74eef13 100644 --- a/views/widget/widget_gtk.cc +++ b/views/widget/widget_gtk.cc @@ -331,7 +331,7 @@ void WidgetGtk::RemoveChild(GtkWidget* child) { // closed. if (GTK_IS_CONTAINER(window_contents_)) { gtk_container_remove(GTK_CONTAINER(window_contents_), child); - gtk_views_fixed_set_use_allocated_size(child, false); + gtk_views_fixed_set_widget_size(child, 0, 0); } } @@ -340,9 +340,7 @@ void WidgetGtk::ReparentChild(GtkWidget* child) { } void WidgetGtk::PositionChild(GtkWidget* child, int x, int y, int w, int h) { - GtkAllocation alloc = { x, y, w, h }; - gtk_widget_size_allocate(child, &alloc); - gtk_views_fixed_set_use_allocated_size(child, true); + gtk_views_fixed_set_widget_size(child, w, h); gtk_fixed_move(GTK_FIXED(window_contents_), child, x, y); } @@ -429,6 +427,18 @@ RootView* WidgetGtk::GetRootViewForWidget(GtkWidget* widget) { return static_cast<RootView*>(user_data); } +void WidgetGtk::GetRequestedSize(gfx::Size* out) const { + int width, height; + if (GTK_IS_VIEWS_FIXED(widget_) && + gtk_views_fixed_get_widget_size(GetNativeView(), &width, &height)) { + out->SetSize(width, height); + } else { + GtkRequisition requisition; + gtk_widget_get_child_requisition(GetNativeView(), &requisition); + out->SetSize(requisition.width, requisition.height); + } +} + //////////////////////////////////////////////////////////////////////////////// // WidgetGtk, ActiveWindowWatcherX::Observer implementation: diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h index 7e1bdd1..7a2820e 100644 --- a/views/widget/widget_gtk.h +++ b/views/widget/widget_gtk.h @@ -149,6 +149,11 @@ class WidgetGtk // Returns the RootView for |widget|. static RootView* GetRootViewForWidget(GtkWidget* widget); + // Gets the requested size of the widget. This can be the size + // stored in properties for a GtkViewsFixed, or in the requisitioned + // size of other kinds of widgets. + void GetRequestedSize(gfx::Size* out) const; + // Overriden from ActiveWindowWatcherX::Observer. virtual void ActiveWindowChanged(GdkWindow* active_window); |