1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
// Copyright (c) 2011 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"
#include <algorithm>
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "chrome_frame/function_stub.h"
namespace {
// length of each step when opening or closing
const UINT kInfobarSlidingTimerIntervalMs = 50U;
// pixels per step, when opening or closing
const int kInfobarSlideOpenStep = 2;
const int kInfobarSlideCloseStep = 6;
} // namespace
void OnSliderTimer(InfobarWindow::Host* host) {
if (host)
host->UpdateLayout();
}
InfobarWindow::InfobarWindow(InfobarType type)
: type_(type),
host_(NULL),
target_height_(0),
initial_height_(0),
current_height_(0),
current_width_(0),
timer_id_(0),
timer_stub_(NULL),
frame_impl_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
DCHECK(type_ >= FIRST_INFOBAR_TYPE);
DCHECK(type_ < END_OF_INFOBAR_TYPE);
}
InfobarWindow::~InfobarWindow() {
if (StopTimer() && timer_stub_ != NULL)
FunctionStub::Destroy(timer_stub_);
else if (timer_stub_ != NULL)
timer_stub_->set_argument(NULL); // Couldn't stop it, so orphan and disable
}
void InfobarWindow::SetHost(Host* host) {
DCHECK(host_ == NULL);
DCHECK(timer_stub_ == NULL);
DCHECK(host != NULL);
host_ = host;
timer_stub_ = FunctionStub::Create(reinterpret_cast<uintptr_t>(host),
OnSliderTimer);
}
bool InfobarWindow::Show(InfobarContent* content) {
DCHECK(host_ != NULL);
if (host_ == NULL)
return false;
scoped_ptr<InfobarContent> new_content(content);
content_.reset();
if (!new_content->InstallInFrame(&frame_impl_))
return false;
// Force a call to ReserveSpace, which will capture the width of the displaced
// window.
if (current_width_ == 0)
host_->UpdateLayout();
if (current_width_ == 0)
return false; // Might not be any displaced window.. then we can't display.
content_.swap(new_content);
StartSlidingTowards(content_->GetDesiredSize(current_width_, 0));
return true;
}
void InfobarWindow::Hide() {
DCHECK(host_ != NULL);
if (host_ == NULL)
return;
StartSlidingTowards(0);
}
void InfobarWindow::ReserveSpace(RECT* rect) {
DCHECK(rect);
DCHECK(host_ != NULL);
if (rect == NULL || host_ == NULL)
return;
current_width_ = rect->right - rect->left;
current_height_ = CalculateHeight();
RECT infobar_rect = *rect;
switch (type_) {
case TOP_INFOBAR:
infobar_rect.bottom = rect->top + current_height_;
rect->top = std::min(rect->bottom, infobar_rect.bottom);
break;
case BOTTOM_INFOBAR:
infobar_rect.top = rect->bottom - current_height_;
rect->bottom = std::max(rect->top, infobar_rect.top);
break;
default:
NOTREACHED() << "Unknown InfobarType value.";
break;
}
if (content_ != NULL)
content_->SetDimensions(infobar_rect);
// Done sliding?
if (current_height_ == target_height_) {
StopTimer();
if (current_height_ == 0)
content_.reset();
}
}
void InfobarWindow::StartSlidingTowards(int target_height) {
initial_height_ = current_height_;
target_height_ = target_height;
if (StartTimer())
slide_start_ = base::Time::Now();
else
slide_start_ = base::Time(); // NULL time means don't slide, resize now
// Trigger an immediate re-laying out. The timer will handle remaining steps.
host_->UpdateLayout();
}
bool InfobarWindow::StartTimer() {
return false; // TODO(erikwright): Diagnose and fix crashes on IE.
#if 0
if (timer_id_ != 0)
return true;
DCHECK(timer_stub_ != NULL);
if (timer_stub_ == NULL)
return false;
timer_id_ = ::SetTimer(NULL,
timer_id_,
kInfobarSlidingTimerIntervalMs,
reinterpret_cast<TIMERPROC>(timer_stub_->code()));
DPLOG_IF(ERROR, timer_id_ == 0) << "Failure in SetTimer.";
return timer_id_ != 0;
#endif
}
bool InfobarWindow::StopTimer() {
if (timer_id_ == 0)
return true;
if (::KillTimer(NULL, timer_id_)) {
timer_id_ = 0;
return true;
}
DPLOG(ERROR) << "Failure in KillTimer.";
return false;
}
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_;
}
}
InfobarWindow::FrameImpl::FrameImpl(InfobarWindow* infobar_window)
: infobar_window_(infobar_window) {
}
HWND InfobarWindow::FrameImpl::GetFrameWindow() {
return infobar_window_->host_->GetContainerWindow();
}
void InfobarWindow::FrameImpl::CloseInfobar() {
infobar_window_->Hide();
}
|