Chromium Code Reviews| Index: chrome_frame/infobars/internal/infobar_window.cc |
| =================================================================== |
| --- chrome_frame/infobars/internal/infobar_window.cc (revision 0) |
| +++ chrome_frame/infobars/internal/infobar_window.cc (revision 0) |
| @@ -0,0 +1,224 @@ |
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| +// |
| +// Implementation of the manager for infobar windows. |
| + |
| +#include "chrome_frame/infobars/internal/infobar_window.h" |
| + |
|
grt (UTC plus 2)
2010/11/25 18:00:13
Include <algorithm> to explicitly pull in std::min
erikwright (departed)
2010/12/01 20:05:52
Awesome catch!
|
| +#include "base/compiler_specific.h" |
| +#include "base/logging.h" |
| + |
| +#include "chrome_frame/infobars/content.h" |
| + |
| +namespace { |
| +const UINT_PTR kInfobarSlidingTimerId = 1U; |
| +const UINT kInfobarSlidingTimerIntervalMs = 50U; |
| +// The step when the infobar is sliding, in pixels. |
| +const int kInfobarSlideOpenStep = 2; |
| +const int kInfobarSlideCloseStep = 6; |
| +} // namespace |
| + |
| +InfobarWindow::InfobarWindow(InfobarType type, InfobarHost* host) |
| + : type_(type), |
| + host_(host), |
| + target_height_(0), |
| + initial_height_(0), |
| + content_(NULL), |
| + frame_impl_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| + DCHECK(type_ >= FIRST_INFOBAR_TYPE); |
| + DCHECK(type_ < END_OF_INFOBAR_TYPE); |
| + DCHECK(host_); |
| +} |
| + |
| +InfobarWindow::~InfobarWindow() { |
| + ResetContent(); |
| +} |
| + |
| +bool InfobarWindow::InitializeWindow() { |
| + RECT dimensions = {0, 0, 0, 0}; |
| + if (!Create(host_->GetContainerWindow())) { |
| + DPLOG(ERROR) << "Failure to create InfobarWindow."; |
| + return false; |
| + } |
| + |
| + if (!::GetClientRect(host_->GetContainerWindow(), &dimensions)) { |
| + DPLOG(ERROR) << "Failure in GetClientRect."; |
| + DestroyWindow(); |
| + return false; |
| + } |
| + |
| + if (type_ == TOP_INFOBAR) { |
| + dimensions.bottom = dimensions.top; |
| + } else { |
| + DCHECK(type_ == BOTTOM_INFOBAR); |
| + dimensions.top = dimensions.bottom; |
| + } |
| + |
| + if (!MoveWindow(&dimensions, FALSE)) { |
| + DPLOG(ERROR) << "Failure in MoveWindow."; |
| + DestroyWindow(); |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool InfobarWindow::Show(InfobarContent *content) { |
| + ResetContent(); |
| + |
| + // Create the window if not created. |
| + if (!IsWindow() && !InitializeWindow()) { |
| + content->Reset(); |
| + return false; |
| + } |
| + |
| + if (!InstallContent(content)) |
| + return false; |
| + |
| + return true; |
| +} |
| + |
| +void InfobarWindow::Hide() { |
| + if (!IsWindow()) { |
| + ResetContent(); |
| + } else if (!StartSlidingTowards(0)) { |
| + // Failed to trigger a layout - seems our environment is going away or gone. |
| + // Just hide immediately. |
| + RECT empty = {0, 0, 0, 0}; |
| + MoveWindow(&empty, TRUE); |
| + KillTimer(kInfobarSlidingTimerId); |
| + ResetContent(); |
| + } |
| +} |
| + |
| +void InfobarWindow::ReserveSpace(RECT* rect) { |
| + DCHECK(rect); |
| + if (rect == NULL || !IsWindow()) |
| + return; |
| + |
| + int current_height = CalculateHeight(); |
| + |
| + RECT infobar_rect = *rect; |
| + |
| + switch (type_) { |
| + case TOP_INFOBAR: |
| + rect->top = std::min(rect->bottom, |
| + infobar_rect.bottom = rect->top + current_height); |
| + break; |
| + case BOTTOM_INFOBAR: |
| + rect->bottom = std::max(rect->top, |
| + infobar_rect.top = rect->bottom - current_height); |
| + break; |
| + default: |
| + NOTREACHED() << "Unknown InfobarType value."; |
| + break; |
| + } |
| + |
| + if (!MoveWindow(&infobar_rect, TRUE)) |
| + DPLOG(ERROR) << "Failure in MoveWindow."; |
| + |
| + if (!SetWindowPos(HWND_TOP, |
| + &infobar_rect, |
| + current_height != 0 ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)) { |
| + DPLOG(ERROR) << "Failure in SetWindowPos."; |
| + } |
| + |
| + if (content_ != NULL) |
| + content_->SetDimensions(infobar_rect); |
| + |
| + // Done sliding? |
| + if (current_height == target_height_) { |
| + KillTimer(kInfobarSlidingTimerId); |
| + if (current_height == 0) |
| + ResetContent(); |
| + } |
| +} |
| + |
| +bool InfobarWindow::StartSlidingTowards(int target_height) { |
| + if (!IsWindow()) |
| + return false; |
| + |
| + RECT dimensions = {0, 0, 0, 0}; |
| + if (!GetClientRect(&dimensions)) { |
| + DPLOG(ERROR) << "Failure in GetClientRect."; |
| + return false; |
| + } |
| + |
| + if (!SetTimer(kInfobarSlidingTimerId, kInfobarSlidingTimerIntervalMs, NULL)) { |
| + DPLOG(ERROR) << "Failure in SetTimer."; |
| + return false; |
| + } |
| + |
| + slide_start_ = base::Time::Now(); |
| + initial_height_ = dimensions.bottom - dimensions.top; |
| + target_height_ = target_height; |
| + |
| + // Trigger an immediate re-laying out. The timer will handle remaining steps. |
| + host_->UpdateLayout(); |
| + return true; |
| +} |
| + |
| +int InfobarWindow::CalculateHeight() { |
| + if (slide_start_.is_null()) |
| + return target_height_; |
| + |
| + base::TimeDelta elapsed = base::Time::Now() - slide_start_; |
| + int elapsed_steps = static_cast<int>(elapsed.InMilliseconds()) / |
| + kInfobarSlidingTimerIntervalMs; |
| + |
| + if (initial_height_ < target_height_) { |
| + return std::min(initial_height_ + elapsed_steps * kInfobarSlideOpenStep, |
| + target_height_); |
| + } else if (initial_height_ > target_height_) { |
| + return std::max(initial_height_ - elapsed_steps * kInfobarSlideCloseStep, |
| + target_height_); |
| + } else { |
| + return target_height_; |
| + } |
| +} |
| + |
| +bool InfobarWindow::InstallContent(InfobarContent* content) { |
| + // Clear existing content, if any |
| + ResetContent(); |
| + |
| + content_ = content; |
| + |
| + if (!content_->InstallInFrame(&frame_impl_)) { |
| + ResetContent(); |
|
grt (UTC plus 2)
2010/11/25 18:00:13
Multiple exits that require the same DoStuffBefore
erikwright (departed)
2010/12/01 20:05:52
Yeah, I didn't like it either.
Moved to Show(), B
|
| + return false; |
| + } |
| + |
| + RECT dimensions = {0, 0, 0, 0}; |
| + if (!GetClientRect(&dimensions)) { |
| + DPLOG(INFO) << "Failure in GetClientRect."; |
| + ResetContent(); |
| + return false; |
| + } |
| + |
| + int infobar_width = dimensions.right - dimensions.left; |
| + int content_height = content_->GetDesiredSize(infobar_width, 0); |
| + |
| + if (!StartSlidingTowards(content_height)) { |
| + ResetContent(); |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +void InfobarWindow::ResetContent() { |
| + if (content_ != NULL) { |
| + content_->Reset(); |
| + content_ = NULL; |
| + } |
| +} |
| + |
| +LRESULT InfobarWindow::OnTimer(UINT_PTR nIDEvent) { |
| + DCHECK(nIDEvent == kInfobarSlidingTimerId); |
| + |
| + // Might fail if the host is not able to update right now. Expect it to |
| + // eventually succeed (on a future OnTimer invocation). |
| + host_->UpdateLayout(); |
| + return S_OK; |
| +} |
| Property changes on: chrome_frame\infobars\internal\infobar_window.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |