OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/panels/panel_manager.h" | 5 #include "chrome/browser/ui/panels/panel_manager.h" |
6 | 6 |
7 #include <algorithm> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/logging.h" | 7 #include "base/logging.h" |
11 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
12 #include "base/message_loop.h" | |
13 #include "chrome/browser/ui/browser.h" | 9 #include "chrome/browser/ui/browser.h" |
14 #include "chrome/browser/ui/browser_list.h" | 10 #include "chrome/browser/ui/browser_list.h" |
15 #include "chrome/browser/ui/panels/panel_mouse_watcher.h" | 11 #include "chrome/browser/ui/panels/panel_mouse_watcher.h" |
12 #include "chrome/browser/ui/panels/panel_strip.h" | |
16 #include "chrome/browser/ui/window_sizer.h" | 13 #include "chrome/browser/ui/window_sizer.h" |
17 #include "chrome/common/chrome_notification_types.h" | 14 #include "chrome/common/chrome_notification_types.h" |
18 #include "content/public/browser/notification_service.h" | 15 #include "content/public/browser/notification_service.h" |
19 #include "content/public/browser/notification_source.h" | 16 #include "content/public/browser/notification_source.h" |
20 | 17 |
21 namespace { | 18 namespace { |
22 // Invalid panel index. | 19 const int kOverflowStripThickness = 24; |
23 const size_t kInvalidPanelIndex = static_cast<size_t>(-1); | |
24 | 20 |
25 // Width of spacing between first panel and the right edge of the screen. | 21 // Width of spacing around panel strip and the left/right edges of the screen. |
26 // Leaving a larger gap at the edge of the screen allows access to UI | 22 const int kPanelStripLeftMargin = kOverflowStripThickness + 6; |
27 // elements located on the bottom right of windows. | 23 const int kPanelStripRightMargin = 24; |
28 const int kRightScreenEdgeSpacingWidth = 24; | |
29 | 24 |
30 // Width to height ratio is used to compute the default width or height | 25 // Height of panel strip is based on the factor of the working area. |
31 // when only one value is provided. | 26 const double kPanelStripHeightFactor = 0.5; |
32 const double kPanelDefaultWidthToHeightRatio = 1.62; // golden ratio | |
33 | 27 |
34 // Maxmium width and height of a panel based on the factor of the working | |
35 // area. | |
36 const double kPanelMaxWidthFactor = 0.35; | |
37 const double kPanelMaxHeightFactor = 0.5; | |
38 | |
39 // Occasionally some system, like Windows, might not bring up or down the bottom | |
40 // bar when the mouse enters or leaves the bottom screen area. This is the | |
41 // maximum time we will wait for the bottom bar visibility change notification. | |
42 // After the time expires, we bring up/down the titlebars as planned. | |
43 const int kMaxMillisecondsWaitForBottomBarVisibilityChange = 1000; | |
44 | |
45 // See usage below. | |
46 #if defined(TOOLKIT_GTK) | |
47 const int kMillisecondsBeforeCollapsingFromTitleOnlyState = 2000; | |
48 #else | |
49 const int kMillisecondsBeforeCollapsingFromTitleOnlyState = 0; | |
50 #endif | |
51 } // namespace | 28 } // namespace |
52 | 29 |
53 // static | 30 // static |
54 const int PanelManager::kPanelMinWidth = 100; | |
55 const int PanelManager::kPanelMinHeight = 20; | |
56 | |
57 // static | |
58 PanelManager* PanelManager::GetInstance() { | 31 PanelManager* PanelManager::GetInstance() { |
59 static base::LazyInstance<PanelManager> instance = LAZY_INSTANCE_INITIALIZER; | 32 static base::LazyInstance<PanelManager> instance = LAZY_INSTANCE_INITIALIZER; |
60 return instance.Pointer(); | 33 return instance.Pointer(); |
61 } | 34 } |
62 | 35 |
63 PanelManager::PanelManager() | 36 PanelManager::PanelManager() |
64 : minimized_panel_count_(0), | 37 : ALLOW_THIS_IN_INITIALIZER_LIST(panel_strip_(new PanelStrip(this))), |
65 are_titlebars_up_(false), | 38 panel_mouse_watcher_(PanelMouseWatcher::Create()), |
66 dragging_panel_index_(kInvalidPanelIndex), | 39 ALLOW_THIS_IN_INITIALIZER_LIST( |
67 dragging_panel_original_x_(0), | 40 auto_hiding_desktop_bar_(AutoHidingDesktopBar::Create(this))), |
Dmitry Titov
2011/11/30 20:38:45
why not just initialize those in the body of ctor,
| |
68 delayed_titlebar_action_(NO_ACTION), | 41 auto_sizing_enabled_(true) { |
69 remove_delays_for_testing_(false), | |
70 titlebar_action_factory_(this), | |
71 auto_sizing_enabled_(true), | |
72 mouse_watching_disabled_(false) { | |
73 panel_mouse_watcher_.reset(PanelMouseWatcher::Create()); | |
74 auto_hiding_desktop_bar_ = AutoHidingDesktopBar::Create(this); | |
75 OnDisplayChanged(); | 42 OnDisplayChanged(); |
76 } | 43 } |
77 | 44 |
78 PanelManager::~PanelManager() { | 45 PanelManager::~PanelManager() { |
79 DCHECK(panels_.empty()); | |
80 DCHECK(panels_pending_to_remove_.empty()); | |
81 DCHECK_EQ(0, minimized_panel_count_); | |
82 } | 46 } |
83 | 47 |
84 void PanelManager::OnDisplayChanged() { | 48 void PanelManager::OnDisplayChanged() { |
85 scoped_ptr<WindowSizer::MonitorInfoProvider> info_provider( | 49 scoped_ptr<WindowSizer::MonitorInfoProvider> info_provider( |
86 WindowSizer::CreateDefaultMonitorInfoProvider()); | 50 WindowSizer::CreateDefaultMonitorInfoProvider()); |
87 #if defined(OS_MACOSX) | 51 #if defined(OS_MACOSX) |
88 // On OSX, panels should be dropped all the way to the bottom edge of the | 52 // On OSX, panels should be dropped all the way to the bottom edge of the |
89 // screen (and overlap Dock). | 53 // screen (and overlap Dock). |
90 gfx::Rect work_area = info_provider->GetPrimaryMonitorBounds(); | 54 gfx::Rect work_area = info_provider->GetPrimaryMonitorBounds(); |
91 #else | 55 #else |
92 gfx::Rect work_area = info_provider->GetPrimaryMonitorWorkArea(); | 56 gfx::Rect work_area = info_provider->GetPrimaryMonitorWorkArea(); |
93 #endif | 57 #endif |
94 SetWorkArea(work_area); | 58 SetWorkArea(work_area); |
95 } | 59 } |
96 | 60 |
97 void PanelManager::SetWorkArea(const gfx::Rect& work_area) { | 61 void PanelManager::SetWorkArea(const gfx::Rect& work_area) { |
98 if (work_area == work_area_) | 62 if (work_area == work_area_) |
99 return; | 63 return; |
100 work_area_ = work_area; | 64 work_area_ = work_area; |
101 | 65 |
102 auto_hiding_desktop_bar_->UpdateWorkArea(work_area_); | 66 auto_hiding_desktop_bar_->UpdateWorkArea(work_area_); |
103 AdjustWorkAreaForAutoHidingDesktopBars(); | 67 AdjustWorkAreaForAutoHidingDesktopBars(); |
68 Layout(); | |
69 } | |
104 | 70 |
105 Rearrange(panels_.begin(), StartingRightPosition()); | 71 void PanelManager::Layout() { |
72 int height = | |
73 static_cast<int>(adjusted_work_area_.height() * kPanelStripHeightFactor); | |
74 gfx::Rect panel_strip_bounds; | |
75 panel_strip_bounds.set_x(adjusted_work_area_.x() + kPanelStripLeftMargin); | |
76 panel_strip_bounds.set_y(adjusted_work_area_.bottom() - height); | |
77 panel_strip_bounds.set_width(adjusted_work_area_.width() - | |
78 kPanelStripLeftMargin - kPanelStripRightMargin); | |
79 panel_strip_bounds.set_height(height); | |
80 panel_strip_->SetBounds(panel_strip_bounds); | |
106 } | 81 } |
107 | 82 |
108 Panel* PanelManager::CreatePanel(Browser* browser) { | 83 Panel* PanelManager::CreatePanel(Browser* browser) { |
109 int width = browser->override_bounds().width(); | 84 int width = browser->override_bounds().width(); |
110 int height = browser->override_bounds().height(); | 85 int height = browser->override_bounds().height(); |
111 | |
112 Panel* panel = new Panel(browser, gfx::Size(width, height)); | 86 Panel* panel = new Panel(browser, gfx::Size(width, height)); |
113 | 87 panel_strip_->AddPanel(panel); |
114 int max_panel_width = GetMaxPanelWidth(); | |
115 int max_panel_height = GetMaxPanelHeight(); | |
116 panel->SetSizeRange(gfx::Size(kPanelMinWidth, kPanelMinHeight), | |
117 gfx::Size(max_panel_width, max_panel_height)); | |
118 | |
119 // Auto resizable is enabled only if no initial size is provided. | |
120 bool auto_resize = (width == 0 && height == 0); | |
121 panel->SetAutoResizable(auto_resize); | |
122 | |
123 // Adjust the width and height to fit into our constraint. | |
124 if (!auto_resize) { | |
125 if (height == 0) | |
126 height = width / kPanelDefaultWidthToHeightRatio; | |
127 if (width == 0) | |
128 width = height * kPanelDefaultWidthToHeightRatio; | |
129 } | |
130 | |
131 if (width < kPanelMinWidth) | |
132 width = kPanelMinWidth; | |
133 else if (width > max_panel_width) | |
134 width = max_panel_width; | |
135 | |
136 if (height < kPanelMinHeight) | |
137 height = kPanelMinHeight; | |
138 else if (height > max_panel_height) | |
139 height = max_panel_height; | |
140 | |
141 panel->set_restored_size(gfx::Size(width, height)); | |
142 | |
143 // Layout the new panel. | |
144 int y = adjusted_work_area_.bottom() - height; | |
145 int x = GetRightMostAvailablePosition() - width; | |
146 panel->Initialize(gfx::Rect(x, y, width, height)); | |
147 | |
148 panels_.push_back(panel); | |
149 | 88 |
150 content::NotificationService::current()->Notify( | 89 content::NotificationService::current()->Notify( |
151 chrome::NOTIFICATION_PANEL_ADDED, | 90 chrome::NOTIFICATION_PANEL_ADDED, |
152 content::Source<Panel>(panel), | 91 content::Source<Panel>(panel), |
153 content::NotificationService::NoDetails()); | 92 content::NotificationService::NoDetails()); |
154 | 93 |
155 return panel; | 94 return panel; |
156 } | 95 } |
157 | 96 |
158 int PanelManager::GetMaxPanelWidth() const { | |
159 return static_cast<int>(adjusted_work_area_.width() * kPanelMaxWidthFactor); | |
160 } | |
161 | |
162 int PanelManager::GetMaxPanelHeight() const { | |
163 return static_cast<int>(adjusted_work_area_.height() * kPanelMaxHeightFactor); | |
164 } | |
165 | |
166 int PanelManager::StartingRightPosition() const { | 97 int PanelManager::StartingRightPosition() const { |
167 return adjusted_work_area_.right() - kRightScreenEdgeSpacingWidth; | 98 return panel_strip_->StartingRightPosition(); |
168 } | |
169 | |
170 int PanelManager::GetRightMostAvailablePosition() const { | |
171 return panels_.empty() ? StartingRightPosition() : | |
172 (panels_.back()->GetBounds().x() - kPanelsHorizontalSpacing); | |
173 } | 99 } |
174 | 100 |
175 void PanelManager::Remove(Panel* panel) { | 101 void PanelManager::Remove(Panel* panel) { |
176 // If we're in the process of dragging, delay the removal. | 102 if (panel_strip_->Remove(panel)) |
177 if (dragging_panel_index_ != kInvalidPanelIndex) { | |
178 panels_pending_to_remove_.push_back(panel); | |
179 return; | 103 return; |
180 } | 104 // TODO(jianli): else try removing from overflow strip |
181 | |
182 DoRemove(panel); | |
183 } | 105 } |
184 | 106 |
185 void PanelManager::DelayedRemove() { | 107 void PanelManager::OnPanelRemoved(Panel* panel) { |
186 for (size_t i = 0; i < panels_pending_to_remove_.size(); ++i) | |
187 DoRemove(panels_pending_to_remove_[i]); | |
188 panels_pending_to_remove_.clear(); | |
189 } | |
190 | |
191 void PanelManager::DoRemove(Panel* panel) { | |
192 Panels::iterator iter = find(panels_.begin(), panels_.end(), panel); | |
193 if (iter == panels_.end()) | |
194 return; | |
195 | |
196 if (panel->expansion_state() != Panel::EXPANDED) | |
197 DecrementMinimizedPanels(); | |
198 | |
199 gfx::Rect bounds = (*iter)->GetBounds(); | |
200 Rearrange(panels_.erase(iter), bounds.right()); | |
201 | |
202 content::NotificationService::current()->Notify( | 108 content::NotificationService::current()->Notify( |
203 chrome::NOTIFICATION_PANEL_REMOVED, | 109 chrome::NOTIFICATION_PANEL_REMOVED, |
204 content::Source<Panel>(panel), | 110 content::Source<Panel>(panel), |
205 content::NotificationService::NoDetails()); | 111 content::NotificationService::NoDetails()); |
206 } | 112 } |
207 | 113 |
208 void PanelManager::StartDragging(Panel* panel) { | 114 void PanelManager::StartDragging(Panel* panel) { |
209 for (size_t i = 0; i < panels_.size(); ++i) { | 115 panel_strip_->StartDragging(panel); |
210 if (panels_[i] == panel) { | |
211 dragging_panel_index_ = i; | |
212 dragging_panel_bounds_ = panel->GetBounds(); | |
213 dragging_panel_original_x_ = dragging_panel_bounds_.x(); | |
214 break; | |
215 } | |
216 } | |
217 } | 116 } |
218 | 117 |
219 void PanelManager::Drag(int delta_x) { | 118 void PanelManager::Drag(int delta_x) { |
220 DCHECK(dragging_panel_index_ != kInvalidPanelIndex); | 119 panel_strip_->Drag(delta_x); |
221 | |
222 if (!delta_x) | |
223 return; | |
224 | |
225 // Moves this panel to the dragging position. | |
226 Panel* dragging_panel = panels_[dragging_panel_index_]; | |
227 gfx::Rect new_bounds(dragging_panel->GetBounds()); | |
228 new_bounds.set_x(new_bounds.x() + delta_x); | |
229 dragging_panel->SetPanelBounds(new_bounds); | |
230 | |
231 // Checks and processes other affected panels. | |
232 if (delta_x > 0) | |
233 DragRight(); | |
234 else | |
235 DragLeft(); | |
236 } | |
237 | |
238 void PanelManager::DragLeft() { | |
239 Panel* dragging_panel = panels_[dragging_panel_index_]; | |
240 | |
241 // This is the left corner of the dragging panel. We use it to check against | |
242 // all the panels on its left. | |
243 int dragging_panel_left_boundary = dragging_panel->GetBounds().x(); | |
244 | |
245 // This is the right corner which a panel will be moved to. | |
246 int current_panel_right_boundary = | |
247 dragging_panel_bounds_.x() + dragging_panel_bounds_.width(); | |
248 | |
249 // Checks the panels to the left of the dragging panel. | |
250 size_t current_panel_index = dragging_panel_index_ + 1; | |
251 for (; current_panel_index < panels_.size(); ++current_panel_index) { | |
252 Panel* current_panel = panels_[current_panel_index]; | |
253 | |
254 // Current panel will only be affected if the left corner of dragging | |
255 // panel goes beyond the middle position of the current panel. | |
256 if (dragging_panel_left_boundary > current_panel->GetBounds().x() + | |
257 current_panel->GetBounds().width() / 2) | |
258 break; | |
259 | |
260 // Moves current panel to the new position. | |
261 gfx::Rect bounds(current_panel->GetBounds()); | |
262 bounds.set_x(current_panel_right_boundary - bounds.width()); | |
263 current_panel_right_boundary -= bounds.width() + kPanelsHorizontalSpacing; | |
264 current_panel->SetPanelBounds(bounds); | |
265 | |
266 // Updates the index of current panel since it has been moved to the | |
267 // position of previous panel. | |
268 panels_[current_panel_index - 1] = current_panel; | |
269 } | |
270 | |
271 // Updates the position and index of dragging panel as the result of moving | |
272 // other affected panels. | |
273 if (current_panel_index != dragging_panel_index_ + 1) { | |
274 dragging_panel_bounds_.set_x(current_panel_right_boundary - | |
275 dragging_panel_bounds_.width()); | |
276 dragging_panel_index_ = current_panel_index - 1; | |
277 panels_[dragging_panel_index_] = dragging_panel; | |
278 } | |
279 } | |
280 | |
281 void PanelManager::DragRight() { | |
282 Panel* dragging_panel = panels_[dragging_panel_index_]; | |
283 | |
284 // This is the right corner of the dragging panel. We use it to check against | |
285 // all the panels on its right. | |
286 int dragging_panel_right_boundary = dragging_panel->GetBounds().x() + | |
287 dragging_panel->GetBounds().width() - 1; | |
288 | |
289 // This is the left corner which a panel will be moved to. | |
290 int current_panel_left_boundary = dragging_panel_bounds_.x(); | |
291 | |
292 // Checks the panels to the right of the dragging panel. | |
293 int current_panel_index = static_cast<int>(dragging_panel_index_) - 1; | |
294 for (; current_panel_index >= 0; --current_panel_index) { | |
295 Panel* current_panel = panels_[current_panel_index]; | |
296 | |
297 // Current panel will only be affected if the right corner of dragging | |
298 // panel goes beyond the middle position of the current panel. | |
299 if (dragging_panel_right_boundary < current_panel->GetBounds().x() + | |
300 current_panel->GetBounds().width() / 2) | |
301 break; | |
302 | |
303 // Moves current panel to the new position. | |
304 gfx::Rect bounds(current_panel->GetBounds()); | |
305 bounds.set_x(current_panel_left_boundary); | |
306 current_panel_left_boundary += bounds.width() + kPanelsHorizontalSpacing; | |
307 current_panel->SetPanelBounds(bounds); | |
308 | |
309 // Updates the index of current panel since it has been moved to the | |
310 // position of previous panel. | |
311 panels_[current_panel_index + 1] = current_panel; | |
312 } | |
313 | |
314 // Updates the position and index of dragging panel as the result of moving | |
315 // other affected panels. | |
316 if (current_panel_index != static_cast<int>(dragging_panel_index_) - 1) { | |
317 dragging_panel_bounds_.set_x(current_panel_left_boundary); | |
318 dragging_panel_index_ = current_panel_index + 1; | |
319 panels_[dragging_panel_index_] = dragging_panel; | |
320 } | |
321 } | 120 } |
322 | 121 |
323 void PanelManager::EndDragging(bool cancelled) { | 122 void PanelManager::EndDragging(bool cancelled) { |
324 DCHECK(dragging_panel_index_ != kInvalidPanelIndex); | 123 panel_strip_->EndDragging(cancelled); |
325 | |
326 if (cancelled) { | |
327 Drag(dragging_panel_original_x_ - | |
328 panels_[dragging_panel_index_]->GetBounds().x()); | |
329 } else { | |
330 panels_[dragging_panel_index_]->SetPanelBounds( | |
331 dragging_panel_bounds_); | |
332 } | |
333 | |
334 dragging_panel_index_ = kInvalidPanelIndex; | |
335 | |
336 DelayedRemove(); | |
337 } | 124 } |
338 | 125 |
339 void PanelManager::OnPanelExpansionStateChanged( | 126 void PanelManager::OnPanelExpansionStateChanged( |
340 Panel::ExpansionState old_state, Panel::ExpansionState new_state) { | 127 Panel::ExpansionState old_state, Panel::ExpansionState new_state) { |
341 DCHECK_NE(new_state, old_state); | 128 panel_strip_->OnPanelExpansionStateChanged(old_state, new_state); |
342 switch (new_state) { | |
343 case Panel::EXPANDED: | |
344 DecrementMinimizedPanels(); | |
345 break; | |
346 case Panel::MINIMIZED: | |
347 case Panel::TITLE_ONLY: | |
348 if (old_state == Panel::EXPANDED) | |
349 IncrementMinimizedPanels(); | |
350 break; | |
351 default: | |
352 break; | |
353 } | |
354 } | |
355 | |
356 void PanelManager::IncrementMinimizedPanels() { | |
357 if (!mouse_watching_disabled_ && !minimized_panel_count_) | |
358 panel_mouse_watcher_->AddObserver(this); | |
359 minimized_panel_count_++; | |
360 DCHECK_LE(minimized_panel_count_, num_panels()); | |
361 } | |
362 | |
363 void PanelManager::DecrementMinimizedPanels() { | |
364 minimized_panel_count_--; | |
365 DCHECK_GE(minimized_panel_count_, 0); | |
366 if (!mouse_watching_disabled_ && !minimized_panel_count_) | |
367 panel_mouse_watcher_->RemoveObserver(this); | |
368 } | 129 } |
369 | 130 |
370 void PanelManager::OnPreferredWindowSizeChanged( | 131 void PanelManager::OnPreferredWindowSizeChanged( |
371 Panel* panel, const gfx::Size& preferred_window_size) { | 132 Panel* panel, const gfx::Size& preferred_window_size) { |
372 if (!auto_sizing_enabled_) | 133 if (!auto_sizing_enabled_) |
373 return; | 134 return; |
374 | 135 panel_strip_->OnPreferredWindowSizeChanged(panel, preferred_window_size); |
375 gfx::Rect bounds = panel->GetBounds(); | |
376 | |
377 // The panel width: | |
378 // * cannot grow or shrink to go beyond [min_width, max_width] | |
379 int new_width = preferred_window_size.width(); | |
380 if (new_width > panel->max_size().width()) | |
381 new_width = panel->max_size().width(); | |
382 if (new_width < panel->min_size().width()) | |
383 new_width = panel->min_size().width(); | |
384 | |
385 if (new_width != bounds.width()) { | |
386 int delta = bounds.width() - new_width; | |
387 bounds.set_x(bounds.x() + delta); | |
388 bounds.set_width(new_width); | |
389 | |
390 // Reposition all the panels on the left. | |
391 int panel_index = -1; | |
392 for (int i = 0; i < static_cast<int>(panels_.size()); ++i) { | |
393 if (panels_[i] == panel) { | |
394 panel_index = i; | |
395 break; | |
396 } | |
397 } | |
398 DCHECK(panel_index >= 0); | |
399 for (int i = static_cast<int>(panels_.size()) -1; i > panel_index; | |
400 --i) { | |
401 gfx::Rect this_bounds = panels_[i]->GetBounds(); | |
402 this_bounds.set_x(this_bounds.x() + delta); | |
403 panels_[i]->SetPanelBounds(this_bounds); | |
404 } | |
405 } | |
406 | |
407 // The panel height: | |
408 // * cannot grow or shrink to go beyond [min_height, max_height] | |
409 int new_height = preferred_window_size.height(); | |
410 if (new_height > panel->max_size().height()) | |
411 new_height = panel->max_size().height(); | |
412 if (new_height < panel->min_size().height()) | |
413 new_height = panel->min_size().height(); | |
414 | |
415 // Only need to adjust bounds height when panel is expanded. | |
416 gfx::Size restored_size = panel->restored_size(); | |
417 if (new_height != restored_size.height() && | |
418 panel->expansion_state() == Panel::EXPANDED) { | |
419 bounds.set_y(bounds.y() - new_height + bounds.height()); | |
420 bounds.set_height(new_height); | |
421 } | |
422 | |
423 gfx::Size new_size = gfx::Size(new_width, new_height); | |
424 if (new_size != restored_size) | |
425 panel->set_restored_size(new_size); | |
426 | |
427 panel->SetPanelBounds(bounds); | |
428 } | 136 } |
429 | 137 |
430 bool PanelManager::ShouldBringUpTitlebars(int mouse_x, int mouse_y) const { | 138 bool PanelManager::ShouldBringUpTitlebars(int mouse_x, int mouse_y) const { |
431 // We should always bring up the titlebar if the mouse is over the | 139 return panel_strip_->ShouldBringUpTitlebars(mouse_x, mouse_y); |
432 // visible auto-hiding bottom bar. | |
433 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_BOTTOM) && | |
434 auto_hiding_desktop_bar_->GetVisibility( | |
435 AutoHidingDesktopBar::ALIGN_BOTTOM) == | |
436 AutoHidingDesktopBar::VISIBLE && | |
437 mouse_y >= adjusted_work_area_.bottom()) | |
438 return true; | |
439 | |
440 for (Panels::const_iterator iter = panels_.begin(); | |
441 iter != panels_.end(); ++iter) { | |
442 if ((*iter)->ShouldBringUpTitlebar(mouse_x, mouse_y)) | |
443 return true; | |
444 } | |
445 return false; | |
446 } | 140 } |
447 | 141 |
448 void PanelManager::BringUpOrDownTitlebars(bool bring_up) { | 142 void PanelManager::BringUpOrDownTitlebars(bool bring_up) { |
449 if (are_titlebars_up_ == bring_up) | 143 panel_strip_->BringUpOrDownTitlebars(bring_up); |
450 return; | |
451 are_titlebars_up_ = bring_up; | |
452 | |
453 int task_delay_milliseconds = 0; | |
454 | |
455 // If the auto-hiding bottom bar exists, delay the action until the bottom | |
456 // bar is fully visible or hidden. We do not want both bottom bar and panel | |
457 // titlebar to move at the same time but with different speeds. | |
458 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_BOTTOM)) { | |
459 AutoHidingDesktopBar::Visibility visibility = auto_hiding_desktop_bar_-> | |
460 GetVisibility(AutoHidingDesktopBar::ALIGN_BOTTOM); | |
461 if (visibility != (bring_up ? AutoHidingDesktopBar::VISIBLE | |
462 : AutoHidingDesktopBar::HIDDEN)) { | |
463 // Occasionally some system, like Windows, might not bring up or down the | |
464 // bottom bar when the mouse enters or leaves the bottom screen area. | |
465 // Thus, we schedule a delayed task to do the work if we do not receive | |
466 // the bottom bar visibility change notification within a certain period | |
467 // of time. | |
468 task_delay_milliseconds = | |
469 kMaxMillisecondsWaitForBottomBarVisibilityChange; | |
470 } | |
471 } | |
472 | |
473 // On some OSes, the interaction with native Taskbars/Docks may be improved | |
474 // if the panels do not go back to minimized state too fast. For example, | |
475 // it makes it possible to hit the titlebar on OSX if Dock has Magnifying | |
476 // enabled - the panels stay up for a while after Dock magnification effect | |
477 // stops covering the panels. | |
478 // | |
479 // Another example would be taskbar in auto-hide mode on Linux. In this mode | |
480 // taskbar will cover the panel in title hover mode, leaving it up for a few | |
481 // seconds would allow the user to be able to click on it. | |
482 // | |
483 // Currently, no platforms use both delays. | |
484 DCHECK(task_delay_milliseconds == 0); | |
485 if (!bring_up) | |
486 task_delay_milliseconds = kMillisecondsBeforeCollapsingFromTitleOnlyState; | |
487 | |
488 // OnAutoHidingDesktopBarVisibilityChanged will handle this. | |
489 delayed_titlebar_action_ = bring_up ? BRING_UP : BRING_DOWN; | |
490 if (remove_delays_for_testing_) | |
491 task_delay_milliseconds = 0; | |
492 | |
493 // If user moves the mouse in and out of mouse tracking area, we might have | |
494 // previously posted but not yet dispatched task in the queue. New action | |
495 // should always 'reset' the delays so cancel any tasks that haven't run yet | |
496 // and post a new one. | |
497 titlebar_action_factory_.InvalidateWeakPtrs(); | |
498 MessageLoop::current()->PostDelayedTask( | |
499 FROM_HERE, | |
500 base::Bind(&PanelManager::DelayedBringUpOrDownTitlebarsCheck, | |
501 titlebar_action_factory_.GetWeakPtr()), | |
502 task_delay_milliseconds); | |
503 } | |
504 | |
505 void PanelManager::DelayedBringUpOrDownTitlebarsCheck() { | |
506 // Task was already processed or cancelled - bail out. | |
507 if (delayed_titlebar_action_ == NO_ACTION) | |
508 return; | |
509 | |
510 bool need_to_bring_up_titlebars = (delayed_titlebar_action_ == BRING_UP); | |
511 | |
512 delayed_titlebar_action_ = NO_ACTION; | |
513 | |
514 // Check if the action is still needed based on the latest mouse position. The | |
515 // user could move the mouse into the tracking area and then quickly move it | |
516 // out of the area. In case of this, cancel the action. | |
517 if (are_titlebars_up_ != need_to_bring_up_titlebars) | |
518 return; | |
519 | |
520 DoBringUpOrDownTitlebars(need_to_bring_up_titlebars); | |
521 } | |
522 | |
523 void PanelManager::DoBringUpOrDownTitlebars(bool bring_up) { | |
524 for (Panels::const_iterator iter = panels_.begin(); | |
525 iter != panels_.end(); ++iter) { | |
526 Panel* panel = *iter; | |
527 | |
528 // Skip any panel that is drawing the attention. | |
529 if (panel->IsDrawingAttention()) | |
530 continue; | |
531 | |
532 if (bring_up) { | |
533 if (panel->expansion_state() == Panel::MINIMIZED) | |
534 panel->SetExpansionState(Panel::TITLE_ONLY); | |
535 } else { | |
536 if (panel->expansion_state() == Panel::TITLE_ONLY) | |
537 panel->SetExpansionState(Panel::MINIMIZED); | |
538 } | |
539 } | |
540 } | 144 } |
541 | 145 |
542 void PanelManager::AdjustWorkAreaForAutoHidingDesktopBars() { | 146 void PanelManager::AdjustWorkAreaForAutoHidingDesktopBars() { |
543 // Note that we do not care about the desktop bar aligned to the top edge | 147 // Note that we do not care about the desktop bar aligned to the top edge |
544 // since panels could not reach so high due to size constraint. | 148 // since panels could not reach so high due to size constraint. |
545 adjusted_work_area_ = work_area_; | 149 adjusted_work_area_ = work_area_; |
546 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_LEFT)) { | 150 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_LEFT)) { |
547 int space = auto_hiding_desktop_bar_->GetThickness( | 151 int space = auto_hiding_desktop_bar_->GetThickness( |
548 AutoHidingDesktopBar::ALIGN_LEFT); | 152 AutoHidingDesktopBar::ALIGN_LEFT); |
549 adjusted_work_area_.set_x(adjusted_work_area_.x() + space); | 153 adjusted_work_area_.set_x(adjusted_work_area_.x() + space); |
550 adjusted_work_area_.set_width(adjusted_work_area_.width() - space); | 154 adjusted_work_area_.set_width(adjusted_work_area_.width() - space); |
551 } | 155 } |
552 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_RIGHT)) { | 156 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_RIGHT)) { |
553 int space = auto_hiding_desktop_bar_->GetThickness( | 157 int space = auto_hiding_desktop_bar_->GetThickness( |
554 AutoHidingDesktopBar::ALIGN_RIGHT); | 158 AutoHidingDesktopBar::ALIGN_RIGHT); |
555 adjusted_work_area_.set_width(adjusted_work_area_.width() - space); | 159 adjusted_work_area_.set_width(adjusted_work_area_.width() - space); |
556 } | 160 } |
557 } | 161 } |
558 | 162 |
559 int PanelManager::GetBottomPositionForExpansionState( | 163 int PanelManager::GetBottomPositionForExpansionState( |
560 Panel::ExpansionState expansion_state) const { | 164 Panel::ExpansionState expansion_state) const { |
561 int bottom = adjusted_work_area_.bottom(); | 165 return panel_strip_->GetBottomPositionForExpansionState(expansion_state); |
562 // If there is an auto-hiding desktop bar aligned to the bottom edge, we need | |
563 // to move the title-only panel above the auto-hiding desktop bar. | |
564 if (expansion_state == Panel::TITLE_ONLY && | |
565 auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_BOTTOM)) { | |
566 bottom -= auto_hiding_desktop_bar_->GetThickness( | |
567 AutoHidingDesktopBar::ALIGN_BOTTOM); | |
568 } | |
569 | |
570 return bottom; | |
571 } | 166 } |
572 | 167 |
573 BrowserWindow* PanelManager::GetNextBrowserWindowToActivate( | 168 BrowserWindow* PanelManager::GetNextBrowserWindowToActivate( |
574 Panel* panel) const { | 169 Panel* panel) const { |
575 // Find the last active browser window that is not minimized. | 170 // Find the last active browser window that is not minimized. |
576 BrowserList::const_reverse_iterator iter = BrowserList::begin_last_active(); | 171 BrowserList::const_reverse_iterator iter = BrowserList::begin_last_active(); |
577 BrowserList::const_reverse_iterator end = BrowserList::end_last_active(); | 172 BrowserList::const_reverse_iterator end = BrowserList::end_last_active(); |
578 for (; (iter != end); ++iter) { | 173 for (; (iter != end); ++iter) { |
579 Browser* browser = *iter; | 174 Browser* browser = *iter; |
580 if (panel->browser() != browser && !browser->window()->IsMinimized()) | 175 if (panel->browser() != browser && !browser->window()->IsMinimized()) |
581 return browser->window(); | 176 return browser->window(); |
582 } | 177 } |
583 | 178 |
584 return NULL; | 179 return NULL; |
585 } | 180 } |
586 | 181 |
587 void PanelManager::MoveToPanelStrip(Panel* panel) { | |
588 // TODO(jennb) - implement. | |
589 } | |
590 | |
591 void PanelManager::MoveToOverflowStrip(Panel* panel, bool is_new) { | 182 void PanelManager::MoveToOverflowStrip(Panel* panel, bool is_new) { |
592 // TODO(jianli) - implement. | 183 // TODO(jianli) - implement. |
593 } | 184 } |
594 | 185 |
595 void PanelManager::OnMouseMove(const gfx::Point& mouse_position) { | |
596 bool bring_up_titlebars = ShouldBringUpTitlebars(mouse_position.x(), | |
597 mouse_position.y()); | |
598 BringUpOrDownTitlebars(bring_up_titlebars); | |
599 } | |
600 | |
601 void PanelManager::OnAutoHidingDesktopBarThicknessChanged() { | 186 void PanelManager::OnAutoHidingDesktopBarThicknessChanged() { |
602 AdjustWorkAreaForAutoHidingDesktopBars(); | 187 AdjustWorkAreaForAutoHidingDesktopBars(); |
603 Rearrange(panels_.begin(), StartingRightPosition()); | 188 Layout(); |
604 } | 189 } |
605 | 190 |
606 void PanelManager::OnAutoHidingDesktopBarVisibilityChanged( | 191 void PanelManager::OnAutoHidingDesktopBarVisibilityChanged( |
607 AutoHidingDesktopBar::Alignment alignment, | 192 AutoHidingDesktopBar::Alignment alignment, |
608 AutoHidingDesktopBar::Visibility visibility) { | 193 AutoHidingDesktopBar::Visibility visibility) { |
609 if (delayed_titlebar_action_ == NO_ACTION) | 194 panel_strip_->OnAutoHidingDesktopBarVisibilityChanged(alignment, visibility); |
610 return; | |
611 | |
612 AutoHidingDesktopBar::Visibility expected_visibility = | |
613 delayed_titlebar_action_ == BRING_UP ? AutoHidingDesktopBar::VISIBLE | |
614 : AutoHidingDesktopBar::HIDDEN; | |
615 if (visibility != expected_visibility) | |
616 return; | |
617 | |
618 DoBringUpOrDownTitlebars(delayed_titlebar_action_ == BRING_UP); | |
619 delayed_titlebar_action_ = NO_ACTION; | |
620 } | |
621 | |
622 void PanelManager::Rearrange(Panels::iterator iter_to_start, | |
623 int rightmost_position) { | |
624 for (Panels::iterator iter = iter_to_start; iter != panels_.end(); ++iter) { | |
625 Panel* panel = *iter; | |
626 gfx::Rect new_bounds(panel->GetBounds()); | |
627 new_bounds.set_x(rightmost_position - new_bounds.width()); | |
628 new_bounds.set_y( | |
629 GetBottomPositionForExpansionState(panel->expansion_state()) - | |
630 new_bounds.height()); | |
631 if (new_bounds != panel->GetBounds()) | |
632 panel->SetPanelBounds(new_bounds); | |
633 | |
634 rightmost_position = new_bounds.x() - kPanelsHorizontalSpacing; | |
635 } | |
636 } | 195 } |
637 | 196 |
638 void PanelManager::RemoveAll() { | 197 void PanelManager::RemoveAll() { |
639 // This should not be called when we're in the process of dragging. | 198 panel_strip_->RemoveAll(); |
640 DCHECK(dragging_panel_index_ == kInvalidPanelIndex); | 199 // TODO(jianli): overflow_strip_->RemoveAll(); |
200 } | |
641 | 201 |
642 // Make a copy of the iterator as closing panels can modify the vector. | 202 int PanelManager::num_panels() const { |
643 Panels panels_copy = panels_; | 203 return panel_strip_->num_panels(); |
644 | 204 // TODO(jianli): + overflow_strip_->num_panels(); |
645 // Start from the bottom to avoid reshuffling. | |
646 for (Panels::reverse_iterator iter = panels_copy.rbegin(); | |
647 iter != panels_copy.rend(); ++iter) | |
648 (*iter)->Close(); | |
649 } | 205 } |
650 | 206 |
651 bool PanelManager::is_dragging_panel() const { | 207 bool PanelManager::is_dragging_panel() const { |
652 return dragging_panel_index_ != kInvalidPanelIndex; | 208 return panel_strip_->is_dragging_panel(); |
653 } | 209 } |
210 | |
211 const PanelManager::Panels& PanelManager::panels() const { | |
212 return panel_strip_->panels(); | |
213 } | |
OLD | NEW |