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: ash/wm/workspace/frame_maximize_button.cc

Issue 23498031: Move code related to the window controls to ash/wm/caption_buttons (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 7 years, 3 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "ash/wm/workspace/frame_maximize_button.h"
6
7 #include "ash/launcher/launcher.h"
8 #include "ash/screen_ash.h"
9 #include "ash/shelf/shelf_widget.h"
10 #include "ash/shell.h"
11 #include "ash/shell_delegate.h"
12 #include "ash/touch/touch_uma.h"
13 #include "ash/wm/maximize_bubble_controller.h"
14 #include "ash/wm/property_util.h"
15 #include "ash/wm/window_animations.h"
16 #include "ash/wm/window_settings.h"
17 #include "ash/wm/workspace/phantom_window_controller.h"
18 #include "ash/wm/workspace/snap_sizer.h"
19 #include "grit/ash_strings.h"
20 #include "ui/aura/client/aura_constants.h"
21 #include "ui/aura/window.h"
22 #include "ui/base/events/event.h"
23 #include "ui/base/events/event_handler.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/resource/resource_bundle.h"
26 #include "ui/gfx/image/image.h"
27 #include "ui/gfx/screen.h"
28 #include "ui/views/widget/widget.h"
29 #include "ui/views/window/non_client_view.h"
30
31 using ash::internal::SnapSizer;
32
33 namespace ash {
34
35 namespace {
36
37 // Delay before forcing an update of the snap location.
38 const int kUpdateDelayMS = 400;
39
40 // The delay of the bubble appearance.
41 const int kBubbleAppearanceDelayMS = 500;
42
43 // The minimum sanp size in percent of the screen width.
44 const int kMinSnapSizePercent = 50;
45 }
46
47 // EscapeEventFilter is installed on the RootWindow to track when the escape key
48 // is pressed. We use an EventFilter for this as the FrameMaximizeButton
49 // normally does not get focus.
50 class FrameMaximizeButton::EscapeEventFilter : public ui::EventHandler {
51 public:
52 explicit EscapeEventFilter(FrameMaximizeButton* button);
53 virtual ~EscapeEventFilter();
54
55 // EventFilter overrides:
56 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
57
58 private:
59 FrameMaximizeButton* button_;
60
61 DISALLOW_COPY_AND_ASSIGN(EscapeEventFilter);
62 };
63
64 FrameMaximizeButton::EscapeEventFilter::EscapeEventFilter(
65 FrameMaximizeButton* button)
66 : button_(button) {
67 Shell::GetInstance()->AddPreTargetHandler(this);
68 }
69
70 FrameMaximizeButton::EscapeEventFilter::~EscapeEventFilter() {
71 Shell::GetInstance()->RemovePreTargetHandler(this);
72 }
73
74 void FrameMaximizeButton::EscapeEventFilter::OnKeyEvent(
75 ui::KeyEvent* event) {
76 if (event->type() == ui::ET_KEY_PRESSED &&
77 event->key_code() == ui::VKEY_ESCAPE) {
78 button_->Cancel(false);
79 }
80 }
81
82 // FrameMaximizeButton ---------------------------------------------------------
83
84 FrameMaximizeButton::FrameMaximizeButton(views::ButtonListener* listener,
85 views::NonClientFrameView* frame)
86 : ImageButton(listener),
87 frame_(frame),
88 is_snap_enabled_(false),
89 exceeded_drag_threshold_(false),
90 widget_(NULL),
91 press_is_gesture_(false),
92 snap_type_(SNAP_NONE),
93 bubble_appearance_delay_ms_(kBubbleAppearanceDelayMS) {
94 // TODO(sky): nuke this. It's temporary while we don't have good images.
95 SetImageAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
96
97 if (ash::Shell::IsForcedMaximizeMode())
98 views::View::SetVisible(false);
99 }
100
101 FrameMaximizeButton::~FrameMaximizeButton() {
102 // Before the window gets destroyed, the maximizer dialog needs to be shut
103 // down since it would otherwise call into a deleted object.
104 maximizer_.reset();
105 if (widget_)
106 OnWindowDestroying(widget_->GetNativeWindow());
107 }
108
109 void FrameMaximizeButton::SnapButtonHovered(SnapType type) {
110 // Make sure to only show hover operations when no button is pressed and
111 // a similar snap operation in progress does not get re-applied.
112 if (is_snap_enabled_ || (type == snap_type_ && snap_sizer_))
113 return;
114 // Prime the mouse location with the center of the (local) button.
115 press_location_ = gfx::Point(width() / 2, height() / 2);
116 // Then get an adjusted mouse position to initiate the effect.
117 gfx::Point location = press_location_;
118 switch (type) {
119 case SNAP_LEFT:
120 location.set_x(location.x() - width());
121 break;
122 case SNAP_RIGHT:
123 location.set_x(location.x() + width());
124 break;
125 case SNAP_MINIMIZE:
126 location.set_y(location.y() + height());
127 break;
128 case SNAP_RESTORE:
129 // Simulate a mouse button move over the according button.
130 if (GetMaximizeBubbleFrameState() == FRAME_STATE_SNAP_LEFT)
131 location.set_x(location.x() - width());
132 else if (GetMaximizeBubbleFrameState() == FRAME_STATE_SNAP_RIGHT)
133 location.set_x(location.x() + width());
134 break;
135 case SNAP_MAXIMIZE:
136 break;
137 case SNAP_NONE:
138 Cancel(true);
139 return;
140 default:
141 // We should not come here.
142 NOTREACHED();
143 }
144 // Note: There is no hover with touch - we can therefore pass false for touch
145 // operations.
146 UpdateSnap(location, true, false);
147 }
148
149 void FrameMaximizeButton::ExecuteSnapAndCloseMenu(SnapType snap_type) {
150 // We can come here with no snap type set in case that the mouse opened the
151 // maximize button and a touch event "touched" a button.
152 if (snap_type_ == SNAP_NONE)
153 SnapButtonHovered(snap_type);
154
155 Cancel(true);
156 // Tell our menu to close.
157 maximizer_.reset();
158 snap_type_ = snap_type;
159 // Since Snap might destroy |this|, but the snap_sizer needs to be destroyed,
160 // The ownership of the snap_sizer is taken now.
161 scoped_ptr<SnapSizer> snap_sizer(snap_sizer_.release());
162 Snap(*snap_sizer.get());
163 }
164
165 void FrameMaximizeButton::DestroyMaximizeMenu() {
166 Cancel(false);
167 }
168
169 void FrameMaximizeButton::OnWindowBoundsChanged(
170 aura::Window* window,
171 const gfx::Rect& old_bounds,
172 const gfx::Rect& new_bounds) {
173 Cancel(false);
174 }
175
176 void FrameMaximizeButton::OnWindowPropertyChanged(aura::Window* window,
177 const void* key,
178 intptr_t old) {
179 Cancel(false);
180 }
181
182 void FrameMaximizeButton::OnWindowDestroying(aura::Window* window) {
183 maximizer_.reset();
184 if (widget_) {
185 CHECK_EQ(widget_->GetNativeWindow(), window);
186 widget_->GetNativeWindow()->RemoveObserver(this);
187 widget_->RemoveObserver(this);
188 widget_ = NULL;
189 }
190 }
191
192 void FrameMaximizeButton::OnWidgetActivationChanged(views::Widget* widget,
193 bool active) {
194 // Upon losing focus, the control bubble should hide.
195 if (!active && maximizer_)
196 maximizer_.reset();
197 }
198
199 bool FrameMaximizeButton::OnMousePressed(const ui::MouseEvent& event) {
200 // If we are already in a mouse click / drag operation, a second button down
201 // call will cancel (this addresses crbug.com/143755).
202 if (is_snap_enabled_) {
203 Cancel(false);
204 } else {
205 is_snap_enabled_ = event.IsOnlyLeftMouseButton();
206 if (is_snap_enabled_)
207 ProcessStartEvent(event);
208 }
209 ImageButton::OnMousePressed(event);
210 return true;
211 }
212
213 void FrameMaximizeButton::OnMouseEntered(const ui::MouseEvent& event) {
214 ImageButton::OnMouseEntered(event);
215 if (!maximizer_) {
216 DCHECK(GetWidget());
217 if (!widget_) {
218 widget_ = frame_->GetWidget();
219 widget_->GetNativeWindow()->AddObserver(this);
220 widget_->AddObserver(this);
221 }
222 maximizer_.reset(new MaximizeBubbleController(
223 this,
224 GetMaximizeBubbleFrameState(),
225 bubble_appearance_delay_ms_));
226 }
227 }
228
229 void FrameMaximizeButton::OnMouseExited(const ui::MouseEvent& event) {
230 ImageButton::OnMouseExited(event);
231 // Remove the bubble menu when the button is not pressed and the mouse is not
232 // within the bubble.
233 if (!is_snap_enabled_ && maximizer_) {
234 if (maximizer_->GetBubbleWindow()) {
235 gfx::Point screen_location = Shell::GetScreen()->GetCursorScreenPoint();
236 if (!maximizer_->GetBubbleWindow()->GetBoundsInScreen().Contains(
237 screen_location)) {
238 maximizer_.reset();
239 // Make sure that all remaining snap hover states get removed.
240 SnapButtonHovered(SNAP_NONE);
241 }
242 } else {
243 // The maximize dialog does not show up immediately after creating the
244 // |mazimizer_|. Destroy the dialog therefore before it shows up.
245 maximizer_.reset();
246 }
247 }
248 }
249
250 bool FrameMaximizeButton::OnMouseDragged(const ui::MouseEvent& event) {
251 if (is_snap_enabled_)
252 ProcessUpdateEvent(event);
253 return ImageButton::OnMouseDragged(event);
254 }
255
256 void FrameMaximizeButton::OnMouseReleased(const ui::MouseEvent& event) {
257 maximizer_.reset();
258 bool snap_was_enabled = is_snap_enabled_;
259 if (!ProcessEndEvent(event) && snap_was_enabled)
260 ImageButton::OnMouseReleased(event);
261 // At this point |this| might be already destroyed.
262 }
263
264 void FrameMaximizeButton::OnMouseCaptureLost() {
265 Cancel(false);
266 ImageButton::OnMouseCaptureLost();
267 }
268
269 void FrameMaximizeButton::OnGestureEvent(ui::GestureEvent* event) {
270 if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
271 is_snap_enabled_ = true;
272 ProcessStartEvent(*event);
273 event->SetHandled();
274 return;
275 }
276
277 if (event->type() == ui::ET_GESTURE_TAP ||
278 (event->type() == ui::ET_GESTURE_SCROLL_END && is_snap_enabled_) ||
279 event->type() == ui::ET_SCROLL_FLING_START) {
280 // The position of the event may have changed from the previous event (both
281 // for TAP and SCROLL_END). So it is necessary to update the snap-state for
282 // the current event.
283 ProcessUpdateEvent(*event);
284 if (event->type() == ui::ET_GESTURE_TAP) {
285 snap_type_ = SnapTypeForLocation(event->location());
286 TouchUMA::GetInstance()->RecordGestureAction(
287 TouchUMA::GESTURE_FRAMEMAXIMIZE_TAP);
288 }
289 ProcessEndEvent(*event);
290 event->SetHandled();
291 return;
292 }
293
294 if (is_snap_enabled_) {
295 if (event->type() == ui::ET_GESTURE_END &&
296 event->details().touch_points() == 1) {
297 // The position of the event may have changed from the previous event. So
298 // it is necessary to update the snap-state for the current event.
299 ProcessUpdateEvent(*event);
300 snap_type_ = SnapTypeForLocation(event->location());
301 ProcessEndEvent(*event);
302 event->SetHandled();
303 return;
304 }
305
306 if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE ||
307 event->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
308 ProcessUpdateEvent(*event);
309 event->SetHandled();
310 return;
311 }
312 }
313
314 ImageButton::OnGestureEvent(event);
315 }
316
317 void FrameMaximizeButton::SetVisible(bool visible) {
318 // In the enforced maximized mode we do not allow to be made visible.
319 if (ash::Shell::IsForcedMaximizeMode())
320 return;
321
322 views::View::SetVisible(visible);
323 }
324
325 void FrameMaximizeButton::ProcessStartEvent(const ui::LocatedEvent& event) {
326 DCHECK(is_snap_enabled_);
327 // Prepare the help menu.
328 if (!maximizer_) {
329 maximizer_.reset(new MaximizeBubbleController(
330 this,
331 GetMaximizeBubbleFrameState(),
332 bubble_appearance_delay_ms_));
333 } else {
334 // If the menu did not show up yet, we delay it even a bit more.
335 maximizer_->DelayCreation();
336 }
337 snap_sizer_.reset(NULL);
338 InstallEventFilter();
339 snap_type_ = SNAP_NONE;
340 press_location_ = event.location();
341 press_is_gesture_ = event.IsGestureEvent();
342 exceeded_drag_threshold_ = false;
343 update_timer_.Start(
344 FROM_HERE,
345 base::TimeDelta::FromMilliseconds(kUpdateDelayMS),
346 this,
347 &FrameMaximizeButton::UpdateSnapFromEventLocation);
348 }
349
350 void FrameMaximizeButton::ProcessUpdateEvent(const ui::LocatedEvent& event) {
351 DCHECK(is_snap_enabled_);
352 if (!exceeded_drag_threshold_) {
353 exceeded_drag_threshold_ = views::View::ExceededDragThreshold(
354 event.location() - press_location_);
355 }
356 if (exceeded_drag_threshold_)
357 UpdateSnap(event.location(), false, event.IsGestureEvent());
358 }
359
360 bool FrameMaximizeButton::ProcessEndEvent(const ui::LocatedEvent& event) {
361 update_timer_.Stop();
362 UninstallEventFilter();
363 bool should_snap = is_snap_enabled_;
364 is_snap_enabled_ = false;
365
366 // Remove our help bubble.
367 maximizer_.reset();
368
369 if (!should_snap || snap_type_ == SNAP_NONE)
370 return false;
371
372 SetState(views::CustomButton::STATE_NORMAL);
373 // SetState will not call SchedulePaint() if state was already set to
374 // STATE_NORMAL during a drag.
375 SchedulePaint();
376 phantom_window_.reset();
377 // Since Snap might destroy |this|, but the snap_sizer needs to be destroyed,
378 // The ownership of the snap_sizer is taken now.
379 scoped_ptr<SnapSizer> snap_sizer(snap_sizer_.release());
380 Snap(*snap_sizer.get());
381 return true;
382 }
383
384 void FrameMaximizeButton::Cancel(bool keep_menu_open) {
385 if (!keep_menu_open) {
386 maximizer_.reset();
387 UninstallEventFilter();
388 is_snap_enabled_ = false;
389 snap_sizer_.reset();
390 }
391 phantom_window_.reset();
392 snap_type_ = SNAP_NONE;
393 update_timer_.Stop();
394 SchedulePaint();
395 }
396
397 void FrameMaximizeButton::InstallEventFilter() {
398 if (escape_event_filter_)
399 return;
400
401 escape_event_filter_.reset(new EscapeEventFilter(this));
402 }
403
404 void FrameMaximizeButton::UninstallEventFilter() {
405 escape_event_filter_.reset(NULL);
406 }
407
408 void FrameMaximizeButton::UpdateSnapFromEventLocation() {
409 // If the drag threshold has been exceeded the snap location is up to date.
410 if (exceeded_drag_threshold_)
411 return;
412 exceeded_drag_threshold_ = true;
413 UpdateSnap(press_location_, false, press_is_gesture_);
414 }
415
416 void FrameMaximizeButton::UpdateSnap(const gfx::Point& location,
417 bool select_default,
418 bool is_touch) {
419 SnapType type = SnapTypeForLocation(location);
420 if (type == snap_type_) {
421 if (snap_sizer_) {
422 snap_sizer_->Update(LocationForSnapSizer(location));
423 phantom_window_->Show(ScreenAsh::ConvertRectToScreen(
424 frame_->GetWidget()->GetNativeView()->parent(),
425 snap_sizer_->target_bounds()));
426 }
427 return;
428 }
429
430 snap_type_ = type;
431 snap_sizer_.reset();
432 SchedulePaint();
433
434 if (snap_type_ == SNAP_NONE) {
435 phantom_window_.reset();
436 return;
437 }
438
439 if (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT) {
440 SnapSizer::Edge snap_edge = snap_type_ == SNAP_LEFT ?
441 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE;
442 SnapSizer::InputType input_type =
443 is_touch ? SnapSizer::TOUCH_MAXIMIZE_BUTTON_INPUT :
444 SnapSizer::OTHER_INPUT;
445 snap_sizer_.reset(new SnapSizer(frame_->GetWidget()->GetNativeWindow(),
446 LocationForSnapSizer(location),
447 snap_edge,
448 input_type));
449 if (select_default)
450 snap_sizer_->SelectDefaultSizeAndDisableResize();
451 }
452 if (!phantom_window_) {
453 phantom_window_.reset(new internal::PhantomWindowController(
454 frame_->GetWidget()->GetNativeWindow()));
455 }
456 if (maximizer_) {
457 phantom_window_->set_phantom_below_window(maximizer_->GetBubbleWindow());
458 maximizer_->SetSnapType(snap_type_);
459 }
460 phantom_window_->Show(
461 ScreenBoundsForType(snap_type_, *snap_sizer_.get()));
462 }
463
464 SnapType FrameMaximizeButton::SnapTypeForLocation(
465 const gfx::Point& location) const {
466 MaximizeBubbleFrameState maximize_type = GetMaximizeBubbleFrameState();
467 gfx::Vector2d delta(location - press_location_);
468 if (!views::View::ExceededDragThreshold(delta))
469 return maximize_type != FRAME_STATE_FULL ? SNAP_MAXIMIZE : SNAP_RESTORE;
470 if (delta.x() < 0 && delta.y() > delta.x() && delta.y() < -delta.x())
471 return maximize_type == FRAME_STATE_SNAP_LEFT ? SNAP_RESTORE : SNAP_LEFT;
472 if (delta.x() > 0 && delta.y() > -delta.x() && delta.y() < delta.x())
473 return maximize_type == FRAME_STATE_SNAP_RIGHT ? SNAP_RESTORE : SNAP_RIGHT;
474 if (delta.y() > 0)
475 return SNAP_MINIMIZE;
476 return maximize_type != FRAME_STATE_FULL ? SNAP_MAXIMIZE : SNAP_RESTORE;
477 }
478
479 gfx::Rect FrameMaximizeButton::ScreenBoundsForType(
480 SnapType type,
481 const SnapSizer& snap_sizer) const {
482 aura::Window* window = frame_->GetWidget()->GetNativeWindow();
483 switch (type) {
484 case SNAP_LEFT:
485 case SNAP_RIGHT:
486 return ScreenAsh::ConvertRectToScreen(
487 frame_->GetWidget()->GetNativeView()->parent(),
488 snap_sizer.target_bounds());
489 case SNAP_MAXIMIZE:
490 return ScreenAsh::ConvertRectToScreen(
491 window->parent(),
492 ScreenAsh::GetMaximizedWindowBoundsInParent(window));
493 case SNAP_MINIMIZE: {
494 gfx::Rect rect = GetMinimizeAnimationTargetBoundsInScreen(window);
495 if (!rect.IsEmpty()) {
496 // PhantomWindowController insets slightly, outset it so the phantom
497 // doesn't appear inset.
498 rect.Inset(-8, -8);
499 }
500 return rect;
501 }
502 case SNAP_RESTORE: {
503 const gfx::Rect* restore = GetRestoreBoundsInScreen(window);
504 return restore ?
505 *restore : frame_->GetWidget()->GetWindowBoundsInScreen();
506 }
507 case SNAP_NONE:
508 NOTREACHED();
509 }
510 return gfx::Rect();
511 }
512
513 gfx::Point FrameMaximizeButton::LocationForSnapSizer(
514 const gfx::Point& location) const {
515 gfx::Point result(location);
516 views::View::ConvertPointToScreen(this, &result);
517 return result;
518 }
519
520 void FrameMaximizeButton::Snap(const SnapSizer& snap_sizer) {
521 ash::Shell* shell = ash::Shell::GetInstance();
522 views::Widget* widget = frame_->GetWidget();
523 switch (snap_type_) {
524 case SNAP_LEFT:
525 case SNAP_RIGHT: {
526 shell->delegate()->RecordUserMetricsAction(
527 snap_type_ == SNAP_LEFT ?
528 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_LEFT :
529 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_RIGHT);
530 // Get the bounds in screen coordinates for restore purposes.
531 gfx::Rect restore = widget->GetWindowBoundsInScreen();
532 if (widget->IsMaximized() || widget->IsFullscreen()) {
533 aura::Window* window = widget->GetNativeWindow();
534 // In case of maximized we have a restore boundary.
535 DCHECK(ash::GetRestoreBoundsInScreen(window));
536 // If it was maximized we need to recover the old restore set.
537 restore = *ash::GetRestoreBoundsInScreen(window);
538
539 // The auto position manager will kick in when this is the only window.
540 // To avoid interference with it we tell it temporarily to not change
541 // the coordinates of this window.
542 wm::WindowSettings* settings = wm::GetWindowSettings(window);
543 bool was_managed = settings->window_position_managed();
544 settings->set_window_position_managed(false);
545
546 // Set the restore size we want to restore to.
547 ash::SetRestoreBoundsInScreen(window,
548 ScreenBoundsForType(snap_type_,
549 snap_sizer));
550 widget->Restore();
551
552 // After the window is where we want it to be we allow the window to be
553 // auto managed again.
554 settings->set_window_position_managed(was_managed);
555 } else {
556 // Others might also have set up a restore rectangle already. If so,
557 // we should not overwrite the restore rectangle.
558 bool restore_set =
559 GetRestoreBoundsInScreen(widget->GetNativeWindow()) != NULL;
560 widget->SetBounds(ScreenBoundsForType(snap_type_, snap_sizer));
561 if (restore_set)
562 break;
563 }
564 // Remember the widow's bounds for restoration.
565 ash::SetRestoreBoundsInScreen(widget->GetNativeWindow(), restore);
566 break;
567 }
568 case SNAP_MAXIMIZE:
569 widget->Maximize();
570 shell->delegate()->RecordUserMetricsAction(
571 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE);
572 break;
573 case SNAP_MINIMIZE:
574 widget->Minimize();
575 shell->delegate()->RecordUserMetricsAction(
576 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MINIMIZE);
577 break;
578 case SNAP_RESTORE:
579 widget->Restore();
580 shell->delegate()->RecordUserMetricsAction(
581 ash::UMA_WINDOW_MAXIMIZE_BUTTON_RESTORE);
582 break;
583 case SNAP_NONE:
584 NOTREACHED();
585 }
586 }
587
588 MaximizeBubbleFrameState
589 FrameMaximizeButton::GetMaximizeBubbleFrameState() const {
590 // When there are no restore bounds, we are in normal mode.
591 if (!ash::GetRestoreBoundsInScreen(
592 frame_->GetWidget()->GetNativeWindow()))
593 return FRAME_STATE_NONE;
594 // The normal maximized test can be used.
595 if (frame_->GetWidget()->IsMaximized())
596 return FRAME_STATE_FULL;
597 // For Left/right maximize we need to check the dimensions.
598 gfx::Rect bounds = frame_->GetWidget()->GetWindowBoundsInScreen();
599 gfx::Rect screen = Shell::GetScreen()->GetDisplayNearestWindow(
600 frame_->GetWidget()->GetNativeView()).work_area();
601 if (bounds.width() < (screen.width() * kMinSnapSizePercent) / 100)
602 return FRAME_STATE_NONE;
603 // We might still have a horizontally filled window at this point which we
604 // treat as no special state.
605 if (bounds.y() != screen.y() || bounds.height() != screen.height())
606 return FRAME_STATE_NONE;
607
608 // We have to be in a maximize mode at this point.
609 if (bounds.x() == screen.x())
610 return FRAME_STATE_SNAP_LEFT;
611 if (bounds.right() == screen.right())
612 return FRAME_STATE_SNAP_RIGHT;
613 // If we come here, it is likely caused by the fact that the
614 // "VerticalResizeDoubleClick" stored a restore rectangle. In that case
615 // we allow all maximize operations (and keep the restore rectangle).
616 return FRAME_STATE_NONE;
617 }
618
619 } // namespace ash
OLDNEW
« no previous file with comments | « ash/wm/workspace/frame_maximize_button.h ('k') | ash/wm/workspace/maximize_bubble_frame_state.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698