#include "ash/root_window_controller.h"
#include "ash/screen_util.h"
#include "ash/shell_window_ids.h"
+#include "ash/wm/default_state.h"
#include "ash/wm/window_properties.h"
#include "ash/wm/window_state_delegate.h"
#include "ash/wm/window_state_observer.h"
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/layout_manager.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/display.h"
#include "ui/views/corewm/window_util.h"
namespace ash {
namespace wm {
+namespace {
+
+// A tentative class to set the bounds on the window.
+// TODO(oshima): Once all logic is cleaned up, move this to the real layout
+// manager with proper friendship.
+class BoundsSetter : public aura::LayoutManager {
+ public:
+ BoundsSetter() {}
+ virtual ~BoundsSetter() {}
+
+ // aura::LayoutManager overrides:
+ virtual void OnWindowResized() OVERRIDE {}
+ virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {}
+ virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {}
+ virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {}
+ virtual void OnChildWindowVisibilityChanged(
+ aura::Window* child, bool visible) OVERRIDE {}
+ virtual void SetChildBounds(
+ aura::Window* child, const gfx::Rect& requested_bounds) OVERRIDE {}
+
+ void SetBounds(aura::Window* window, const gfx::Rect& bounds) {
+ SetChildBoundsDirect(window, bounds);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BoundsSetter);
+};
+
+WMEvent WMEventFromShowState(ui::WindowShowState requested_show_state) {
+ switch (requested_show_state) {
+ case ui::SHOW_STATE_DEFAULT:
+ case ui::SHOW_STATE_NORMAL:
+ return NORMAL;
+ case ui::SHOW_STATE_MINIMIZED:
+ return MINIMIZE;
+ case ui::SHOW_STATE_MAXIMIZED:
+ return MAXIMIZE;
+ case ui::SHOW_STATE_FULLSCREEN:
+ return FULLSCREEN;
+ case ui::SHOW_STATE_INACTIVE:
+ return SHOW_INACTIVE;
+ case ui::SHOW_STATE_DETACHED:
+ case ui::SHOW_STATE_END:
+ NOTREACHED() << "No WMEvent defined for the show type:"
+ << requested_show_state;
+ }
+ return NORMAL;
+}
+
+} // namespace
+
WindowState::WindowState(aura::Window* window)
: window_(window),
window_position_managed_(false),
ignored_by_shelf_(false),
can_consume_system_keys_(false),
top_row_keys_are_function_keys_(false),
- always_restores_to_restore_bounds_(false),
+ unminimize_to_restore_bounds_(false),
hide_shelf_when_fullscreen_(true),
animate_to_fullscreen_(true),
minimum_visibility_(false),
- in_set_window_show_type_(false),
- window_show_type_(ToWindowShowType(GetShowState())) {
+ ignore_property_change_(false),
+ window_show_type_(ToWindowShowType(GetShowState())),
+ current_state_(new DefaultState) {
window_->AddObserver(this);
-
#if defined(OS_CHROMEOS)
// NOTE(pkotwicz): Animating to immersive fullscreen does not look good. When
// switches::UseImmersiveFullscreenForAllWindows() returns true, most windows
}
bool WindowState::IsNormalShowState() const {
- ui::WindowShowState state = window_->GetProperty(aura::client::kShowStateKey);
+ ui::WindowShowState state = GetShowState();
return state == ui::SHOW_STATE_NORMAL || state == ui::SHOW_STATE_DEFAULT;
}
+bool WindowState::IsNormalShowType() const {
+ return window_show_type_ == SHOW_TYPE_NORMAL ||
+ window_show_type_ == SHOW_TYPE_DEFAULT;
+}
+
bool WindowState::IsActive() const {
return IsActiveWindow(window_);
}
}
void WindowState::Restore() {
- window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+ if (!IsNormalShowType())
+ OnWMEvent(NORMAL);
}
-void WindowState::ToggleMaximized() {
- if (IsMaximized())
- Restore();
- else if (CanMaximize())
- Maximize();
+void WindowState::ToggleFullscreen() {
+ OnWMEvent(TOGGLE_FULLSCREEN);
}
-void WindowState::ToggleFullscreen() {
- // Window which cannot be maximized should not be fullscreened.
- // It can, however, be restored if it was fullscreened.
- bool is_fullscreen = IsFullscreen();
- if (!is_fullscreen && !CanMaximize())
- return;
- if (delegate_ && delegate_->ToggleFullscreen(this))
- return;
- if (is_fullscreen) {
- Restore();
- } else {
- window_->SetProperty(aura::client::kShowStateKey,
- ui::SHOW_STATE_FULLSCREEN);
- }
+void WindowState::OnWMEvent(WMEvent event) {
+ current_state_->OnWMEvent(this, event);
}
void WindowState::SetBoundsInScreen(
observer_list_.RemoveObserver(observer);
}
-bool WindowState::CreateDragDetails(aura::Window* window,
+void WindowState::CreateDragDetails(aura::Window* window,
const gfx::Point& point_in_parent,
int window_component,
aura::client::WindowMoveSource source) {
- scoped_ptr<DragDetails> details(new DragDetails(
- window, point_in_parent, window_component, source));
- if (!details->is_resizable)
- return false;
- drag_details_ = details.Pass();
- return true;
+ drag_details_.reset(
+ new DragDetails(window, point_in_parent, window_component, source));
}
void WindowState::DeleteDragDetails() {
drag_details_.reset();
}
+void WindowState::SetAndClearRestoreBounds() {
+ DCHECK(HasRestoreBounds());
+ SetBoundsInScreen(GetRestoreBoundsInScreen());
+ ClearRestoreBounds();
+}
+
+void WindowState::AdjustSnappedBounds(gfx::Rect* bounds) {
+ if (is_dragged() || !IsSnapped())
+ return;
+ gfx::Rect maximized_bounds = ScreenUtil::GetMaximizedWindowBoundsInParent(
+ window_);
+ if (window_show_type() == SHOW_TYPE_LEFT_SNAPPED)
+ bounds->set_x(maximized_bounds.x());
+ else if (window_show_type() == SHOW_TYPE_RIGHT_SNAPPED)
+ bounds->set_x(maximized_bounds.right() - bounds->width());
+ bounds->set_y(maximized_bounds.y());
+ bounds->set_height(maximized_bounds.height());
+}
+
void WindowState::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
DCHECK_EQ(window, window_);
- if (key == aura::client::kShowStateKey)
- SetWindowShowType(ToWindowShowType(GetShowState()));
+ if (key == aura::client::kShowStateKey && !ignore_property_change_)
+ OnWMEvent(WMEventFromShowState(GetShowState()));
}
void WindowState::SnapWindow(WindowShowType left_or_right,
DCHECK(left_or_right == SHOW_TYPE_LEFT_SNAPPED ||
left_or_right == SHOW_TYPE_RIGHT_SNAPPED);
- SetWindowShowType(left_or_right);
+ OnWMEvent(left_or_right == SHOW_TYPE_LEFT_SNAPPED ?
+ SNAP_LEFT : SNAP_RIGHT);
+
// TODO(varkha): Ideally the bounds should be changed in a LayoutManager upon
// observing the WindowShowType change.
// If the window is a child of kShellWindowId_DockedContainer such as during
SetRestoreBoundsInScreen(restore_bounds_in_screen);
}
-void WindowState::SetWindowShowType(WindowShowType new_window_show_type) {
- if (in_set_window_show_type_)
- return;
- base::AutoReset<bool> resetter(&in_set_window_show_type_, true);
-
+void WindowState::UpdateWindowShowType(WindowShowType new_window_show_type) {
ui::WindowShowState new_window_state =
ToWindowShowState(new_window_show_type);
- if (new_window_state != GetShowState())
+ if (new_window_state != GetShowState()) {
+ base::AutoReset<bool> resetter(&ignore_property_change_, true);
window_->SetProperty(aura::client::kShowStateKey, new_window_state);
- WindowShowType old_window_show_type = window_show_type_;
- window_show_type_ = new_window_show_type;
- if (old_window_show_type != window_show_type_) {
- FOR_EACH_OBSERVER(WindowStateObserver, observer_list_,
- OnWindowShowTypeChanged(this, old_window_show_type));
}
+ window_show_type_ = new_window_show_type;
+}
+
+void WindowState::NotifyPreShowTypeChange(WindowShowType old_window_show_type) {
+ FOR_EACH_OBSERVER(WindowStateObserver, observer_list_,
+ OnPreWindowShowTypeChange(this, old_window_show_type));
+}
+
+void WindowState::NotifyPostShowTypeChange(
+ WindowShowType old_window_show_type) {
+ FOR_EACH_OBSERVER(WindowStateObserver, observer_list_,
+ OnPostWindowShowTypeChange(this, old_window_show_type));
+}
+
+void WindowState::SetBoundsDirect(const gfx::Rect& bounds) {
+ BoundsSetter().SetBounds(window_, bounds);
+}
+
+void WindowState::SetBoundsDirectAnimated(const gfx::Rect& bounds) {
+ const int kBoundsChangeSlideDurationMs = 120;
+
+ ui::Layer* layer = window_->layer();
+ ui::ScopedLayerAnimationSettings slide_settings(layer->GetAnimator());
+ slide_settings.SetPreemptionStrategy(
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+ slide_settings.SetTransitionDuration(
+ base::TimeDelta::FromMilliseconds(kBoundsChangeSlideDurationMs));
+ SetBoundsDirect(bounds);
}
WindowState* GetActiveWindowState() {