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

Side by Side Diff: chrome/browser/ui/cocoa/panels/panel_stack_window_cocoa.mm

Issue 2263863002: Remove implementation of Panels on OSes other than ChromeOS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: CR feedback Created 4 years, 4 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
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/cocoa/panels/panel_stack_window_cocoa.h"
6
7 #include "base/logging.h"
8 #include "base/strings/sys_string_conversions.h"
9 #import "chrome/browser/ui/cocoa/panels/panel_cocoa.h"
10 #import "chrome/browser/ui/cocoa/panels/panel_utils_cocoa.h"
11 #include "chrome/browser/ui/panels/panel.h"
12 #include "chrome/browser/ui/panels/panel_manager.h"
13 #include "chrome/browser/ui/panels/stacked_panel_collection.h"
14 #include "ui/base/cocoa/window_size_constants.h"
15 #include "ui/gfx/canvas.h"
16 #include "ui/gfx/geometry/vector2d.h"
17 #include "ui/gfx/image/image.h"
18 #include "ui/gfx/image/image_skia.h"
19 #include "ui/gfx/image/image_skia_rep.h"
20 #include "ui/snapshot/snapshot.h"
21
22 // The delegate class to receive the notification from NSViewAnimation.
23 @interface BatchBoundsAnimationDelegate : NSObject<NSAnimationDelegate> {
24 @private
25 PanelStackWindowCocoa* window_; // Weak pointer.
26 }
27
28 // Called when NSViewAnimation finishes the animation.
29 - (void)animationDidEnd:(NSAnimation*)animation;
30 @end
31
32 @implementation BatchBoundsAnimationDelegate
33
34 - (id)initWithWindow:(PanelStackWindowCocoa*)window {
35 if ((self = [super init]))
36 window_ = window;
37 return self;
38 }
39
40 - (void)animationDidEnd:(NSAnimation*)animation {
41 window_->BoundsUpdateAnimationEnded();
42 }
43
44 @end
45
46 // static
47 NativePanelStackWindow* NativePanelStackWindow::Create(
48 NativePanelStackWindowDelegate* delegate) {
49 return new PanelStackWindowCocoa(delegate);
50 }
51
52 PanelStackWindowCocoa::PanelStackWindowCocoa(
53 NativePanelStackWindowDelegate* delegate)
54 : delegate_(delegate),
55 attention_request_id_(0),
56 bounds_updates_started_(false),
57 animate_bounds_updates_(false),
58 bounds_animation_(nil) {
59 DCHECK(delegate);
60 bounds_animation_delegate_.reset(
61 [[BatchBoundsAnimationDelegate alloc] initWithWindow:this]);
62 }
63
64 PanelStackWindowCocoa::~PanelStackWindowCocoa() {
65 }
66
67 void PanelStackWindowCocoa::Close() {
68 TerminateBoundsAnimation();
69 [window_ close];
70 }
71
72 void PanelStackWindowCocoa::AddPanel(Panel* panel) {
73 panels_.push_back(panel);
74
75 EnsureWindowCreated();
76
77 // Make the stack window own the panel window such that all panels window
78 // could be moved simulatenously when the stack window is moved.
79 [window_ addChildWindow:panel->GetNativeWindow() ordered:NSWindowAbove];
80
81 UpdateStackWindowBounds();
82 }
83
84 void PanelStackWindowCocoa::RemovePanel(Panel* panel) {
85 if (IsAnimatingPanelBounds()) {
86 // This panel is gone. We should not perform any update to it.
87 bounds_updates_.erase(panel);
88 }
89
90 panels_.remove(panel);
91
92 // If the native panel is closed, the native window should already be gone.
93 if (!static_cast<PanelCocoa*>(panel->native_panel())->IsClosed())
94 [window_ removeChildWindow:panel->GetNativeWindow()];
95
96 UpdateStackWindowBounds();
97 }
98
99 void PanelStackWindowCocoa::MergeWith(NativePanelStackWindow* another) {
100 PanelStackWindowCocoa* another_stack =
101 static_cast<PanelStackWindowCocoa*>(another);
102
103 for (Panels::const_iterator iter = another_stack->panels_.begin();
104 iter != another_stack->panels_.end(); ++iter) {
105 Panel* panel = *iter;
106 panels_.push_back(panel);
107
108 // Change the panel window owner.
109 NSWindow* panel_window = panel->GetNativeWindow();
110 [another_stack->window_ removeChildWindow:panel_window];
111 [window_ addChildWindow:panel_window ordered:NSWindowAbove];
112 }
113 another_stack->panels_.clear();
114
115 UpdateStackWindowBounds();
116 }
117
118 bool PanelStackWindowCocoa::IsEmpty() const {
119 return panels_.empty();
120 }
121
122 bool PanelStackWindowCocoa::HasPanel(Panel* panel) const {
123 return std::find(panels_.begin(), panels_.end(), panel) != panels_.end();
124 }
125
126 void PanelStackWindowCocoa::MovePanelsBy(const gfx::Vector2d& delta) {
127 // Moving the background stack window will cause all foreground panels window
128 // being moved simulatenously.
129 gfx::Rect enclosing_bounds = GetStackWindowBounds();
130 enclosing_bounds.Offset(delta);
131 NSRect frame = cocoa_utils::ConvertRectToCocoaCoordinates(enclosing_bounds);
132 [window_ setFrame:frame display:NO];
133
134 // We also need to update the panel bounds.
135 for (Panels::const_iterator iter = panels_.begin();
136 iter != panels_.end(); ++iter) {
137 Panel* panel = *iter;
138 gfx::Rect bounds = panel->GetBounds();
139 bounds.Offset(delta);
140 panel->SetPanelBoundsInstantly(bounds);
141 }
142 }
143
144 void PanelStackWindowCocoa::BeginBatchUpdatePanelBounds(bool animate) {
145 // If the batch animation is still in progress, continue the animation
146 // with the new target bounds even we want to update the bounds instantly
147 // this time.
148 if (!bounds_updates_started_) {
149 animate_bounds_updates_ = animate;
150 bounds_updates_started_ = true;
151 }
152 }
153
154 void PanelStackWindowCocoa::AddPanelBoundsForBatchUpdate(
155 Panel* panel, const gfx::Rect& new_bounds) {
156 DCHECK(bounds_updates_started_);
157
158 // No need to track it if no change is needed.
159 if (panel->GetBounds() == new_bounds)
160 return;
161
162 // Old bounds are stored as the map value.
163 bounds_updates_[panel] = panel->GetBounds();
164
165 // New bounds are directly applied to the value stored in native panel
166 // window.
167 static_cast<PanelCocoa*>(panel->native_panel())->set_cached_bounds_directly(
168 new_bounds);
169 }
170
171 void PanelStackWindowCocoa::EndBatchUpdatePanelBounds() {
172 DCHECK(bounds_updates_started_);
173
174 // No need to proceed with the animation when the bounds update list is
175 // empty or animation was not requested.
176 if (bounds_updates_.empty() || !animate_bounds_updates_) {
177 // Set the bounds directly when the update list is not empty.
178 if (!bounds_updates_.empty()) {
179 for (BoundsUpdates::const_iterator iter = bounds_updates_.begin();
180 iter != bounds_updates_.end(); ++iter) {
181 Panel* panel = iter->first;
182 NSRect frame =
183 cocoa_utils::ConvertRectToCocoaCoordinates(panel->GetBounds());
184 [panel->GetNativeWindow() setFrame:frame display:YES animate:NO];
185 }
186 bounds_updates_.clear();
187 UpdateStackWindowBounds();
188 }
189
190 bounds_updates_started_ = false;
191 delegate_->PanelBoundsBatchUpdateCompleted();
192 return;
193 }
194
195 // Terminate previous animation, if it is still playing.
196 TerminateBoundsAnimation();
197
198 // Find out if we need the animation for each panel. If the batch updates
199 // consist of only moving all panels by delta offset, moving the background
200 // window would be enough.
201
202 // If all the panels move and don't resize, just animate the underlying
203 // parent window. Otherwise, animate each individual panel.
204 bool need_to_animate_individual_panels = false;
205 if (bounds_updates_.size() == panels_.size()) {
206 gfx::Vector2d delta;
207 for (BoundsUpdates::const_iterator iter = bounds_updates_.begin();
208 iter != bounds_updates_.end(); ++iter) {
209 gfx::Rect old_bounds = iter->second;
210 gfx::Rect new_bounds = iter->first->GetBounds();
211
212 // Size should not be changed.
213 if (old_bounds.width() != new_bounds.width() ||
214 old_bounds.height() != new_bounds.height()) {
215 need_to_animate_individual_panels = true;
216 break;
217 }
218
219 // Origin offset should be same.
220 if (iter == bounds_updates_.begin()) {
221 delta = new_bounds.origin() - old_bounds.origin();
222 } else if (!(delta == new_bounds.origin() - old_bounds.origin())) {
223 need_to_animate_individual_panels = true;
224 break;
225 }
226 }
227 } else {
228 need_to_animate_individual_panels = true;
229 }
230
231 int num_of_animations = 1;
232 if (need_to_animate_individual_panels)
233 num_of_animations += bounds_updates_.size();
234 base::scoped_nsobject<NSMutableArray> animations(
235 [[NSMutableArray alloc] initWithCapacity:num_of_animations]);
236
237 // Add the animation for each panel in the update list.
238 if (need_to_animate_individual_panels) {
239 for (BoundsUpdates::const_iterator iter = bounds_updates_.begin();
240 iter != bounds_updates_.end(); ++iter) {
241 Panel* panel = iter->first;
242 NSRect panel_frame =
243 cocoa_utils::ConvertRectToCocoaCoordinates(panel->GetBounds());
244 NSDictionary* animation = [NSDictionary dictionaryWithObjectsAndKeys:
245 panel->GetNativeWindow(), NSViewAnimationTargetKey,
246 [NSValue valueWithRect:panel_frame], NSViewAnimationEndFrameKey,
247 nil];
248 [animations addObject:animation];
249 }
250 }
251
252 // Compute the final bounds that enclose all panels after the animation.
253 gfx::Rect enclosing_bounds;
254 for (Panels::const_iterator iter = panels_.begin();
255 iter != panels_.end(); ++iter) {
256 gfx::Rect target_bounds = (*iter)->GetBounds();
257 enclosing_bounds = UnionRects(enclosing_bounds, target_bounds);
258 }
259
260 // Add the animation for the background stack window.
261 NSRect enclosing_frame =
262 cocoa_utils::ConvertRectToCocoaCoordinates(enclosing_bounds);
263 NSDictionary* stack_animation = [NSDictionary dictionaryWithObjectsAndKeys:
264 window_.get(), NSViewAnimationTargetKey,
265 [NSValue valueWithRect:enclosing_frame], NSViewAnimationEndFrameKey,
266 nil];
267 [animations addObject:stack_animation];
268
269 // Start all the animations.
270 // |bounds_animation_| is released when the animation ends.
271 bounds_animation_ =
272 [[NSViewAnimation alloc] initWithViewAnimations:animations];
273 [bounds_animation_ setDelegate:bounds_animation_delegate_.get()];
274 [bounds_animation_ setDuration:PanelManager::AdjustTimeInterval(0.18)];
275 [bounds_animation_ setFrameRate:0.0];
276 [bounds_animation_ setAnimationBlockingMode: NSAnimationNonblocking];
277 [bounds_animation_ startAnimation];
278 }
279
280 bool PanelStackWindowCocoa::IsAnimatingPanelBounds() const {
281 return bounds_updates_started_ && animate_bounds_updates_;
282 }
283
284 void PanelStackWindowCocoa::BoundsUpdateAnimationEnded() {
285 bounds_updates_started_ = false;
286
287 for (BoundsUpdates::const_iterator iter = bounds_updates_.begin();
288 iter != bounds_updates_.end(); ++iter) {
289 Panel* panel = iter->first;
290 panel->manager()->OnPanelAnimationEnded(panel);
291 }
292 bounds_updates_.clear();
293
294 delegate_->PanelBoundsBatchUpdateCompleted();
295 }
296
297 void PanelStackWindowCocoa::Minimize() {
298 // Provide the custom miniwindow image since there is nothing painted for
299 // the background stack window.
300 gfx::Size stack_window_size = GetStackWindowBounds().size();
301 gfx::Canvas canvas(stack_window_size, 1.0f, true);
302 int y = 0;
303 Panels::const_iterator iter = panels_.begin();
304 for (; iter != panels_.end(); ++iter) {
305 Panel* panel = *iter;
306 gfx::Rect snapshot_bounds = gfx::Rect(panel->GetBounds().size());
307 std::vector<unsigned char> png;
308 if (!ui::GrabWindowSnapshot(panel->GetNativeWindow(),
309 &png,
310 snapshot_bounds))
311 break;
312 gfx::Image snapshot_image = gfx::Image::CreateFrom1xPNGBytes(
313 &(png[0]), png.size());
314 canvas.DrawImageInt(snapshot_image.AsImageSkia(), 0, y);
315 y += snapshot_bounds.height();
316 }
317 if (iter == panels_.end()) {
318 gfx::Image image(gfx::ImageSkia(canvas.ExtractImageRep()));
319 [window_ setMiniwindowImage:image.AsNSImage()];
320 }
321
322 [window_ miniaturize:nil];
323 }
324
325 bool PanelStackWindowCocoa::IsMinimized() const {
326 return [window_ isMiniaturized];
327 }
328
329 void PanelStackWindowCocoa::DrawSystemAttention(bool draw_attention) {
330 BOOL is_drawing_attention = attention_request_id_ != 0;
331 if (draw_attention == is_drawing_attention)
332 return;
333
334 if (draw_attention) {
335 attention_request_id_ = [NSApp requestUserAttention:NSCriticalRequest];
336 } else {
337 [NSApp cancelUserAttentionRequest:attention_request_id_];
338 attention_request_id_ = 0;
339 }
340 }
341
342 void PanelStackWindowCocoa::OnPanelActivated(Panel* panel) {
343 // Nothing to do.
344 }
345
346 void PanelStackWindowCocoa::TerminateBoundsAnimation() {
347 if (!bounds_animation_)
348 return;
349 [bounds_animation_ stopAnimation];
350 [bounds_animation_ setDelegate:nil];
351 [bounds_animation_ release];
352 bounds_animation_ = nil;
353 }
354
355 gfx::Rect PanelStackWindowCocoa::GetStackWindowBounds() const {
356 gfx::Rect enclosing_bounds;
357 for (Panels::const_iterator iter = panels_.begin();
358 iter != panels_.end(); ++iter) {
359 Panel* panel = *iter;
360 enclosing_bounds = UnionRects(enclosing_bounds, panel->GetBounds());
361 }
362 return enclosing_bounds;
363 }
364
365 void PanelStackWindowCocoa::UpdateStackWindowBounds() {
366 NSRect enclosing_bounds =
367 cocoa_utils::ConvertRectToCocoaCoordinates(GetStackWindowBounds());
368 [window_ setFrame:enclosing_bounds display:NO];
369 }
370
371 void PanelStackWindowCocoa::EnsureWindowCreated() {
372 if (window_)
373 return;
374
375 window_.reset(
376 [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
377 styleMask:NSBorderlessWindowMask
378 backing:NSBackingStoreBuffered
379 defer:NO]);
380 [window_ setBackgroundColor:[NSColor clearColor]];
381 [window_ setHasShadow:YES];
382 [window_ setLevel:NSNormalWindowLevel];
383 [window_ orderFront:nil];
384 [window_ setTitle:base::SysUTF16ToNSString(delegate_->GetTitle())];
385 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/panels/panel_stack_window_cocoa.h ('k') | chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698