Chromium Code Reviews| Index: chrome_frame/infobar_window.cc |
| =================================================================== |
| --- chrome_frame/infobar_window.cc (revision 0) |
| +++ chrome_frame/infobar_window.cc (revision 0) |
| @@ -0,0 +1,197 @@ |
| +// 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/infobar_window.h" |
| + |
| +#include "base/logging.h" |
| +#include "base/scoped_ptr.h" |
| + |
| +namespace { |
| + |
| +const UINT_PTR kInfobarSlidingTimerId = 1U; |
| +// In milliseconds. |
| +const UINT kInfobarSlidingTimerInterval = 50U; |
|
grt (UTC plus 2)
2010/11/10 17:59:29
Consider putting "ms" in the constant name so that
erikwright (departed)
2010/11/24 06:24:56
Agreed.
|
| +// The step when the infobar is sliding, in pixels. |
| +const int kInfobarSlidingStep = 1; |
| +// The default height of the infobar. |
| +const int kInfobarDefaultHeight = 39; |
| + |
| +} // namespace |
| + |
| +InfobarWindow::InfobarWindow(InfobarType type, InfobarHost* host) |
| + : type_(type), |
|
grt (UTC plus 2)
2010/11/10 17:59:29
Although I like spreading the initializer list out
erikwright (departed)
2010/11/24 06:24:56
It does prefer to avoid unnecessary whitespace, bu
|
| + host_(host), |
| + show_(false), |
| + target_height_(1), |
| + initial_height_(1), |
| + content_(NULL), |
| + frame_impl_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| + DCHECK(host_); |
| +} |
| + |
| +InfobarWindow::~InfobarWindow() { |
| + Reset(); |
| + |
| + if (IsWindow()) { |
| + DestroyWindow(); |
| + } |
| +} |
| + |
| +HRESULT InfobarWindow::Show(InfobarContent *content, |
| + int max_height) { |
| + if (content_) { |
| + content_->Reset(); |
| + content_ = NULL; |
| + } |
| + |
| + // Create the window if not created. |
| + if (!IsWindow()) { |
| + Create(host_->GetContainerWindow()); |
| + RECT dimensions = {0, 0, 0, 0}; |
| + GetClientRect(&dimensions); |
| + dimensions.bottom = 1; |
| + MoveWindow(&dimensions, TRUE); |
| + } |
| + if (!IsWindow()) |
| + return E_UNEXPECTED; |
| + |
| + HRESULT hr = content->InstallInFrame(&frame_impl_); |
| + if (FAILED(hr)) { |
| + return hr; |
| + } |
| + |
| + StartUpdatingLayout(true, max_height, true); |
| + |
| + // We only keep the pointer in case of success. At this point, we promise to |
| + // call Reset at some future point on the content. |
| + content_ = content; |
| + return S_OK; |
| +} |
| + |
| +HRESULT InfobarWindow::Hide() { |
| + StartUpdatingLayout(false, 0, false); |
| + |
| + return S_OK; |
| +} |
| + |
| +void InfobarWindow::ReserveSpace(RECT* rect) { |
| + DCHECK(rect); |
| + if (rect == NULL || !show_ || !IsWindow()) |
| + return; |
| + |
| + RECT infobar_rect = *rect; |
| + |
| + int height = CalculateHeight(); |
| + |
| + switch (type_) { |
| + case TOP_INFOBAR: |
| + infobar_rect.bottom = rect->top = std::min(rect->bottom, |
| + rect->top + height); |
| + break; |
| + case BOTTOM_INFOBAR: |
| + infobar_rect.top = rect->bottom = std::max(rect->top, |
| + rect->bottom - height); |
| + break; |
| + default: |
| + NOTREACHED() << "Unknown InfobarType value."; |
| + break; |
| + } |
| + |
| + |
| + MoveWindow(&infobar_rect, TRUE); |
| + |
| + SetWindowPos(HWND_TOP, |
| + &infobar_rect, |
| + show_ || height != target_height_ ? |
| + SWP_SHOWWINDOW : SWP_HIDEWINDOW); |
| + |
| + if (content_ != NULL) { |
| + content_->SetDimensions(infobar_rect); |
| + } |
| + |
| + if (height == target_height_) { |
| + KillTimer(kInfobarSlidingTimerId); |
| + if (!show_ && content_) { |
| + // Content is responsible for freeing itself. |
| + content_->Reset(); |
| + content_ = NULL; |
| + } |
| + } |
| +} |
| + |
| +void InfobarWindow::StartUpdatingLayout(bool show, int max_height, bool slide) { |
| + if (!IsWindow()) { |
| + return; |
| + } |
| + |
| + show_ = show; |
| + if (show) { |
| + // TODO(erikwright): ask our widget for its height |
| + target_height_ = (max_height == 0 || kInfobarDefaultHeight < max_height) ? |
| + kInfobarDefaultHeight : max_height; |
| + if (target_height_ <= 0) { |
| + target_height_ = 1; |
| + } |
| + } else { |
| + target_height_ = 1; |
| + } |
| + |
| + // Trigger an deferred call to ReserveSpace, in which we will do the actual |
| + // MoveWindow |
| + if (!host_->UpdateLayout()) { |
| + // Failed to trigger a layout - seems our environment is going away or gone. |
| + // Let's get out of here. |
| + RECT empty = {0, 0, 0, 0}; |
| + MoveWindow(&empty, TRUE); |
| + KillTimer(kInfobarSlidingTimerId); |
| + if (content_) { |
| + // Content is responsible for freeing itself. |
| + content_->Reset(); |
| + content_ = NULL; |
| + } |
| + return; |
| + } |
| + |
| + if (!slide || !show) { |
| + slide_start_ = base::Time(); |
| + KillTimer(kInfobarSlidingTimerId); |
| + } else { |
| + RECT dimensions = {0, 0, 0, 0}; |
| + GetClientRect(&dimensions); |
| + slide_start_ = base::Time::Now(); |
| + initial_height_ = dimensions.bottom; |
| + SetTimer(kInfobarSlidingTimerId, kInfobarSlidingTimerInterval, NULL); |
| + } |
| + |
| +} |
| + |
| +int InfobarWindow::CalculateHeight() { |
| + RECT dimensions; |
| + int current_height = GetClientRect(&dimensions) ? dimensions.bottom : 0; |
| + |
| + if (slide_start_.is_null()) { |
| + return target_height_; |
| + } |
| + |
| + base::TimeDelta elapsed = base::Time::Now() - slide_start_; |
| + int travel = (static_cast<int>(elapsed.InMilliseconds()) / |
| + kInfobarSlidingTimerInterval) * kInfobarSlidingStep; |
| + |
| + if (current_height < target_height_) { |
| + return std::min(current_height + travel, target_height_); |
| + } else if (current_height > target_height_) { |
| + return std::max(current_height - travel, target_height_); |
| + } else { |
| + return current_height; |
| + } |
| +} |
| + |
| +LRESULT InfobarWindow::OnTimer(UINT_PTR nIDEvent) { |
| + DCHECK(nIDEvent == kInfobarSlidingTimerId); |
| + |
| + host_->UpdateLayout(); |
| + return S_OK; |
| +} |