blob: 8a906077a0c208be7fe00c7818b60b71806197f2 [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/modality_handler.h"
#include "window_manager/event_consumer_registrar.h"
#include "window_manager/stacking_manager.h"
#include "window_manager/util.h"
#include "window_manager/window.h"
#include "window_manager/window_manager.h"
using std::set;
using window_manager::util::XidStr;
namespace window_manager {
// Opacity of the black rectangle that we use to dim everything in the
// background when a modal dialog is being displayed.
static const double kDimmingOpacity = 0.5;
// Duration in milliseconds over which we dim and undim the background when a
// modal dialog is mapped and unmapped.
static const int kDimmingFadeMs = 100;
ModalityHandler::ModalityHandler(WindowManager* wm)
: wm_(wm),
event_consumer_registrar_(new EventConsumerRegistrar(wm_, this)),
modal_window_is_focused_(false),
dimming_actor_(
wm_->compositor()->CreateColoredBox(
wm_->width(), wm_->height(), Compositor::Color(0, 0, 0))),
input_xid_(wm_->CreateInputWindow(Rect(-1, -1, 1, 1), 0)) {
wm_->focus_manager()->RegisterFocusChangeListener(this);
dimming_actor_->SetName("modal window dimming");
dimming_actor_->SetOpacity(0, 0);
dimming_actor_->Show();
wm_->SetNamePropertiesForXid(input_xid_, "modal input window");
wm_->stage()->AddActor(dimming_actor_.get());
}
ModalityHandler::~ModalityHandler() {
wm_->focus_manager()->UnregisterFocusChangeListener(this);
wm_->xconn()->DestroyWindow(input_xid_);
}
void ModalityHandler::HandleScreenResize() {
dimming_actor_->SetSize(wm_->width(), wm_->height());
if (modal_window_is_focused_)
wm_->ConfigureInputWindow(input_xid_, wm_->root_bounds());
}
void ModalityHandler::HandleWindowMap(Window* win) {
event_consumer_registrar_->RegisterForPropertyChanges(
win->xid(), wm_->GetXAtom(ATOM_NET_WM_STATE));
}
void ModalityHandler::HandleWindowUnmap(Window* win) {
event_consumer_registrar_->UnregisterForPropertyChanges(
win->xid(), wm_->GetXAtom(ATOM_NET_WM_STATE));
}
void ModalityHandler::HandleWindowPropertyChange(XWindow xid, XAtom xatom) {
Window* focused_win = wm_->focus_manager()->focused_win();
if (!focused_win || focused_win->xid() != xid)
return;
HandlePossibleModalityChange();
}
void ModalityHandler::HandleFocusChange() {
HandlePossibleModalityChange();
}
void ModalityHandler::RegisterModalityChangeListener(
ModalityChangeListener* listener) {
DCHECK(listener);
bool added = modality_change_listeners_.insert(listener).second;
DCHECK(added) << "Listener " << listener << " was already registered";
}
void ModalityHandler::UnregisterModalityChangeListener(
ModalityChangeListener* listener) {
int num_removed = modality_change_listeners_.erase(listener);
DCHECK_EQ(num_removed, 1) << "Listener " << listener << " wasn't registered";
}
void ModalityHandler::HandlePossibleModalityChange() {
Window* focused_win = wm_->focus_manager()->focused_win();
bool focused_win_is_modal = focused_win && focused_win->wm_state_modal();
bool changed = false;
if (focused_win_is_modal) {
wm_->stacking_manager()->StackActorRelativeToOtherActor(
dimming_actor_.get(),
focused_win->GetBottomActor(),
StackingManager::BELOW_SIBLING);
wm_->xconn()->StackWindow(input_xid_, focused_win->xid(), false);
if (!modal_window_is_focused_) {
modal_window_is_focused_ = true;
dimming_actor_->SetOpacity(kDimmingOpacity, kDimmingFadeMs);
wm_->ConfigureInputWindow(input_xid_, wm_->root_bounds());
changed = true;
}
} else {
if (modal_window_is_focused_) {
modal_window_is_focused_ = false;
dimming_actor_->SetOpacity(0, kDimmingFadeMs);
wm_->xconn()->ConfigureWindowOffscreen(input_xid_);
changed = true;
}
}
if (changed) {
for (set<ModalityChangeListener*>::const_iterator it =
modality_change_listeners_.begin();
it != modality_change_listeners_.end(); ++it) {
(*it)->HandleModalityChange();
}
}
}
} // namespace window_manager