Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ash/touch/touch_observer_hud.h" | 5 #include "ash/touch/touch_observer_hud.h" |
| 6 | 6 |
| 7 #include "ash/display/display_controller.h" | |
| 8 #include "ash/display/display_manager.h" | 7 #include "ash/display/display_manager.h" |
| 9 #include "ash/root_window_controller.h" | 8 #include "ash/root_window_controller.h" |
| 9 #include "ash/shell.h" | |
| 10 #include "ash/shell_window_ids.h" | 10 #include "ash/shell_window_ids.h" |
| 11 #include "ash/wm/property_util.h" | 11 #include "ash/wm/property_util.h" |
| 12 #include "base/json/json_string_value_serializer.h" | |
| 13 #include "base/strings/string_number_conversions.h" | |
| 14 #include "base/strings/stringprintf.h" | |
| 15 #include "base/strings/utf_string_conversions.h" | |
| 16 #include "third_party/skia/include/core/SkPath.h" | |
| 17 #include "third_party/skia/include/core/SkXfermode.h" | |
| 18 #include "third_party/skia/include/effects/SkGradientShader.h" | |
| 19 #include "ui/aura/root_window.h" | 12 #include "ui/aura/root_window.h" |
| 20 #include "ui/aura/window.h" | |
| 21 #include "ui/base/animation/animation_delegate.h" | |
| 22 #include "ui/base/animation/linear_animation.h" | |
| 23 #include "ui/base/events/event.h" | |
| 24 #include "ui/gfx/canvas.h" | |
| 25 #include "ui/gfx/display.h" | 13 #include "ui/gfx/display.h" |
| 26 #include "ui/gfx/rect.h" | 14 #include "ui/gfx/rect.h" |
| 27 #include "ui/gfx/screen.h" | 15 #include "ui/gfx/screen.h" |
| 28 #include "ui/gfx/size.h" | 16 #include "ui/gfx/size.h" |
| 29 #include "ui/gfx/transform.h" | |
| 30 #include "ui/views/background.h" | |
| 31 #include "ui/views/controls/label.h" | |
| 32 #include "ui/views/layout/box_layout.h" | |
| 33 #include "ui/views/widget/widget.h" | 17 #include "ui/views/widget/widget.h" |
| 34 | 18 |
| 35 #if defined(USE_X11) | |
| 36 #include <X11/extensions/XInput2.h> | |
| 37 #include <X11/Xlib.h> | |
| 38 | |
| 39 #include "ui/base/x/device_data_manager.h" | |
| 40 #endif | |
| 41 | |
| 42 namespace ash { | 19 namespace ash { |
| 43 namespace internal { | 20 namespace internal { |
| 44 | 21 |
| 45 const int kPointRadius = 20; | |
| 46 const SkColor kColors[] = { | |
| 47 SK_ColorYELLOW, | |
| 48 SK_ColorGREEN, | |
| 49 SK_ColorRED, | |
| 50 SK_ColorBLUE, | |
| 51 SK_ColorGRAY, | |
| 52 SK_ColorMAGENTA, | |
| 53 SK_ColorCYAN, | |
| 54 SK_ColorWHITE, | |
| 55 SK_ColorBLACK, | |
| 56 SkColorSetRGB(0xFF, 0x8C, 0x00), | |
| 57 SkColorSetRGB(0x8B, 0x45, 0x13), | |
| 58 SkColorSetRGB(0xFF, 0xDE, 0xAD), | |
| 59 }; | |
| 60 const int kAlpha = 0x60; | |
| 61 const SkColor kProjectionFillColor = SkColorSetRGB(0xF5, 0xF5, 0xDC); | |
| 62 const SkColor kProjectionStrokeColor = SK_ColorGRAY; | |
| 63 const int kProjectionAlpha = 0xB0; | |
| 64 const int kMaxPaths = arraysize(kColors); | |
| 65 const int kReducedScale = 10; | |
| 66 const int kFadeoutDurationInMs = 250; | |
| 67 const int kFadeoutFrameRate = 60; | |
| 68 | |
| 69 const char* GetTouchEventLabel(ui::EventType type) { | |
| 70 switch (type) { | |
| 71 case ui::ET_UNKNOWN: | |
| 72 return " "; | |
| 73 case ui::ET_TOUCH_PRESSED: | |
| 74 return "P"; | |
| 75 case ui::ET_TOUCH_MOVED: | |
| 76 return "M"; | |
| 77 case ui::ET_TOUCH_RELEASED: | |
| 78 return "R"; | |
| 79 case ui::ET_TOUCH_CANCELLED: | |
| 80 return "C"; | |
| 81 default: | |
| 82 break; | |
| 83 } | |
| 84 return "?"; | |
| 85 } | |
| 86 | |
| 87 int GetTrackingId(const ui::TouchEvent& event) { | |
| 88 if (!event.HasNativeEvent()) | |
| 89 return 0; | |
| 90 #if defined(USE_XI2_MT) | |
| 91 ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance(); | |
| 92 double tracking_id; | |
| 93 if (manager->GetEventData(*event.native_event(), | |
| 94 ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, | |
| 95 &tracking_id)) { | |
| 96 return static_cast<int>(tracking_id); | |
| 97 } | |
| 98 #endif | |
| 99 return 0; | |
| 100 } | |
| 101 | |
| 102 int GetSourceDeviceId(const ui::TouchEvent& event) { | |
| 103 if (!event.HasNativeEvent()) | |
| 104 return 0; | |
| 105 #if defined(USE_X11) | |
| 106 XEvent* xev = event.native_event(); | |
| 107 return static_cast<XIDeviceEvent*>(xev->xcookie.data)->sourceid; | |
| 108 #endif | |
| 109 return 0; | |
| 110 } | |
| 111 | |
| 112 // A TouchPointLog represents a single touch-event of a touch point. | |
| 113 struct TouchPointLog { | |
| 114 public: | |
| 115 explicit TouchPointLog(const ui::TouchEvent& touch) | |
| 116 : id(touch.touch_id()), | |
| 117 type(touch.type()), | |
| 118 location(touch.root_location()), | |
| 119 timestamp(touch.time_stamp().InMillisecondsF()), | |
| 120 radius_x(touch.radius_x()), | |
| 121 radius_y(touch.radius_y()), | |
| 122 pressure(touch.force()), | |
| 123 tracking_id(GetTrackingId(touch)), | |
| 124 source_device(GetSourceDeviceId(touch)) { | |
| 125 } | |
| 126 | |
| 127 // Populates a dictionary value with all the information about the touch | |
| 128 // point. | |
| 129 scoped_ptr<DictionaryValue> GetAsDictionary() const { | |
| 130 scoped_ptr<DictionaryValue> value(new DictionaryValue()); | |
| 131 | |
| 132 value->SetInteger("id", id); | |
| 133 value->SetString("type", std::string(GetTouchEventLabel(type))); | |
| 134 value->SetString("location", location.ToString()); | |
| 135 value->SetDouble("timestamp", timestamp); | |
| 136 value->SetDouble("radius_x", radius_x); | |
| 137 value->SetDouble("radius_y", radius_y); | |
| 138 value->SetDouble("pressure", pressure); | |
| 139 value->SetInteger("tracking_id", tracking_id); | |
| 140 value->SetInteger("source_device", source_device); | |
| 141 | |
| 142 return value.Pass(); | |
| 143 } | |
| 144 | |
| 145 int id; | |
| 146 ui::EventType type; | |
| 147 gfx::Point location; | |
| 148 double timestamp; | |
| 149 float radius_x; | |
| 150 float radius_y; | |
| 151 float pressure; | |
| 152 int tracking_id; | |
| 153 int source_device; | |
| 154 }; | |
| 155 | |
| 156 // A TouchTrace keeps track of all the touch events of a single touch point | |
| 157 // (starting from a touch-press and ending at touch-release). | |
| 158 class TouchTrace { | |
| 159 public: | |
| 160 typedef std::vector<TouchPointLog>::iterator iterator; | |
| 161 typedef std::vector<TouchPointLog>::const_iterator const_iterator; | |
| 162 typedef std::vector<TouchPointLog>::reverse_iterator reverse_iterator; | |
| 163 typedef std::vector<TouchPointLog>::const_reverse_iterator | |
| 164 const_reverse_iterator; | |
| 165 | |
| 166 TouchTrace() { | |
| 167 } | |
| 168 | |
| 169 void AddTouchPoint(const ui::TouchEvent& touch) { | |
| 170 log_.push_back(TouchPointLog(touch)); | |
| 171 } | |
| 172 | |
| 173 const std::vector<TouchPointLog>& log() const { return log_; } | |
| 174 | |
| 175 bool active() const { | |
| 176 return !log_.empty() && log_.back().type != ui::ET_TOUCH_RELEASED && | |
| 177 log_.back().type != ui::ET_TOUCH_CANCELLED; | |
| 178 } | |
| 179 | |
| 180 // Returns a list containing data from all events for the touch point. | |
| 181 scoped_ptr<ListValue> GetAsList() const { | |
| 182 scoped_ptr<ListValue> list(new ListValue()); | |
| 183 for (const_iterator i = log_.begin(); i != log_.end(); ++i) | |
| 184 list->Append((*i).GetAsDictionary().release()); | |
| 185 return list.Pass(); | |
| 186 } | |
| 187 | |
| 188 void Reset() { | |
| 189 log_.clear(); | |
| 190 } | |
| 191 | |
| 192 private: | |
| 193 std::vector<TouchPointLog> log_; | |
| 194 | |
| 195 DISALLOW_COPY_AND_ASSIGN(TouchTrace); | |
| 196 }; | |
| 197 | |
| 198 // A TouchLog keeps track of all touch events of all touch points. | |
| 199 class TouchLog { | |
| 200 public: | |
| 201 TouchLog() : next_trace_index_(0) { | |
| 202 } | |
| 203 | |
| 204 void AddTouchPoint(const ui::TouchEvent& touch) { | |
| 205 if (touch.type() == ui::ET_TOUCH_PRESSED) | |
| 206 StartTrace(touch); | |
| 207 AddToTrace(touch); | |
| 208 } | |
| 209 | |
| 210 void Reset() { | |
| 211 next_trace_index_ = 0; | |
| 212 for (int i = 0; i < kMaxPaths; ++i) | |
| 213 traces_[i].Reset(); | |
| 214 } | |
| 215 | |
| 216 scoped_ptr<ListValue> GetAsList() const { | |
| 217 scoped_ptr<ListValue> list(new ListValue()); | |
| 218 for (int i = 0; i < kMaxPaths; ++i) { | |
| 219 if (!traces_[i].log().empty()) | |
| 220 list->Append(traces_[i].GetAsList().release()); | |
| 221 } | |
| 222 return list.Pass(); | |
| 223 } | |
| 224 | |
| 225 int GetTraceIndex(int touch_id) const { | |
| 226 return touch_id_to_trace_index_.at(touch_id); | |
| 227 } | |
| 228 | |
| 229 const TouchTrace* traces() const { | |
| 230 return traces_; | |
| 231 } | |
| 232 | |
| 233 private: | |
| 234 void StartTrace(const ui::TouchEvent& touch) { | |
| 235 // Find the first inactive spot; otherwise, overwrite the one | |
| 236 // |next_trace_index_| is pointing to. | |
| 237 int old_trace_index = next_trace_index_; | |
| 238 do { | |
| 239 if (!traces_[next_trace_index_].active()) | |
| 240 break; | |
| 241 next_trace_index_ = (next_trace_index_ + 1) % kMaxPaths; | |
| 242 } while (next_trace_index_ != old_trace_index); | |
| 243 int touch_id = touch.touch_id(); | |
| 244 traces_[next_trace_index_].Reset(); | |
| 245 touch_id_to_trace_index_[touch_id] = next_trace_index_; | |
| 246 next_trace_index_ = (next_trace_index_ + 1) % kMaxPaths; | |
| 247 } | |
| 248 | |
| 249 void AddToTrace(const ui::TouchEvent& touch) { | |
| 250 int touch_id = touch.touch_id(); | |
| 251 int trace_index = touch_id_to_trace_index_[touch_id]; | |
| 252 traces_[trace_index].AddTouchPoint(touch); | |
| 253 } | |
| 254 | |
| 255 TouchTrace traces_[kMaxPaths]; | |
| 256 int next_trace_index_; | |
| 257 | |
| 258 std::map<int, int> touch_id_to_trace_index_; | |
| 259 | |
| 260 DISALLOW_COPY_AND_ASSIGN(TouchLog); | |
| 261 }; | |
| 262 | |
| 263 // TouchHudCanvas draws touch traces in |FULLSCREEN| and |REDUCED_SCALE| modes. | |
| 264 class TouchHudCanvas : public views::View { | |
| 265 public: | |
| 266 explicit TouchHudCanvas(const TouchLog& touch_log) | |
| 267 : touch_log_(touch_log), | |
| 268 scale_(1) { | |
| 269 SetPaintToLayer(true); | |
| 270 SetFillsBoundsOpaquely(false); | |
| 271 | |
| 272 paint_.setStyle(SkPaint::kFill_Style); | |
| 273 } | |
| 274 | |
| 275 virtual ~TouchHudCanvas() {} | |
| 276 | |
| 277 void SetScale(int scale) { | |
| 278 if (scale_ == scale) | |
| 279 return; | |
| 280 scale_ = scale; | |
| 281 gfx::Transform transform; | |
| 282 transform.Scale(1. / scale_, 1. / scale_); | |
| 283 layer()->SetTransform(transform); | |
| 284 } | |
| 285 | |
| 286 int scale() const { return scale_; } | |
| 287 | |
| 288 void TouchPointAdded(int touch_id) { | |
| 289 int trace_index = touch_log_.GetTraceIndex(touch_id); | |
| 290 const TouchTrace& trace = touch_log_.traces()[trace_index]; | |
| 291 const TouchPointLog& point = trace.log().back(); | |
| 292 if (point.type == ui::ET_TOUCH_PRESSED) | |
| 293 StartedTrace(trace_index); | |
| 294 if (point.type != ui::ET_TOUCH_CANCELLED) | |
| 295 AddedPointToTrace(trace_index); | |
| 296 } | |
| 297 | |
| 298 void Clear() { | |
| 299 for (int i = 0; i < kMaxPaths; ++i) | |
| 300 paths_[i].reset(); | |
| 301 | |
| 302 SchedulePaint(); | |
| 303 } | |
| 304 | |
| 305 private: | |
| 306 void StartedTrace(int trace_index) { | |
| 307 paths_[trace_index].reset(); | |
| 308 colors_[trace_index] = SkColorSetA(kColors[trace_index], kAlpha); | |
| 309 } | |
| 310 | |
| 311 void AddedPointToTrace(int trace_index) { | |
| 312 const TouchTrace& trace = touch_log_.traces()[trace_index]; | |
| 313 const TouchPointLog& point = trace.log().back(); | |
| 314 const gfx::Point& location = point.location; | |
| 315 SkScalar x = SkIntToScalar(location.x()); | |
| 316 SkScalar y = SkIntToScalar(location.y()); | |
| 317 SkPoint last; | |
| 318 if (!paths_[trace_index].getLastPt(&last) || x != last.x() || | |
| 319 y != last.y()) { | |
| 320 paths_[trace_index].addCircle(x, y, SkIntToScalar(kPointRadius)); | |
| 321 SchedulePaint(); | |
| 322 } | |
| 323 } | |
| 324 | |
| 325 // Overridden from views::View. | |
| 326 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { | |
| 327 for (int i = 0; i < kMaxPaths; ++i) { | |
| 328 if (paths_[i].countPoints() == 0) | |
| 329 continue; | |
| 330 paint_.setColor(colors_[i]); | |
| 331 canvas->DrawPath(paths_[i], paint_); | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 SkPaint paint_; | |
| 336 | |
| 337 const TouchLog& touch_log_; | |
| 338 SkPath paths_[kMaxPaths]; | |
| 339 SkColor colors_[kMaxPaths]; | |
| 340 | |
| 341 int scale_; | |
| 342 | |
| 343 DISALLOW_COPY_AND_ASSIGN(TouchHudCanvas); | |
| 344 }; | |
| 345 | |
| 346 // TouchPointView draws a single touch point in |PROJECTION| mode. This object | |
| 347 // manages its own lifetime and deletes itself upon fade-out completion or | |
| 348 // whenever |Remove()| is explicitly called. | |
| 349 class TouchPointView : public views::View, | |
| 350 public ui::AnimationDelegate, | |
| 351 public views::WidgetObserver { | |
| 352 public: | |
| 353 explicit TouchPointView(views::Widget* parent_widget) | |
| 354 : circle_center_(kPointRadius + 1, kPointRadius + 1), | |
| 355 gradient_center_(SkPoint::Make(kPointRadius + 1, | |
| 356 kPointRadius + 1)) { | |
| 357 SetPaintToLayer(true); | |
| 358 SetFillsBoundsOpaquely(false); | |
| 359 | |
| 360 SetSize(gfx::Size(2 * kPointRadius + 2, 2 * kPointRadius + 2)); | |
| 361 | |
| 362 stroke_paint_.setStyle(SkPaint::kStroke_Style); | |
| 363 stroke_paint_.setColor(kProjectionStrokeColor); | |
| 364 | |
| 365 gradient_colors_[0] = kProjectionFillColor; | |
| 366 gradient_colors_[1] = kProjectionStrokeColor; | |
| 367 | |
| 368 gradient_pos_[0] = SkFloatToScalar(0.9f); | |
| 369 gradient_pos_[1] = SkFloatToScalar(1.0f); | |
| 370 | |
| 371 parent_widget->GetContentsView()->AddChildView(this); | |
| 372 | |
| 373 parent_widget->AddObserver(this); | |
| 374 } | |
| 375 | |
| 376 void UpdateTouch(const ui::TouchEvent& touch) { | |
| 377 if (touch.type() == ui::ET_TOUCH_RELEASED || | |
| 378 touch.type() == ui::ET_TOUCH_CANCELLED) { | |
| 379 fadeout_.reset(new ui::LinearAnimation(kFadeoutDurationInMs, | |
| 380 kFadeoutFrameRate, | |
| 381 this)); | |
| 382 fadeout_->Start(); | |
| 383 } else { | |
| 384 SetX(touch.root_location().x() - kPointRadius - 1); | |
| 385 SetY(touch.root_location().y() - kPointRadius - 1); | |
| 386 } | |
| 387 } | |
| 388 | |
| 389 void Remove() { | |
| 390 delete this; | |
| 391 } | |
| 392 | |
| 393 private: | |
| 394 virtual ~TouchPointView() { | |
| 395 GetWidget()->RemoveObserver(this); | |
| 396 parent()->RemoveChildView(this); | |
| 397 } | |
| 398 | |
| 399 // Overridden from views::View. | |
| 400 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { | |
| 401 int alpha = kProjectionAlpha; | |
| 402 if (fadeout_) | |
| 403 alpha = static_cast<int>(fadeout_->CurrentValueBetween(alpha, 0)); | |
| 404 fill_paint_.setAlpha(alpha); | |
| 405 stroke_paint_.setAlpha(alpha); | |
| 406 SkShader* shader = SkGradientShader::CreateRadial( | |
| 407 gradient_center_, | |
| 408 SkIntToScalar(kPointRadius), | |
| 409 gradient_colors_, | |
| 410 gradient_pos_, | |
| 411 arraysize(gradient_colors_), | |
| 412 SkShader::kMirror_TileMode, | |
| 413 NULL); | |
| 414 fill_paint_.setShader(shader); | |
| 415 shader->unref(); | |
| 416 canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius), | |
| 417 fill_paint_); | |
| 418 canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius), | |
| 419 stroke_paint_); | |
| 420 } | |
| 421 | |
| 422 // Overridden from ui::AnimationDelegate. | |
| 423 virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE { | |
| 424 DCHECK_EQ(fadeout_.get(), animation); | |
| 425 delete this; | |
| 426 } | |
| 427 | |
| 428 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE { | |
| 429 DCHECK_EQ(fadeout_.get(), animation); | |
| 430 SchedulePaint(); | |
| 431 } | |
| 432 | |
| 433 virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE { | |
| 434 AnimationEnded(animation); | |
| 435 } | |
| 436 | |
| 437 // Overridden from views::WidgetObserver. | |
| 438 virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE { | |
| 439 fadeout_->Stop(); | |
| 440 } | |
| 441 | |
| 442 const gfx::Point circle_center_; | |
| 443 const SkPoint gradient_center_; | |
| 444 | |
| 445 SkPaint fill_paint_; | |
| 446 SkPaint stroke_paint_; | |
| 447 SkColor gradient_colors_[2]; | |
| 448 SkScalar gradient_pos_[2]; | |
| 449 | |
| 450 scoped_ptr<ui::Animation> fadeout_; | |
| 451 | |
| 452 DISALLOW_COPY_AND_ASSIGN(TouchPointView); | |
| 453 }; | |
| 454 | |
| 455 TouchObserverHUD::TouchObserverHUD(aura::RootWindow* initial_root) | 22 TouchObserverHUD::TouchObserverHUD(aura::RootWindow* initial_root) |
| 456 : display_id_(initial_root->GetProperty(kDisplayIdKey)), | 23 : display_id_(initial_root->GetProperty(kDisplayIdKey)), |
| 457 root_window_(initial_root), | 24 root_window_(initial_root) { |
| 458 mode_(FULLSCREEN), | |
| 459 touch_log_(new TouchLog()) { | |
| 460 const gfx::Display& display = | 25 const gfx::Display& display = |
| 461 Shell::GetInstance()->display_manager()->GetDisplayForId(display_id_); | 26 Shell::GetInstance()->display_manager()->GetDisplayForId(display_id_); |
| 462 | 27 |
| 463 views::View* content = new views::View; | 28 views::View* content = new views::View; |
| 464 | 29 |
| 465 canvas_ = new TouchHudCanvas(*touch_log_); | |
| 466 content->AddChildView(canvas_); | |
| 467 | |
| 468 const gfx::Size& display_size = display.size(); | 30 const gfx::Size& display_size = display.size(); |
| 469 canvas_->SetSize(display_size); | |
| 470 content->SetSize(display_size); | 31 content->SetSize(display_size); |
| 471 | 32 |
| 472 label_container_ = new views::View; | |
| 473 label_container_->SetLayoutManager(new views::BoxLayout( | |
| 474 views::BoxLayout::kVertical, 0, 0, 0)); | |
| 475 | |
| 476 for (int i = 0; i < kMaxTouchPoints; ++i) { | |
| 477 touch_labels_[i] = new views::Label; | |
| 478 touch_labels_[i]->SetBackgroundColor(SkColorSetARGB(0, 255, 255, 255)); | |
| 479 touch_labels_[i]->SetShadowColors(SK_ColorWHITE, | |
| 480 SK_ColorWHITE); | |
| 481 touch_labels_[i]->SetShadowOffset(1, 1); | |
| 482 label_container_->AddChildView(touch_labels_[i]); | |
| 483 } | |
| 484 label_container_->SetX(0); | |
| 485 label_container_->SetY(display_size.height() / kReducedScale); | |
| 486 label_container_->SetSize(label_container_->GetPreferredSize()); | |
| 487 label_container_->SetVisible(false); | |
| 488 content->AddChildView(label_container_); | |
| 489 | |
| 490 widget_ = new views::Widget(); | 33 widget_ = new views::Widget(); |
| 491 views::Widget::InitParams | 34 views::Widget::InitParams |
| 492 params(views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); | 35 params(views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| 493 params.transparent = true; | 36 params.transparent = true; |
| 494 params.can_activate = false; | 37 params.can_activate = false; |
| 495 params.accept_events = false; | 38 params.accept_events = false; |
| 496 params.bounds = gfx::Rect(display_size); | 39 params.bounds = display.bounds(); |
|
sadrul
2013/06/26 17:26:21
This fixes positioning the HUD in the right displa
mohsen
2013/06/26 19:15:49
Yes. The bounds for "overlay container" need to be
| |
| 497 params.parent = Shell::GetContainer( | 40 params.parent = Shell::GetContainer( |
| 498 root_window_, | 41 root_window_, |
| 499 internal::kShellWindowId_OverlayContainer); | 42 internal::kShellWindowId_OverlayContainer); |
| 500 widget_->Init(params); | 43 widget_->Init(params); |
| 501 widget_->SetContentsView(content); | 44 widget_->SetContentsView(content); |
| 502 widget_->StackAtTop(); | 45 widget_->StackAtTop(); |
| 503 widget_->Show(); | 46 widget_->Show(); |
| 504 | 47 |
| 505 widget_->AddObserver(this); | 48 widget_->AddObserver(this); |
| 506 | 49 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 518 Shell::GetInstance()->display_controller()->RemoveObserver(this); | 61 Shell::GetInstance()->display_controller()->RemoveObserver(this); |
| 519 | 62 |
| 520 #if defined(OS_CHROMEOS) | 63 #if defined(OS_CHROMEOS) |
| 521 Shell::GetInstance()->output_configurator()->RemoveObserver(this); | 64 Shell::GetInstance()->output_configurator()->RemoveObserver(this); |
| 522 #endif // defined(OS_CHROMEOS) | 65 #endif // defined(OS_CHROMEOS) |
| 523 Shell::GetScreen()->RemoveObserver(this); | 66 Shell::GetScreen()->RemoveObserver(this); |
| 524 | 67 |
| 525 widget_->RemoveObserver(this); | 68 widget_->RemoveObserver(this); |
| 526 } | 69 } |
| 527 | 70 |
| 528 // static | 71 void TouchObserverHUD::Clear() { |
| 529 scoped_ptr<DictionaryValue> TouchObserverHUD::GetAllAsDictionary() { | |
| 530 scoped_ptr<DictionaryValue> value(new DictionaryValue()); | |
| 531 Shell::RootWindowList roots = Shell::GetInstance()->GetAllRootWindows(); | |
| 532 for (Shell::RootWindowList::iterator iter = roots.begin(); | |
| 533 iter != roots.end(); ++iter) { | |
| 534 internal::RootWindowController* controller = GetRootWindowController(*iter); | |
| 535 if (controller->touch_observer_hud()) { | |
| 536 int64 display_id = (*iter)->GetProperty(kDisplayIdKey); | |
| 537 scoped_ptr<ListValue> list = | |
| 538 controller->touch_observer_hud()->GetLogAsList(); | |
| 539 if (!list->empty()) | |
| 540 value->Set(base::Int64ToString(display_id), list.release()); | |
| 541 } | |
| 542 } | |
| 543 return value.Pass(); | |
| 544 } | 72 } |
| 545 | 73 |
| 546 void TouchObserverHUD::ChangeToNextMode() { | 74 void TouchObserverHUD::Remove() { |
| 547 switch (mode_) { | 75 root_window_->RemovePreTargetHandler(this); |
| 548 case FULLSCREEN: | 76 |
| 549 SetMode(REDUCED_SCALE); | 77 RootWindowController* controller = GetRootWindowController(root_window_); |
| 550 break; | 78 UnsetHudForRootWindowController(controller); |
| 551 case REDUCED_SCALE: | 79 |
| 552 SetMode(PROJECTION); | 80 widget_->CloseNow(); |
| 553 break; | |
| 554 case PROJECTION: | |
| 555 SetMode(INVISIBLE); | |
| 556 break; | |
| 557 case INVISIBLE: | |
| 558 SetMode(FULLSCREEN); | |
| 559 break; | |
| 560 } | |
| 561 } | 81 } |
| 562 | 82 |
| 563 void TouchObserverHUD::Clear() { | 83 void TouchObserverHUD::OnTouchEvent(ui::TouchEvent* /*event*/) { |
| 564 if (widget_->IsVisible()) | |
| 565 canvas_->Clear(); | |
| 566 for (int i = 0; i < kMaxTouchPoints; ++i) | |
| 567 touch_labels_[i]->SetText(string16()); | |
| 568 label_container_->SetSize(label_container_->GetPreferredSize()); | |
| 569 } | |
| 570 | |
| 571 scoped_ptr<ListValue> TouchObserverHUD::GetLogAsList() const { | |
| 572 return touch_log_->GetAsList(); | |
| 573 } | |
| 574 | |
| 575 void TouchObserverHUD::SetMode(Mode mode) { | |
| 576 if (mode_ == mode) | |
| 577 return; | |
| 578 // When going out of projection mode, hide all active touch points. | |
| 579 if (mode_ == PROJECTION) { | |
| 580 for (std::map<int, TouchPointView*>::iterator iter = points_.begin(); | |
| 581 iter != points_.end(); ++iter) | |
| 582 iter->second->Remove(); | |
| 583 points_.clear(); | |
| 584 } | |
| 585 mode_ = mode; | |
| 586 switch (mode) { | |
| 587 case FULLSCREEN: | |
| 588 label_container_->SetVisible(false); | |
| 589 canvas_->SetVisible(true); | |
| 590 canvas_->SetScale(1); | |
| 591 canvas_->SchedulePaint(); | |
| 592 widget_->Show(); | |
| 593 break; | |
| 594 case REDUCED_SCALE: | |
| 595 label_container_->SetVisible(true); | |
| 596 canvas_->SetVisible(true); | |
| 597 canvas_->SetScale(kReducedScale); | |
| 598 canvas_->SchedulePaint(); | |
| 599 widget_->Show(); | |
| 600 break; | |
| 601 case PROJECTION: | |
| 602 label_container_->SetVisible(false); | |
| 603 canvas_->SetVisible(false); | |
| 604 widget_->Show(); | |
| 605 break; | |
| 606 case INVISIBLE: | |
| 607 widget_->Hide(); | |
| 608 break; | |
| 609 } | |
| 610 } | |
| 611 | |
| 612 void TouchObserverHUD::UpdateTouchPointLabel(int index) { | |
| 613 int trace_index = touch_log_->GetTraceIndex(index); | |
| 614 const TouchTrace& trace = touch_log_->traces()[trace_index]; | |
| 615 TouchTrace::const_reverse_iterator point = trace.log().rbegin(); | |
| 616 ui::EventType touch_status = point->type; | |
| 617 float touch_radius = std::max(point->radius_x, point->radius_y); | |
| 618 while (point != trace.log().rend() && point->type == ui::ET_TOUCH_CANCELLED) | |
| 619 point++; | |
| 620 DCHECK(point != trace.log().rend()); | |
| 621 gfx::Point touch_position = point->location; | |
| 622 | |
| 623 std::string string = base::StringPrintf("%2d: %s %s (%.4f)", | |
| 624 index, | |
| 625 GetTouchEventLabel(touch_status), | |
| 626 touch_position.ToString().c_str(), | |
| 627 touch_radius); | |
| 628 touch_labels_[index]->SetText(UTF8ToUTF16(string)); | |
| 629 } | |
| 630 | |
| 631 void TouchObserverHUD::OnTouchEvent(ui::TouchEvent* event) { | |
| 632 if (event->touch_id() >= kMaxTouchPoints) | |
| 633 return; | |
| 634 | |
| 635 touch_log_->AddTouchPoint(*event); | |
| 636 canvas_->TouchPointAdded(event->touch_id()); | |
| 637 | |
| 638 if (mode_ == PROJECTION) { | |
| 639 if (event->type() == ui::ET_TOUCH_PRESSED) { | |
| 640 TouchPointView* point = new TouchPointView(widget_); | |
| 641 point->UpdateTouch(*event); | |
| 642 std::pair<std::map<int, TouchPointView*>::iterator, bool> result = | |
| 643 points_.insert(std::make_pair(event->touch_id(), point)); | |
| 644 // If a |TouchPointView| is already mapped to the touch id, remove it and | |
| 645 // replace it with the new one. | |
| 646 if (!result.second) { | |
| 647 result.first->second->Remove(); | |
| 648 result.first->second = point; | |
| 649 } | |
| 650 } else { | |
| 651 std::map<int, TouchPointView*>::iterator iter = | |
| 652 points_.find(event->touch_id()); | |
| 653 if (iter != points_.end()) { | |
| 654 iter->second->UpdateTouch(*event); | |
| 655 if (event->type() == ui::ET_TOUCH_RELEASED || | |
| 656 event->type() == ui::ET_TOUCH_CANCELLED) | |
| 657 points_.erase(iter); | |
| 658 } | |
| 659 } | |
| 660 } | |
| 661 | |
| 662 UpdateTouchPointLabel(event->touch_id()); | |
| 663 label_container_->SetSize(label_container_->GetPreferredSize()); | |
| 664 } | 84 } |
| 665 | 85 |
| 666 void TouchObserverHUD::OnWidgetDestroying(views::Widget* widget) { | 86 void TouchObserverHUD::OnWidgetDestroying(views::Widget* widget) { |
| 667 DCHECK_EQ(widget, widget_); | 87 DCHECK_EQ(widget, widget_); |
| 668 delete this; | 88 delete this; |
| 669 } | 89 } |
| 670 | 90 |
| 671 void TouchObserverHUD::OnDisplayBoundsChanged(const gfx::Display& display) { | 91 void TouchObserverHUD::OnDisplayBoundsChanged(const gfx::Display& display) { |
| 672 if (display.id() != display_id_) | 92 if (display.id() != display_id_) |
| 673 return; | 93 return; |
| 674 const gfx::Size& size = display.size(); | 94 widget_->SetSize(display.size()); |
| 675 widget_->SetSize(size); | |
| 676 canvas_->SetSize(size); | |
| 677 label_container_->SetY(size.height() / kReducedScale); | |
| 678 } | 95 } |
| 679 | 96 |
| 680 void TouchObserverHUD::OnDisplayAdded(const gfx::Display& new_display) {} | 97 void TouchObserverHUD::OnDisplayAdded(const gfx::Display& new_display) {} |
| 681 | 98 |
| 682 void TouchObserverHUD::OnDisplayRemoved(const gfx::Display& old_display) { | 99 void TouchObserverHUD::OnDisplayRemoved(const gfx::Display& old_display) { |
| 683 if (old_display.id() != display_id_) | 100 if (old_display.id() != display_id_) |
| 684 return; | 101 return; |
| 685 widget_->CloseNow(); | 102 widget_->CloseNow(); |
| 686 } | 103 } |
| 687 | 104 |
| 688 #if defined(OS_CHROMEOS) | 105 #if defined(OS_CHROMEOS) |
| 689 void TouchObserverHUD::OnDisplayModeChanged() { | 106 void TouchObserverHUD::OnDisplayModeChanged() { |
| 690 // Clear touch HUD for any change in display mode (single, dual extended, dual | 107 // Clear touch HUD for any change in display mode (single, dual extended, dual |
| 691 // mirrored, ...). | 108 // mirrored, ...). |
| 692 Clear(); | 109 Clear(); |
| 693 } | 110 } |
| 694 #endif // defined(OS_CHROMEOS) | 111 #endif // defined(OS_CHROMEOS) |
| 695 | 112 |
| 696 void TouchObserverHUD::OnDisplayConfigurationChanging() { | 113 void TouchObserverHUD::OnDisplayConfigurationChanging() { |
| 697 if (!root_window_) | 114 if (!root_window_) |
| 698 return; | 115 return; |
| 699 | 116 |
| 700 root_window_->RemovePreTargetHandler(this); | 117 root_window_->RemovePreTargetHandler(this); |
| 701 | 118 |
| 702 RootWindowController* controller = GetRootWindowController(root_window_); | 119 RootWindowController* controller = GetRootWindowController(root_window_); |
| 703 controller->set_touch_observer_hud(NULL); | 120 UnsetHudForRootWindowController(controller); |
| 704 | 121 |
| 705 views::Widget::ReparentNativeView( | 122 views::Widget::ReparentNativeView( |
| 706 widget_->GetNativeView(), | 123 widget_->GetNativeView(), |
| 707 Shell::GetContainer(root_window_, | 124 Shell::GetContainer(root_window_, |
| 708 internal::kShellWindowId_UnparentedControlContainer)); | 125 internal::kShellWindowId_UnparentedControlContainer)); |
| 709 | 126 |
| 710 root_window_ = NULL; | 127 root_window_ = NULL; |
| 711 } | 128 } |
| 712 | 129 |
| 713 void TouchObserverHUD::OnDisplayConfigurationChanged() { | 130 void TouchObserverHUD::OnDisplayConfigurationChanged() { |
| 714 if (root_window_) | 131 if (root_window_) |
| 715 return; | 132 return; |
| 716 | 133 |
| 717 root_window_ = Shell::GetInstance()->display_controller()-> | 134 root_window_ = Shell::GetInstance()->display_controller()-> |
| 718 GetRootWindowForDisplayId(display_id_); | 135 GetRootWindowForDisplayId(display_id_); |
| 719 | 136 |
| 720 views::Widget::ReparentNativeView( | 137 views::Widget::ReparentNativeView( |
| 721 widget_->GetNativeView(), | 138 widget_->GetNativeView(), |
| 722 Shell::GetContainer(root_window_, | 139 Shell::GetContainer(root_window_, |
| 723 internal::kShellWindowId_OverlayContainer)); | 140 internal::kShellWindowId_OverlayContainer)); |
| 724 | 141 |
| 725 RootWindowController* controller = GetRootWindowController(root_window_); | 142 RootWindowController* controller = GetRootWindowController(root_window_); |
| 726 controller->set_touch_observer_hud(this); | 143 SetHudForRootWindowController(controller); |
| 727 | 144 |
| 728 root_window_->AddPreTargetHandler(this); | 145 root_window_->AddPreTargetHandler(this); |
| 729 } | 146 } |
| 730 | 147 |
| 731 } // namespace internal | 148 } // namespace internal |
| 732 } // namespace ash | 149 } // namespace ash |
| OLD | NEW |