Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(208)

Side by Side Diff: ui/views/cocoa/bridged_native_widget.mm

Issue 659233002: STASH: Epic Experimental patch for toolkit-views App List on Mac Base URL: https://chromium.googlesource.com/chromium/src.git/+/master
Patch Set: Fix a few things. Works@master Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/mac/mac_util.h" 8 #include "base/mac/mac_util.h"
9 #import "base/mac/sdk_forward_declarations.h" 9 #import "base/mac/sdk_forward_declarations.h"
10 #include "ui/base/ime/input_method.h" 10 #include "ui/base/ime/input_method.h"
11 #include "ui/base/ime/input_method_factory.h" 11 #include "ui/base/ime/input_method_factory.h"
12 #include "ui/base/ui_base_switches_util.h" 12 #include "ui/base/ui_base_switches_util.h"
13 #include "ui/gfx/display.h"
13 #import "ui/gfx/mac/coordinate_conversion.h" 14 #import "ui/gfx/mac/coordinate_conversion.h"
15 #include "ui/gfx/screen.h"
14 #import "ui/views/cocoa/bridged_content_view.h" 16 #import "ui/views/cocoa/bridged_content_view.h"
15 #import "ui/views/cocoa/views_nswindow_delegate.h" 17 #import "ui/views/cocoa/views_nswindow_delegate.h"
16 #include "ui/views/widget/native_widget_mac.h" 18 #include "ui/views/widget/native_widget_mac.h"
17 #include "ui/views/ime/input_method_bridge.h" 19 #include "ui/views/ime/input_method_bridge.h"
18 #include "ui/views/ime/null_input_method.h" 20 #include "ui/views/ime/null_input_method.h"
19 #include "ui/views/view.h" 21 #include "ui/views/view.h"
20 #include "ui/views/widget/widget.h" 22 #include "ui/views/widget/widget.h"
21 23
24 #include "base/bind.h"
25
26 #include "cc/output/copy_output_request.h"
27 #include "cc/output/copy_output_result.h"
28
29 #include "third_party/skia/include/core/SkBitmap.h"
30 #include "ui/gfx/codec/png_codec.h"
31 #include "ui/gfx/image/image_skia_rep.h"
32 #include "ui/gfx/canvas.h"
33
34 namespace {
35
36 float GetDeviceScaleFactorFromDisplay(NSView* view) {
37 gfx::Display display = gfx::Screen::GetScreenFor(view)->
38 GetDisplayNearestWindow(view);
39 DCHECK(display.is_valid());
40 return display.device_scale_factor();
41 }
42
43 } // namespace
44
22 namespace views { 45 namespace views {
23 46
24 BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent) 47 BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent)
25 : native_widget_mac_(parent), 48 : native_widget_mac_(parent),
26 focus_manager_(NULL), 49 focus_manager_(NULL),
27 target_fullscreen_state_(false), 50 target_fullscreen_state_(false),
28 in_fullscreen_transition_(false) { 51 in_fullscreen_transition_(false),
52 window_visible_(false) {
29 DCHECK(parent); 53 DCHECK(parent);
30 window_delegate_.reset( 54 window_delegate_.reset(
31 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]); 55 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]);
32 } 56 }
33 57
34 BridgedNativeWidget::~BridgedNativeWidget() { 58 BridgedNativeWidget::~BridgedNativeWidget() {
35 RemoveOrDestroyChildren(); 59 RemoveOrDestroyChildren();
36 SetFocusManager(NULL); 60 SetFocusManager(NULL);
37 SetRootView(NULL); 61 SetRootView(NULL);
38 if ([window_ delegate]) { 62 if ([window_ delegate]) {
39 // If the delegate is still set, it means OnWindowWillClose has not been 63 // If the delegate is still set, it means OnWindowWillClose has not been
40 // called and the window is still open. Calling -[NSWindow close] will 64 // called and the window is still open. Calling -[NSWindow close] will
41 // synchronously call OnWindowWillClose and notify NativeWidgetMac. 65 // synchronously call OnWindowWillClose and notify NativeWidgetMac.
42 [window_ close]; 66 [window_ close];
43 } 67 }
44 DCHECK(![window_ delegate]); 68 DCHECK(![window_ delegate]);
45 } 69 }
46 70
47 void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window, 71 void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window,
48 const Widget::InitParams& params) { 72 const Widget::InitParams& params) {
49 DCHECK(!window_); 73 DCHECK(!window_);
50 window_.swap(window); 74 window_.swap(window);
51 [window_ setDelegate:window_delegate_]; 75 [window_ setDelegate:window_delegate_];
52 76
77 // Register for application hide notifications so that visibility can be
78 // properly tracked. This is not done in the delegate so that the lifetime is
79 // tied to the C++ object, rather than the delegate (which may be reference
80 // counted). This is required since the application hides do not send an
81 // orderOut: to individual windows. Unhide, however, does send an order
82 // message.
83 [[NSNotificationCenter defaultCenter]
84 addObserver:window_delegate_
85 selector:@selector(onWindowOrderChanged:)
86 name:NSApplicationDidHideNotification
87 object:nil];
88
53 // Validate the window's initial state, otherwise the bridge's initial 89 // Validate the window's initial state, otherwise the bridge's initial
54 // tracking state will be incorrect. 90 // tracking state will be incorrect.
55 DCHECK(![window_ isVisible]); 91 DCHECK(![window_ isVisible]);
56 DCHECK_EQ(0u, [window_ styleMask] & NSFullScreenWindowMask); 92 DCHECK_EQ(0u, [window_ styleMask] & NSFullScreenWindowMask);
57 93
58 if (params.parent) { 94 if (params.parent) {
59 // Use NSWindow to manage child windows. This won't automatically close them 95 // Use NSWindow to manage child windows. This won't automatically close them
60 // but it will maintain relative positioning of the window layer and origin. 96 // but it will maintain relative positioning of the window layer and origin.
61 [[params.parent window] addChildWindow:window_ ordered:NSWindowAbove]; 97 [[params.parent window] addChildWindow:window_ ordered:NSWindowAbove];
98
99 // Windows with a parent that are not explicitly child windows are transient
100 // children.
101 if (!params.child) {
102 [window setExcludedFromWindowsMenu:YES];
103 [window_delegate_ setTransientChild:YES];
104 }
62 } 105 }
63 } 106 }
64 107
65 void BridgedNativeWidget::SetFocusManager(FocusManager* focus_manager) { 108 void BridgedNativeWidget::SetFocusManager(FocusManager* focus_manager) {
66 if (focus_manager_ == focus_manager) 109 if (focus_manager_ == focus_manager)
67 return; 110 return;
68 111
69 if (focus_manager_) 112 if (focus_manager_)
70 focus_manager_->RemoveFocusChangeListener(this); 113 focus_manager_->RemoveFocusChangeListener(this);
71 114
72 if (focus_manager) 115 if (focus_manager)
73 focus_manager->AddFocusChangeListener(this); 116 focus_manager->AddFocusChangeListener(this);
74 117
75 focus_manager_ = focus_manager; 118 focus_manager_ = focus_manager;
76 } 119 }
77 120
121 void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) {
122 [window_ setFrame:gfx::ScreenRectToNSRect(new_bounds)
123 display:YES
124 animate:NO];
125
126 // If not visible, -[NSWindowDelegate windowDidResize:] is not triggered.
127 if (![window_ isVisible])
128 OnSizeChanged();
129 }
130
78 void BridgedNativeWidget::SetRootView(views::View* view) { 131 void BridgedNativeWidget::SetRootView(views::View* view) {
79 if (view == [bridged_view_ hostedView]) 132 if (view == [bridged_view_ hostedView])
80 return; 133 return;
81 134
135 // If this is ever false, the compositor will need to be properly torn down
136 // and replaced, pointing at the new view.
137 DCHECK(!view || !compositor_view_);
138
82 [bridged_view_ clearView]; 139 [bridged_view_ clearView];
83 bridged_view_.reset(); 140 bridged_view_.reset();
84 // Note that there can still be references to the old |bridged_view_| 141 // Note that there can still be references to the old |bridged_view_|
85 // floating around in Cocoa libraries at this point. However, references to 142 // floating around in Cocoa libraries at this point. However, references to
86 // the old views::View will be gone, so any method calls will become no-ops. 143 // the old views::View will be gone, so any method calls will become no-ops.
87 144
88 if (view) { 145 if (view) {
89 bridged_view_.reset([[BridgedContentView alloc] initWithView:view]); 146 bridged_view_.reset([[BridgedContentView alloc] initWithView:view]);
90 // Objective C initializers can return nil. However, if |view| is non-NULL 147 // Objective C initializers can return nil. However, if |view| is non-NULL
91 // this should be treated as an error and caught early. 148 // this should be treated as an error and caught early.
92 CHECK(bridged_view_); 149 CHECK(bridged_view_);
93 } 150 }
94 [window_ setContentView:bridged_view_]; 151 [window_ setContentView:bridged_view_];
95 } 152 }
96 153
97 void BridgedNativeWidget::OnWindowWillClose() { 154 void BridgedNativeWidget::OnWindowWillClose() {
98 [[window_ parentWindow] removeChildWindow:window_]; 155 [[window_ parentWindow] removeChildWindow:window_];
99 [window_ setDelegate:nil]; 156 [window_ setDelegate:nil];
157 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_];
100 native_widget_mac_->OnWindowWillClose(); 158 native_widget_mac_->OnWindowWillClose();
101 } 159 }
102 160
103 void BridgedNativeWidget::OnFullscreenTransitionStart( 161 void BridgedNativeWidget::OnFullscreenTransitionStart(
104 bool target_fullscreen_state) { 162 bool target_fullscreen_state) {
105 DCHECK_NE(target_fullscreen_state, target_fullscreen_state_); 163 DCHECK_NE(target_fullscreen_state, target_fullscreen_state_);
106 target_fullscreen_state_ = target_fullscreen_state; 164 target_fullscreen_state_ = target_fullscreen_state;
107 in_fullscreen_transition_ = true; 165 in_fullscreen_transition_ = true;
108 166
109 // If going into fullscreen, store an answer for GetRestoredBounds(). 167 // If going into fullscreen, store an answer for GetRestoredBounds().
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 206
149 // Since fullscreen requests are ignored if the collection behavior does not 207 // Since fullscreen requests are ignored if the collection behavior does not
150 // allow it, save the collection behavior and restore it after. 208 // allow it, save the collection behavior and restore it after.
151 NSWindowCollectionBehavior behavior = [window_ collectionBehavior]; 209 NSWindowCollectionBehavior behavior = [window_ collectionBehavior];
152 [window_ setCollectionBehavior:behavior | 210 [window_ setCollectionBehavior:behavior |
153 NSWindowCollectionBehaviorFullScreenPrimary]; 211 NSWindowCollectionBehaviorFullScreenPrimary];
154 [window_ toggleFullScreen:nil]; 212 [window_ toggleFullScreen:nil];
155 [window_ setCollectionBehavior:behavior]; 213 [window_ setCollectionBehavior:behavior];
156 } 214 }
157 215
216 void BridgedNativeWidget::OnSizeChanged() {
217 NSSize new_size = [window_ frame].size;
218 native_widget_mac_->GetWidget()->OnNativeWidgetSizeChanged(
219 gfx::Size(new_size.width, new_size.height));
220 if (layer())
221 SetLayerSize(native_widget_mac_->GetClientAreaBoundsInScreen().size());
222 }
223
224 void BridgedNativeWidget::OnVisibilityChanged() {
225 OnSizeChanged();
226 if (window_visible_ == [window_ isVisible])
227 return;
228
229 window_visible_ = [window_ isVisible];
230 native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged(
231 window_visible_);
232 }
233
234 void BridgedNativeWidget::OnDisplayChanged() {
235 NOTIMPLEMENTED();
236 }
237
158 InputMethod* BridgedNativeWidget::CreateInputMethod() { 238 InputMethod* BridgedNativeWidget::CreateInputMethod() {
159 if (switches::IsTextInputFocusManagerEnabled()) 239 if (switches::IsTextInputFocusManagerEnabled())
160 return new NullInputMethod(); 240 return new NullInputMethod();
161 241
162 return new InputMethodBridge(this, GetHostInputMethod(), true); 242 return new InputMethodBridge(this, GetHostInputMethod(), true);
163 } 243 }
164 244
165 ui::InputMethod* BridgedNativeWidget::GetHostInputMethod() { 245 ui::InputMethod* BridgedNativeWidget::GetHostInputMethod() {
166 if (!input_method_) { 246 if (!input_method_) {
167 // Delegate is NULL because Mac IME does not need DispatchKeyEventPostIME 247 // Delegate is NULL because Mac IME does not need DispatchKeyEventPostIME
168 // callbacks. 248 // callbacks.
169 input_method_ = ui::CreateInputMethod(NULL, nil); 249 input_method_ = ui::CreateInputMethod(NULL, nil);
170 } 250 }
171 return input_method_.get(); 251 return input_method_.get();
172 } 252 }
173 253
174 gfx::Rect BridgedNativeWidget::GetRestoredBounds() const { 254 gfx::Rect BridgedNativeWidget::GetRestoredBounds() const {
175 if (target_fullscreen_state_ || in_fullscreen_transition_) 255 if (target_fullscreen_state_ || in_fullscreen_transition_)
176 return bounds_before_fullscreen_; 256 return bounds_before_fullscreen_;
177 257
178 return gfx::ScreenRectFromNSRect([window_ frame]); 258 return gfx::ScreenRectFromNSRect([window_ frame]);
179 } 259 }
180 260
261 ui::Layer* BridgedNativeWidget::GetOrCreateLayer() {
262 if (!bridged_view_)
263 return NULL;
264
265 if (layer())
266 return layer();
267
268 NSView* host_view = BrowserCompositorSuperview();
269 [host_view setWantsLayer:YES];
270 // Next line does nothing.
271 [[host_view layer] setBackgroundColor:CGColorGetConstantColor(kCGColorClear)];
272
273 SetLayer(new ui::Layer());
274 layer()->set_delegate(this);
275 // DCHECK_EQ(0u, [[bridged_view_ subviews] count]);
276 compositor_view_.reset(new content::BrowserCompositorViewMac(this));
277
278 DCHECK(compositor_view_->GetCompositor());
279 DCHECK_EQ(compositor_view_->GetCompositor(), layer()->GetCompositor());
280
281 [window_ setOpaque:NO];
282 layer()->GetCompositor()->SetHostHasTransparentBackground(true);
283 layer()->SetFillsBoundsCompletely(true);
284
285 SetLayerSize(native_widget_mac_->GetClientAreaBoundsInScreen().size());
286
287 return layer();
288 }
289
181 //////////////////////////////////////////////////////////////////////////////// 290 ////////////////////////////////////////////////////////////////////////////////
182 // BridgedNativeWidget, internal::InputMethodDelegate: 291 // BridgedNativeWidget, internal::InputMethodDelegate:
183 292
184 void BridgedNativeWidget::DispatchKeyEventPostIME(const ui::KeyEvent& key) { 293 void BridgedNativeWidget::DispatchKeyEventPostIME(const ui::KeyEvent& key) {
185 // Mac key events don't go through this, but some unit tests that use 294 // Mac key events don't go through this, but some unit tests that use
186 // MockInputMethod do. 295 // MockInputMethod do.
187 DCHECK(focus_manager_); 296 DCHECK(focus_manager_);
188 native_widget_mac_->GetWidget()->OnKeyEvent(const_cast<ui::KeyEvent*>(&key)); 297 native_widget_mac_->GetWidget()->OnKeyEvent(const_cast<ui::KeyEvent*>(&key));
189 if (!key.handled()) 298 if (!key.handled())
190 focus_manager_->OnKeyEvent(key); 299 focus_manager_->OnKeyEvent(key);
191 } 300 }
192 301
302 ////////////////////////////////////////////////////////////////////////////////
303 // BridgedNativeWidget, content::BrowserCompositorViewMacClient:
304
305 bool BridgedNativeWidget::BrowserCompositorViewShouldAckImmediately() const {
306 return false;
307 }
308
309 void BridgedNativeWidget::BrowserCompositorViewFrameSwapped(
310 const std::vector<ui::LatencyInfo>& latency_info) {
311 }
312
313 NSView* BridgedNativeWidget::BrowserCompositorSuperview() {
314 if (!compositor_superview_) {
315 compositor_superview_.reset([[NSView alloc] initWithFrame:NSZeroRect]);
316 if ([[bridged_view_ subviews] count] == 0) {
317 [bridged_view_ addSubview:compositor_superview_];
318 } else {
319 [bridged_view_ addSubview:compositor_superview_
320 positioned:NSWindowBelow
321 relativeTo:[[bridged_view_ subviews] objectAtIndex:0]];
322 }
323 }
324 return compositor_superview_;
325 }
326
327 ui::Layer* BridgedNativeWidget::BrowserCompositorRootLayer() {
328 return layer();
329 }
330
331 ////////////////////////////////////////////////////////////////////////////////
332 // BridgedNativeWidget, FocusChangeListener:
333
193 void BridgedNativeWidget::OnWillChangeFocus(View* focused_before, 334 void BridgedNativeWidget::OnWillChangeFocus(View* focused_before,
194 View* focused_now) { 335 View* focused_now) {
195 } 336 }
196 337
197 void BridgedNativeWidget::OnDidChangeFocus(View* focused_before, 338 void BridgedNativeWidget::OnDidChangeFocus(View* focused_before,
198 View* focused_now) { 339 View* focused_now) {
199 ui::TextInputClient* input_client = 340 ui::TextInputClient* input_client =
200 focused_now ? focused_now->GetTextInputClient() : NULL; 341 focused_now ? focused_now->GetTextInputClient() : NULL;
201 [bridged_view_ setTextInputClient:input_client]; 342 [bridged_view_ setTextInputClient:input_client];
202 } 343 }
203 344
204 //////////////////////////////////////////////////////////////////////////////// 345 ////////////////////////////////////////////////////////////////////////////////
346 // BridgedNativeWidget, LayerDelegate:
347
348 static bool WritePNGFile(const SkBitmap& bitmap, const base::FilePath& file_path ,
349 bool discard_transparency) {
350 std::vector<unsigned char> png_data;
351 if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap,
352 discard_transparency,
353 &png_data) &&
354 base::CreateDirectory(file_path.DirName())) {
355 char* data = reinterpret_cast<char*>(&png_data[0]);
356 int size = static_cast<int>(png_data.size());
357 bool result = base::WriteFile(file_path, data, size) == size;
358 return result;
359 }
360 return false;
361 }
362
363 static void ReadbackResult(scoped_ptr<cc::CopyOutputResult> result) {
364 return;
365 DLOG(INFO) << "result!";
366 scoped_ptr<SkBitmap> result_bitmap = result->TakeBitmap().Pass();
367 static int filectr = 0;
368 std::ostringstream oss;
369 oss << "file" << filectr++ << ".png";
370 WritePNGFile(*result_bitmap, base::FilePath().AppendASCII(oss.str().c_str()), false);
371 }
372
373 void BridgedNativeWidget::OnPaintLayer(gfx::Canvas* canvas) {
374 native_widget_mac_->GetWidget()->OnNativeWidgetPaint(canvas);
375 return;
376 layer()->RequestCopyOfOutput(cc::CopyOutputRequest::CreateBitmapRequest(base:: Bind(&ReadbackResult)));
377 native_widget_mac_->GetWidget()->OnNativeWidgetPaint(canvas);
378 gfx::ImageSkiaRep image = canvas->ExtractImageRep();
379 static int filectr = 0;
380 std::ostringstream oss;
381 oss << "bpass" << filectr++ << ".png";
382 WritePNGFile(image.sk_bitmap(), base::FilePath().AppendASCII(oss.str().c_str() ), false);
383
384 }
385
386 void BridgedNativeWidget::OnDelegatedFrameDamage(
387 const gfx::Rect& damage_rect_in_dip) {
388 NOTIMPLEMENTED();
389 }
390
391 void BridgedNativeWidget::OnDeviceScaleFactorChanged(
392 float device_scale_factor) {
393 }
394
395 base::Closure BridgedNativeWidget::PrepareForLayerBoundsChange() {
396 return base::Bind(&BridgedNativeWidget::OnWindowBoundsChanged,
397 base::Unretained(this));
398 }
399
400 ////////////////////////////////////////////////////////////////////////////////
205 // BridgedNativeWidget, private: 401 // BridgedNativeWidget, private:
206 402
207 void BridgedNativeWidget::RemoveOrDestroyChildren() { 403 void BridgedNativeWidget::RemoveOrDestroyChildren() {
208 // TODO(tapted): Implement unowned child windows if required. 404 // TODO(tapted): Implement unowned child windows if required.
209 base::scoped_nsobject<NSArray> child_windows( 405 base::scoped_nsobject<NSArray> child_windows(
210 [[NSArray alloc] initWithArray:[window_ childWindows]]); 406 [[NSArray alloc] initWithArray:[window_ childWindows]]);
211 [child_windows makeObjectsPerformSelector:@selector(close)]; 407 [child_windows makeObjectsPerformSelector:@selector(close)];
212 } 408 }
213 409
410 void BridgedNativeWidget::SetLayerSize(const gfx::Size& size_in_dip) {
411 DLOG(INFO) << "SetLayerSize: " << size_in_dip.ToString();
412 DCHECK(layer());
413 DCHECK(compositor_superview_);
414
415 layer()->SetBounds(gfx::Rect(size_in_dip));
416 NSRect view_frame = [compositor_superview_ frame];
417 view_frame.size.width = size_in_dip.width();
418 view_frame.size.height = size_in_dip.height();
419 [compositor_superview_ setFrame:view_frame];
420
421 float scale_factor = GetDeviceScaleFactorFromDisplay(compositor_superview_);
422 gfx::Size size_in_pixels(size_in_dip.width() * scale_factor,
423 size_in_dip.height() * scale_factor);
424 compositor_view_->GetCompositor()->SetScaleAndSize(scale_factor,
425 size_in_pixels);
426 }
427
428 void BridgedNativeWidget::OnWindowBoundsChanged() {
429 }
430
214 } // namespace views 431 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.h ('k') | ui/views/cocoa/bridged_native_widget_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698