1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Implementation of the manager for infobar windows.
7 #include "chrome_frame/infobars/internal/infobar_window.h"
11 #include "base/compiler_specific.h"
12 #include "base/logging.h"
13 #include "chrome_frame/function_stub.h"
17 // length of each step when opening or closing
18 const UINT kInfobarSlidingTimerIntervalMs = 50U;
19 // pixels per step, when opening or closing
20 const int kInfobarSlideOpenStep = 2;
21 const int kInfobarSlideCloseStep = 6;
25 VOID CALLBACK OnSliderTimer(InfobarWindow::Host* host,
26 HWND /*hwnd*/, UINT /*uMsg*/,
27 UINT_PTR /*idEvent*/, DWORD /*dwTime*/) {
32 InfobarWindow::InfobarWindow(InfobarType type)
42 DCHECK(type_ >= FIRST_INFOBAR_TYPE);
43 DCHECK(type_ < END_OF_INFOBAR_TYPE);
46 InfobarWindow::~InfobarWindow() {
47 if (StopTimer() && timer_stub_ != NULL)
48 FunctionStub::Destroy(timer_stub_);
49 else if (timer_stub_ != NULL)
50 timer_stub_->set_argument(NULL); // Couldn't stop it, so orphan and disable
53 void InfobarWindow::SetHost(Host* host) {
54 DCHECK(host_ == NULL);
55 DCHECK(timer_stub_ == NULL);
58 timer_stub_ = FunctionStub::Create(reinterpret_cast<uintptr_t>(host),
62 bool InfobarWindow::Show(InfobarContent* content) {
63 DCHECK(host_ != NULL);
67 scoped_ptr<InfobarContent> new_content(content);
70 if (!new_content->InstallInFrame(&frame_impl_))
73 // Force a call to ReserveSpace, which will capture the width of the displaced
75 if (current_width_ == 0)
76 host_->UpdateLayout();
77 if (current_width_ == 0)
78 return false; // Might not be any displaced window.. then we can't display.
80 content_.swap(new_content);
81 StartSlidingTowards(content_->GetDesiredSize(current_width_, 0));
86 void InfobarWindow::Hide() {
87 DCHECK(host_ != NULL);
91 StartSlidingTowards(0);
94 void InfobarWindow::ReserveSpace(RECT* rect) {
96 DCHECK(host_ != NULL);
97 if (rect == NULL || host_ == NULL)
100 current_width_ = rect->right - rect->left;
101 current_height_ = CalculateHeight();
103 RECT infobar_rect = *rect;
107 infobar_rect.bottom = rect->top + current_height_;
108 rect->top = std::min(rect->bottom, infobar_rect.bottom);
111 infobar_rect.top = rect->bottom - current_height_;
112 rect->bottom = std::max(rect->top, infobar_rect.top);
115 NOTREACHED() << "Unknown InfobarType value.";
119 if (content_ != NULL)
120 content_->SetDimensions(infobar_rect);
123 if (current_height_ == target_height_) {
125 if (current_height_ == 0)
130 void InfobarWindow::StartSlidingTowards(int target_height) {
131 initial_height_ = current_height_;
132 target_height_ = target_height;
135 slide_start_ = base::Time::Now();
137 slide_start_ = base::Time(); // NULL time means don't slide, resize now
139 // Trigger an immediate re-laying out. The timer will handle remaining steps.
140 host_->UpdateLayout();
143 bool InfobarWindow::StartTimer() {
147 DCHECK(timer_stub_ != NULL);
148 if (timer_stub_ == NULL)
151 timer_id_ = ::SetTimer(NULL,
153 kInfobarSlidingTimerIntervalMs,
154 reinterpret_cast<TIMERPROC>(timer_stub_->code()));
156 DPLOG_IF(ERROR, timer_id_ == 0) << "Failure in SetTimer.";
158 return timer_id_ != 0;
161 bool InfobarWindow::StopTimer() {
165 if (::KillTimer(NULL, timer_id_)) {
170 DPLOG(ERROR) << "Failure in KillTimer.";
174 int InfobarWindow::CalculateHeight() {
175 if (slide_start_.is_null())
176 return target_height_;
178 base::TimeDelta elapsed = base::Time::Now() - slide_start_;
179 int elapsed_steps = static_cast<int>(elapsed.InMilliseconds()) /
180 kInfobarSlidingTimerIntervalMs;
182 if (initial_height_ < target_height_) {
183 return std::min(initial_height_ + elapsed_steps * kInfobarSlideOpenStep,
185 } else if (initial_height_ > target_height_) {
186 return std::max(initial_height_ - elapsed_steps * kInfobarSlideCloseStep,
189 return target_height_;
193 InfobarWindow::FrameImpl::FrameImpl(InfobarWindow* infobar_window)
194 : infobar_window_(infobar_window) {
197 HWND InfobarWindow::FrameImpl::GetFrameWindow() {
198 return infobar_window_->host_->GetContainerWindow();
201 void InfobarWindow::FrameImpl::CloseInfobar() {
202 infobar_window_->Hide();