blob: f41e57dbaa9f2ceb6653d6c2f1bce22ce9ae6071 [file] [log] [blame]
// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "window_manager/layout2/browser_window.h"
#include <map>
#include <string>
#include "base/time.h"
#include "cros/chromeos_wm_ipc_enums.h"
#include "window_manager/atom_cache.h"
#include "window_manager/callback.h"
#include "window_manager/event_consumer_registrar.h"
#include "window_manager/event_loop.h"
#include "window_manager/layout2/layout_manager2.h"
#include "window_manager/shadow.h"
#include "window_manager/stacking_manager.h"
#include "window_manager/transient_window_collection.h"
#include "window_manager/window.h"
#include "window_manager/window_manager.h"
using base::TimeDelta;
using std::map;
using std::string;
namespace {
// Distance over which we move the window for the no-op window-switching
// animation.
const int kNudgeAnimPixels = 25;
// Amount of time used for the no-op window-switching animation.
const int kNudgeAnimMs = 180;
// Scale of the browser window in the first and second keyframe of the no-op
// "squish" animation displayed when the user attempts to toggle to overlapping
// mode while there's only a single browser window open.
const double kSquishAnimShrinkScale = 0.975;
const double kSquishAnimReboundScale = 1.0125;
// Total amount of time used for the no-op "squish" animation.
const int kSquishAnimMs = 300;
} // anonymous namespace
namespace window_manager {
BrowserWindow::BrowserWindow(Window* win,
LayoutManager2* layout_manager,
int unmaximized_width)
: win_(win),
event_consumer_registrar_(
new EventConsumerRegistrar(wm(), layout_manager)),
unmaximized_width_(unmaximized_width),
unmaximized_anchoring_(ANCHOR_LEFT),
status_area_displayed_(
!win->chrome_state_xatoms().count(ATOM_CHROME_STATE_STATUS_HIDDEN)),
brightness_(1.0),
transients_(
new TransientWindowCollection(
win, // owner_win
TransientWindowCollection::STACK_IN_LAYER,
TransientWindowCollection::CENTER_OVER_OWNER,
TransientWindowCollection::KEEP_ONSCREEN_IF_OWNER_IS_ONSCREEN,
layout_manager)),
dimming_box_(
wm()->compositor()->CreateColoredBox(
win_->client_width(), win_->client_height(),
Compositor::Color("#000"))) {
DCHECK(ShouldHandleWindow(*win));
wm()->focus_manager()->UseClickToFocusForWindow(
win, FocusManager::PASS_CLICKS_THROUGH);
event_consumer_registrar_->RegisterForWindowEvents(win->xid());
win_->SetVisibility(Window::VISIBILITY_SHOWN);
win_->SetShadowType(Shadow::TYPE_RECTANGULAR);
dimming_box_->SetName(string("dimming box for window ") + win_->xid_str());
dimming_box_->Move(win_->client_x(), win_->client_y(), 0);
dimming_box_->SetOpacity(0, 0);
wm()->stage()->AddActor(dimming_box_.get());
wm()->stacking_manager()->StackActorRelativeToOtherActor(
dimming_box_.get(),
win_->GetTopActor(),
StackingManager::ABOVE_SIBLING);
}
BrowserWindow::~BrowserWindow() {
win_->SetVisibility(Window::VISIBILITY_HIDDEN);
transients_->CloseAllWindows();
win_ = NULL;
}
// static
bool BrowserWindow::ShouldHandleWindow(const Window& win) {
if (win.transient_for_xid())
return false;
return win.type() == chromeos::WM_IPC_WINDOW_CHROME_TOPLEVEL ||
win.type() == chromeos::WM_IPC_WINDOW_UNKNOWN;
}
WindowManager* BrowserWindow::wm() const {
return win_->wm();
}
void BrowserWindow::SetBounds(const Rect& bounds, int anim_ms) {
win_->SetBounds(bounds, anim_ms);
dimming_box_->Move(bounds.x, bounds.y, anim_ms);
dimming_box_->SetSize(bounds.width, bounds.height);
transients_->ConfigureAllWindowsRelativeToOwner(anim_ms);
}
void BrowserWindow::StackAtTopOfLayer(
StackingManager::Layer layer,
StackingManager::ShadowPolicy shadow_policy,
StackingManager::Layer shadow_layer) {
wm()->stacking_manager()->StackWindowAtTopOfLayer(
win_, layer, shadow_policy, shadow_layer);
wm()->stacking_manager()->StackActorRelativeToOtherActor(
dimming_box_.get(),
win_->GetTopActor(),
StackingManager::ABOVE_SIBLING);
transients_->set_stacking_policy(
layer == StackingManager::LAYER_FULLSCREEN_WINDOW ?
TransientWindowCollection::STACK_ABOVE_OWNER :
TransientWindowCollection::STACK_IN_LAYER);
transients_->ApplyStackingForAllWindows();
}
void BrowserWindow::StackBelowOtherBrowserWindow(
BrowserWindow* other_browser,
StackingManager::ShadowPolicy shadow_policy,
StackingManager::Layer shadow_layer) {
DCHECK(other_browser);
// The layer that we pass here is irrelevant since we're stacking our shadow
// directly below our actor rather than at the bottom of the layer.
wm()->stacking_manager()->StackWindowRelativeToOtherWindow(
win_,
other_browser->win(),
StackingManager::BELOW_SIBLING,
shadow_policy,
shadow_layer);
wm()->stacking_manager()->StackActorRelativeToOtherActor(
dimming_box_.get(),
win_->GetTopActor(),
StackingManager::ABOVE_SIBLING);
transients_->set_stacking_policy(TransientWindowCollection::STACK_IN_LAYER);
transients_->ApplyStackingForAllWindows();
}
void BrowserWindow::TakeFocus(XTime timestamp) {
if (!transients_->TakeFocus(timestamp))
wm()->FocusWindow(win_, timestamp);
}
void BrowserWindow::HandleTransientWindowMap(Window* transient_win) {
if (!transient_win->is_rgba())
transient_win->SetShadowType(Shadow::TYPE_RECTANGULAR);
transients_->AddWindow(transient_win);
}
void BrowserWindow::HandleTransientWindowUnmap(Window* transient_win) {
transients_->RemoveWindow(transient_win);
}
void BrowserWindow::HandleTransientWindowConfigureRequest(
Window* transient_win, const Rect& requested_bounds) {
transients_->HandleConfigureRequest(transient_win, requested_bounds);
}
bool BrowserWindow::IsWindowOrTransientFocused() const {
return win_->IsFocused() || transients_->HasFocusedWindow();
}
void BrowserWindow::SetPreferredTransientWindowToFocus(Window* transient_win) {
transients_->SetPreferredWindowToFocus(transient_win);
}
void BrowserWindow::HandleTransientWindowModalityChange(Window* transient_win) {
transients_->HandleWindowModalityChange(transient_win);
}
void BrowserWindow::SetTransientWindowVisibility(bool shown) {
if (shown)
transients_->Show();
else
transients_->Hide();
}
void BrowserWindow::DoNudgeAnimation(bool move_to_left) {
AnimationPair* animations = win_->CreateMoveCompositedAnimation();
animations->AppendKeyframe(
win_->composited_x() + (move_to_left ? -1 : 1) * kNudgeAnimPixels,
win_->composited_y(),
TimeDelta::FromMilliseconds(kNudgeAnimMs / 2));
animations->AppendKeyframe(
win_->composited_x(), win_->composited_y(),
TimeDelta::FromMilliseconds(kNudgeAnimMs / 2));
win_->SetMoveCompositedAnimation(animations);
}
void BrowserWindow::DoSquishAnimation() {
const TimeDelta frame_time = TimeDelta::FromMilliseconds(kSquishAnimMs / 3);
AnimationPair* animations = win_->CreateScaleCompositedAnimation();
animations->AppendKeyframe(kSquishAnimShrinkScale, 1.0, frame_time);
animations->AppendKeyframe(kSquishAnimReboundScale, 1.0, frame_time);
animations->AppendKeyframe(1.0, 1.0, frame_time);
win_->SetScaleCompositedAnimation(animations);
const Rect bounds = win_->client_bounds();
animations = win_->CreateMoveCompositedAnimation();
animations->AppendKeyframe(
bounds.x + 0.5 * (1.0 - kSquishAnimShrinkScale) * bounds.width, bounds.y,
frame_time);
animations->AppendKeyframe(
bounds.x + 0.5 * (1.0 - kSquishAnimReboundScale) * bounds.width, bounds.y,
frame_time);
animations->AppendKeyframe(bounds.x, bounds.y, frame_time);
win_->SetMoveCompositedAnimation(animations);
}
void BrowserWindow::SetBrightness(double brightness, int anim_ms) {
DCHECK_GE(brightness, 0.0);
DCHECK_LE(brightness, 1.0);
brightness_ = brightness;
dimming_box_->SetOpacity(1.0 - brightness, anim_ms);
}
double BrowserWindow::GetInstantaneousBrightness() const {
return 1.0 - dimming_box_->GetOpacity();
}
void BrowserWindow::SetStatusAreaDisplayed(bool displayed) {
if (status_area_displayed_ == displayed ||
win_->type() != chromeos::WM_IPC_WINDOW_CHROME_TOPLEVEL)
return;
status_area_displayed_ = displayed;
map<XAtom, bool> states;
states[wm()->GetXAtom(ATOM_CHROME_STATE_STATUS_HIDDEN)] = !displayed;
win_->ChangeChromeState(states);
}
void BrowserWindow::SetFullscreenProperty(bool fullscreen) {
if (win_->wm_state_fullscreen() == fullscreen)
return;
map<XAtom, bool> states;
states[wm()->GetXAtom(ATOM_NET_WM_STATE_FULLSCREEN)] = fullscreen;
win_->ChangeWmState(states);
}
void BrowserWindow::SetMaximizedProperty(bool maximized) {
if (win_->wm_state_maximized_horz() == maximized &&
win_->wm_state_maximized_vert() == maximized)
return;
map<XAtom, bool> states;
if (win_->wm_state_maximized_horz() != maximized)
states[wm()->GetXAtom(ATOM_NET_WM_STATE_MAXIMIZED_HORZ)] = maximized;
if (win_->wm_state_maximized_vert() != maximized)
states[wm()->GetXAtom(ATOM_NET_WM_STATE_MAXIMIZED_VERT)] = maximized;
win_->ChangeWmState(states);
}
} // namespace window_manager