OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ui/views/cocoa/bridged_native_widget.h" | 5 #import "ui/views/cocoa/bridged_native_widget.h" |
6 | 6 |
7 #import <objc/runtime.h> | 7 #import <objc/runtime.h> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/mac/mac_util.h" | 10 #include "base/mac/mac_util.h" |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 // though they are in screen coordinates. | 57 // though they are in screen coordinates. |
58 bool PositionWindowInScreenCoordinates(views::Widget* widget, | 58 bool PositionWindowInScreenCoordinates(views::Widget* widget, |
59 views::Widget::InitParams::Type type) { | 59 views::Widget::InitParams::Type type) { |
60 // Replicate the logic in desktop_aura/desktop_screen_position_client.cc. | 60 // Replicate the logic in desktop_aura/desktop_screen_position_client.cc. |
61 if (views::GetAuraWindowTypeForWidgetType(type) == ui::wm::WINDOW_TYPE_POPUP) | 61 if (views::GetAuraWindowTypeForWidgetType(type) == ui::wm::WINDOW_TYPE_POPUP) |
62 return true; | 62 return true; |
63 | 63 |
64 return widget && widget->is_top_level(); | 64 return widget && widget->is_top_level(); |
65 } | 65 } |
66 | 66 |
| 67 // Return the content size for a minimum or maximum widget size. |
| 68 gfx::Size GetClientSizeForWindowSize(NSWindow* window, |
| 69 const gfx::Size& window_size) { |
| 70 NSRect frame_rect = |
| 71 NSMakeRect(0, 0, window_size.width(), window_size.height()); |
| 72 // Note gfx::Size will prevent dimensions going negative. They are allowed to |
| 73 // be zero at this point, because Widget::GetMinimumSize() may later increase |
| 74 // the size. |
| 75 return gfx::Size([window contentRectForFrameRect:frame_rect].size); |
| 76 } |
| 77 |
67 } // namespace | 78 } // namespace |
68 | 79 |
69 namespace views { | 80 namespace views { |
70 | 81 |
| 82 // static |
| 83 gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize( |
| 84 NSWindow* window, |
| 85 const gfx::Size& content_size) { |
| 86 NSRect content_rect = |
| 87 NSMakeRect(0, 0, content_size.width(), content_size.height()); |
| 88 NSRect frame_rect = [window frameRectForContentRect:content_rect]; |
| 89 return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect)); |
| 90 } |
| 91 |
71 BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent) | 92 BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent) |
72 : native_widget_mac_(parent), | 93 : native_widget_mac_(parent), |
73 focus_manager_(nullptr), | 94 focus_manager_(nullptr), |
74 widget_type_(Widget::InitParams::TYPE_WINDOW), // Updated in Init(). | 95 widget_type_(Widget::InitParams::TYPE_WINDOW), // Updated in Init(). |
75 parent_(nullptr), | 96 parent_(nullptr), |
76 target_fullscreen_state_(false), | 97 target_fullscreen_state_(false), |
77 in_fullscreen_transition_(false), | 98 in_fullscreen_transition_(false), |
78 window_visible_(false), | 99 window_visible_(false), |
79 wants_to_be_visible_(false) { | 100 wants_to_be_visible_(false) { |
80 DCHECK(parent); | 101 DCHECK(parent); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 if (focus_manager_) | 201 if (focus_manager_) |
181 focus_manager_->RemoveFocusChangeListener(this); | 202 focus_manager_->RemoveFocusChangeListener(this); |
182 | 203 |
183 if (focus_manager) | 204 if (focus_manager) |
184 focus_manager->AddFocusChangeListener(this); | 205 focus_manager->AddFocusChangeListener(this); |
185 | 206 |
186 focus_manager_ = focus_manager; | 207 focus_manager_ = focus_manager; |
187 } | 208 } |
188 | 209 |
189 void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) { | 210 void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) { |
| 211 Widget* widget = native_widget_mac_->GetWidget(); |
| 212 // -[NSWindow contentMinSize] is only checked by Cocoa for user-initiated |
| 213 // resizes. This is not what toolkit-views expects, so clamp. Note there is |
| 214 // no check for maximum size (consistent with aura::Window::SetBounds()). |
| 215 gfx::Size clamped_content_size = |
| 216 GetClientSizeForWindowSize(window_, new_bounds.size()); |
| 217 clamped_content_size.SetToMax(widget->GetMinimumSize()); |
| 218 |
190 // A contentRect with zero width or height is a banned practice in ChromeMac, | 219 // A contentRect with zero width or height is a banned practice in ChromeMac, |
191 // due to unpredictable OSX treatment. | 220 // due to unpredictable OSX treatment. |
192 DCHECK(!new_bounds.IsEmpty()) << "Zero-sized windows not supported on Mac"; | 221 DCHECK(!clamped_content_size.IsEmpty()) |
| 222 << "Zero-sized windows not supported on Mac"; |
193 | 223 |
194 if (native_widget_mac_->GetWidget()->IsModal()) { | 224 if (!window_visible_ && widget->IsModal()) { |
195 // Modal dialogs are positioned by Cocoa. Just update the size. | 225 // Window-Modal dialogs (i.e. sheets) are positioned by Cocoa when shown for |
196 [window_ | 226 // the first time. They also have no frame, so just update the content size. |
197 setContentSize:NSMakeSize(new_bounds.width(), new_bounds.height())]; | 227 [window_ setContentSize:NSMakeSize(clamped_content_size.width(), |
| 228 clamped_content_size.height())]; |
198 return; | 229 return; |
199 } | 230 } |
| 231 gfx::Rect actual_new_bounds( |
| 232 new_bounds.origin(), |
| 233 GetWindowSizeForClientSize(window_, clamped_content_size)); |
200 | 234 |
201 gfx::Rect actual_new_bounds(new_bounds); | 235 if (parent_ && !PositionWindowInScreenCoordinates(widget, widget_type_)) |
202 | |
203 if (parent_ && | |
204 !PositionWindowInScreenCoordinates(native_widget_mac_->GetWidget(), | |
205 widget_type_)) | |
206 actual_new_bounds.Offset(parent_->GetRestoredBounds().OffsetFromOrigin()); | 236 actual_new_bounds.Offset(parent_->GetRestoredBounds().OffsetFromOrigin()); |
207 | 237 |
208 [window_ setFrame:gfx::ScreenRectToNSRect(actual_new_bounds) | 238 [window_ setFrame:gfx::ScreenRectToNSRect(actual_new_bounds) |
209 display:YES | 239 display:YES |
210 animate:NO]; | 240 animate:NO]; |
211 } | 241 } |
212 | 242 |
213 void BridgedNativeWidget::SetRootView(views::View* view) { | 243 void BridgedNativeWidget::SetRootView(views::View* view) { |
214 if (view == [bridged_view_ hostedView]) | 244 if (view == [bridged_view_ hostedView]) |
215 return; | 245 return; |
(...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 window_, &kWindowPropertiesKey); | 832 window_, &kWindowPropertiesKey); |
803 if (!properties) { | 833 if (!properties) { |
804 properties = [NSMutableDictionary dictionary]; | 834 properties = [NSMutableDictionary dictionary]; |
805 objc_setAssociatedObject(window_, &kWindowPropertiesKey, | 835 objc_setAssociatedObject(window_, &kWindowPropertiesKey, |
806 properties, OBJC_ASSOCIATION_RETAIN); | 836 properties, OBJC_ASSOCIATION_RETAIN); |
807 } | 837 } |
808 return properties; | 838 return properties; |
809 } | 839 } |
810 | 840 |
811 } // namespace views | 841 } // namespace views |
OLD | NEW |