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 "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h" | 5 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h" |
| 6 | 6 |
| 7 #include <X11/Xatom.h> | 7 #include <X11/Xatom.h> |
| 8 | 8 |
| 9 #include "base/event_types.h" | 9 #include "base/event_types.h" |
| 10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
| 11 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
| 12 #include "ui/aura/window.h" | 12 #include "ui/aura/window.h" |
| 13 #include "ui/aura/window_tree_host.h" | 13 #include "ui/aura/window_tree_host.h" |
| 14 #include "ui/base/clipboard/clipboard.h" | 14 #include "ui/base/clipboard/clipboard.h" |
| 15 #include "ui/base/dragdrop/drop_target_event.h" | 15 #include "ui/base/dragdrop/drop_target_event.h" |
| 16 #include "ui/base/dragdrop/os_exchange_data.h" | 16 #include "ui/base/dragdrop/os_exchange_data.h" |
| 17 #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h" | 17 #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h" |
| 18 #include "ui/base/x/selection_utils.h" | 18 #include "ui/base/x/selection_utils.h" |
| 19 #include "ui/base/x/x11_util.h" | 19 #include "ui/base/x/x11_util.h" |
| 20 #include "ui/events/event.h" | 20 #include "ui/events/event.h" |
| 21 #include "ui/events/platform/platform_event_source.h" | 21 #include "ui/events/platform/platform_event_source.h" |
| 22 #include "ui/gfx/screen.h" | |
| 23 #include "ui/views/controls/image_view.h" | |
| 22 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h" | 24 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h" |
| 23 #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h" | 25 #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h" |
| 26 #include "ui/views/widget/widget.h" | |
| 24 #include "ui/wm/public/drag_drop_client.h" | 27 #include "ui/wm/public/drag_drop_client.h" |
| 25 #include "ui/wm/public/drag_drop_delegate.h" | 28 #include "ui/wm/public/drag_drop_delegate.h" |
| 26 | 29 |
| 27 using aura::client::DragDropDelegate; | 30 using aura::client::DragDropDelegate; |
| 28 using ui::OSExchangeData; | 31 using ui::OSExchangeData; |
| 29 | 32 |
| 30 namespace { | 33 namespace { |
| 31 | 34 |
| 35 // The minimum alpha before we declare a pixel transparent when searching in | |
| 36 // our source image. | |
| 37 const uint32 kMinAlpha = 32; | |
| 38 const unsigned char kDragWidgetOpacity = 0xc0; | |
| 39 | |
| 32 const int kMinXdndVersion = 5; | 40 const int kMinXdndVersion = 5; |
| 33 | 41 |
| 34 const int kWillAcceptDrop = 1; | 42 const int kWillAcceptDrop = 1; |
| 35 const int kWantFurtherPosEvents = 2; | 43 const int kWantFurtherPosEvents = 2; |
| 36 | 44 |
| 37 const char kXdndActionCopy[] = "XdndActionCopy"; | 45 const char kXdndActionCopy[] = "XdndActionCopy"; |
| 38 const char kXdndActionMove[] = "XdndActionMove"; | 46 const char kXdndActionMove[] = "XdndActionMove"; |
| 39 const char kXdndActionLink[] = "XdndActionLink"; | 47 const char kXdndActionLink[] = "XdndActionLink"; |
| 40 const char kXdndActionDirectSave[] = "XdndActionDirectSave"; | 48 const char kXdndActionDirectSave[] = "XdndActionDirectSave"; |
| 41 | 49 |
| (...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 383 waiting_on_status_(false), | 391 waiting_on_status_(false), |
| 384 status_received_since_enter_(false), | 392 status_received_since_enter_(false), |
| 385 source_provider_(NULL), | 393 source_provider_(NULL), |
| 386 source_current_window_(None), | 394 source_current_window_(None), |
| 387 source_state_(SOURCE_STATE_OTHER), | 395 source_state_(SOURCE_STATE_OTHER), |
| 388 drag_operation_(0), | 396 drag_operation_(0), |
| 389 negotiated_operation_(ui::DragDropTypes::DRAG_NONE), | 397 negotiated_operation_(ui::DragDropTypes::DRAG_NONE), |
| 390 grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorGrabbing)), | 398 grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorGrabbing)), |
| 391 copy_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorCopy)), | 399 copy_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorCopy)), |
| 392 move_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorMove)), | 400 move_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorMove)), |
| 401 null_drag_widget_bounds_(-100, -100, 1, 1), | |
| 393 weak_ptr_factory_(this) { | 402 weak_ptr_factory_(this) { |
| 394 DCHECK(g_live_client_map.Get().find(xwindow) == | 403 DCHECK(g_live_client_map.Get().find(xwindow) == |
| 395 g_live_client_map.Get().end()); | 404 g_live_client_map.Get().end()); |
| 396 g_live_client_map.Get().insert(std::make_pair(xwindow, this)); | 405 g_live_client_map.Get().insert(std::make_pair(xwindow, this)); |
| 397 | 406 |
| 398 // Mark that we are aware of drag and drop concepts. | 407 // Mark that we are aware of drag and drop concepts. |
| 399 unsigned long xdnd_version = kMinXdndVersion; | 408 unsigned long xdnd_version = kMinXdndVersion; |
| 400 XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndAware"), | 409 XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndAware"), |
| 401 XA_ATOM, 32, PropModeReplace, | 410 XA_ATOM, 32, PropModeReplace, |
| 402 reinterpret_cast<unsigned char*>(&xdnd_version), 1); | 411 reinterpret_cast<unsigned char*>(&xdnd_version), 1); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 497 // We were waiting on the status message so we could send the XdndDrop. | 506 // We were waiting on the status message so we could send the XdndDrop. |
| 498 if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) { | 507 if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) { |
| 499 move_loop_.EndMoveLoop(); | 508 move_loop_.EndMoveLoop(); |
| 500 return; | 509 return; |
| 501 } | 510 } |
| 502 source_state_ = SOURCE_STATE_DROPPED; | 511 source_state_ = SOURCE_STATE_DROPPED; |
| 503 SendXdndDrop(source_window); | 512 SendXdndDrop(source_window); |
| 504 return; | 513 return; |
| 505 } | 514 } |
| 506 | 515 |
| 507 switch (negotiated_operation_) { | 516 UpdateCursor(); |
| 508 case ui::DragDropTypes::DRAG_COPY: | |
| 509 move_loop_.UpdateCursor(copy_grab_cursor_); | |
| 510 break; | |
| 511 case ui::DragDropTypes::DRAG_MOVE: | |
| 512 move_loop_.UpdateCursor(move_grab_cursor_); | |
| 513 break; | |
| 514 default: | |
| 515 move_loop_.UpdateCursor(grab_cursor_); | |
| 516 break; | |
| 517 } | |
| 518 | 517 |
| 519 // Note: event.data.[2,3] specify a rectangle. It is a request by the other | 518 // Note: event.data.[2,3] specify a rectangle. It is a request by the other |
| 520 // window to not send further XdndPosition messages while the cursor is | 519 // window to not send further XdndPosition messages while the cursor is |
| 521 // within it. However, it is considered advisory and (at least according to | 520 // within it. However, it is considered advisory and (at least according to |
| 522 // the spec) the other side must handle further position messages within | 521 // the spec) the other side must handle further position messages within |
| 523 // it. GTK+ doesn't bother with this, so neither should we. | 522 // it. GTK+ doesn't bother with this, so neither should we. |
| 524 | 523 |
| 525 if (next_position_message_.get()) { | 524 if (next_position_message_.get()) { |
| 526 // We were waiting on the status message so we could send off the next | 525 // We were waiting on the status message so we could send off the next |
| 527 // position message we queued up. | 526 // position message we queued up. |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 623 source_provider_->file_contents_name().AsUTF8Unsafe()); | 622 source_provider_->file_contents_name().AsUTF8Unsafe()); |
| 624 } | 623 } |
| 625 ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions); | 624 ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions); |
| 626 | 625 |
| 627 // It is possible for the DesktopWindowTreeHostX11 to be destroyed during the | 626 // It is possible for the DesktopWindowTreeHostX11 to be destroyed during the |
| 628 // move loop, which would also destroy this drag-client. So keep track of | 627 // move loop, which would also destroy this drag-client. So keep track of |
| 629 // whether it is alive after the drag ends. | 628 // whether it is alive after the drag ends. |
| 630 base::WeakPtr<DesktopDragDropClientAuraX11> alive( | 629 base::WeakPtr<DesktopDragDropClientAuraX11> alive( |
| 631 weak_ptr_factory_.GetWeakPtr()); | 630 weak_ptr_factory_.GetWeakPtr()); |
| 632 | 631 |
| 632 SetDragImage(source_provider_->GetDragImage(), | |
| 633 source_provider_->GetDragImageOffset()); | |
| 634 CreateDragImageWindow(); | |
| 635 // Capture drag widget to continue receiving events even if the drag source | |
| 636 // gets destroyed during the drag such as when we drag an item out of a menu | |
| 637 // and the menu closes. | |
| 638 drag_widget_->GetNativeWindow()->SetCapture(); | |
| 639 | |
| 633 // Windows has a specific method, DoDragDrop(), which performs the entire | 640 // Windows has a specific method, DoDragDrop(), which performs the entire |
| 634 // drag. We have to emulate this, so we spin off a nested runloop which will | 641 // drag. We have to emulate this, so we spin off a nested runloop which will |
| 635 // track all cursor movement and reroute events to a specific handler. | 642 // track all cursor movement and reroute events to a specific handler. |
| 636 move_loop_.SetDragImage(source_provider_->GetDragImage(), | 643 move_loop_.RunMoveLoop(); |
| 637 source_provider_->GetDragImageOffset()); | |
| 638 move_loop_.RunMoveLoop(source_window, grab_cursor_); | |
| 639 | 644 |
| 640 if (alive) { | 645 if (alive) { |
| 641 move_loop_.SetDragImage(gfx::ImageSkia(), gfx::Vector2dF()); | 646 SetDragImage(gfx::ImageSkia(), gfx::Vector2dF()); |
| 642 | 647 |
| 643 source_provider_ = NULL; | 648 source_provider_ = NULL; |
| 644 g_current_drag_drop_client = NULL; | 649 g_current_drag_drop_client = NULL; |
| 645 drag_operation_ = 0; | 650 drag_operation_ = 0; |
| 646 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList")); | 651 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList")); |
| 647 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndDirectSave0)); | 652 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndDirectSave0)); |
| 648 | 653 |
| 649 return negotiated_operation_; | 654 return negotiated_operation_; |
| 650 } | 655 } |
| 651 return ui::DragDropTypes::DRAG_NONE; | 656 return ui::DragDropTypes::DRAG_NONE; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 715 // an XdndFinished message. | 720 // an XdndFinished message. |
| 716 StartEndMoveLoopTimer(); | 721 StartEndMoveLoopTimer(); |
| 717 return; | 722 return; |
| 718 } | 723 } |
| 719 } | 724 } |
| 720 | 725 |
| 721 move_loop_.EndMoveLoop(); | 726 move_loop_.EndMoveLoop(); |
| 722 } | 727 } |
| 723 | 728 |
| 724 void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { | 729 void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { |
| 730 drag_widget_.reset(); | |
| 725 if (source_current_window_ != None) { | 731 if (source_current_window_ != None) { |
| 726 SendXdndLeave(source_current_window_); | 732 SendXdndLeave(source_current_window_); |
| 727 source_current_window_ = None; | 733 source_current_window_ = None; |
| 728 } | 734 } |
| 729 target_current_context_.reset(); | 735 target_current_context_.reset(); |
| 730 repeat_mouse_move_timer_.Stop(); | 736 repeat_mouse_move_timer_.Stop(); |
| 731 end_move_loop_timer_.Stop(); | 737 end_move_loop_timer_.Stop(); |
| 732 } | 738 } |
| 733 | 739 |
| 734 void DesktopDragDropClientAuraX11::ProcessMouseMove( | 740 void DesktopDragDropClientAuraX11::ProcessMouseMove( |
| 735 const gfx::Point& screen_point, | 741 const gfx::Point& screen_point, |
| 736 unsigned long event_time) { | 742 unsigned long event_time) { |
| 737 if (source_state_ != SOURCE_STATE_OTHER) | 743 if (source_state_ != SOURCE_STATE_OTHER) |
| 738 return; | 744 return; |
| 739 | 745 |
| 746 if (drag_widget_.get()) { | |
| 747 if (drag_image_.isNull()) { | |
| 748 drag_widget_->SetBounds(null_drag_widget_bounds_); | |
| 749 } else { | |
| 750 drag_widget_->SetBounds(gfx::Rect( | |
| 751 gfx::ToFlooredPoint(screen_point - drag_offset_), | |
| 752 drag_image_.size())); | |
| 753 } | |
| 754 drag_widget_->StackAtTop(); | |
| 755 } | |
| 756 | |
| 740 // Find the current window the cursor is over. | 757 // Find the current window the cursor is over. |
| 741 ::Window mouse_window = None; | 758 ::Window mouse_window = None; |
| 742 ::Window dest_window = None; | 759 ::Window dest_window = None; |
| 743 FindWindowFor(screen_point, &mouse_window, &dest_window); | 760 FindWindowFor(screen_point, &mouse_window, &dest_window); |
| 744 | 761 |
| 745 if (source_current_window_ != dest_window) { | 762 if (source_current_window_ != dest_window) { |
| 746 if (source_current_window_ != None) | 763 if (source_current_window_ != None) |
| 747 SendXdndLeave(source_current_window_); | 764 SendXdndLeave(source_current_window_); |
| 748 | 765 |
| 749 source_current_window_ = dest_window; | 766 source_current_window_ = dest_window; |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 864 if (drag_operation_ & ui::DragDropTypes::DRAG_LINK) | 881 if (drag_operation_ & ui::DragDropTypes::DRAG_LINK) |
| 865 operations.push_back(atom_cache_.GetAtom(kXdndActionLink)); | 882 operations.push_back(atom_cache_.GetAtom(kXdndActionLink)); |
| 866 return operations; | 883 return operations; |
| 867 } | 884 } |
| 868 | 885 |
| 869 ui::SelectionFormatMap DesktopDragDropClientAuraX11::GetFormatMap() const { | 886 ui::SelectionFormatMap DesktopDragDropClientAuraX11::GetFormatMap() const { |
| 870 return source_provider_ ? source_provider_->GetFormatMap() : | 887 return source_provider_ ? source_provider_->GetFormatMap() : |
| 871 ui::SelectionFormatMap(); | 888 ui::SelectionFormatMap(); |
| 872 } | 889 } |
| 873 | 890 |
| 891 void DesktopDragDropClientAuraX11::UpdateCursor() { | |
| 892 gfx::NativeCursor cursor = grab_cursor_; | |
| 893 switch (negotiated_operation_) { | |
| 894 case ui::DragDropTypes::DRAG_COPY: | |
| 895 cursor = copy_grab_cursor_; | |
| 896 break; | |
| 897 case ui::DragDropTypes::DRAG_MOVE: | |
| 898 cursor = move_grab_cursor_; | |
| 899 break; | |
| 900 default: | |
| 901 break; | |
| 902 } | |
| 903 | |
| 904 // Update the pointer with the new cursor if a grab is active. | |
| 905 XChangeActivePointerGrab( | |
| 906 xdisplay_, | |
| 907 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, | |
| 908 cursor.platform(), | |
| 909 CurrentTime); | |
| 910 } | |
| 911 | |
| 874 void DesktopDragDropClientAuraX11::CompleteXdndPosition( | 912 void DesktopDragDropClientAuraX11::CompleteXdndPosition( |
| 875 ::Window source_window, | 913 ::Window source_window, |
| 876 const gfx::Point& screen_point) { | 914 const gfx::Point& screen_point) { |
| 877 int drag_operation = ui::DragDropTypes::DRAG_NONE; | 915 int drag_operation = ui::DragDropTypes::DRAG_NONE; |
| 878 scoped_ptr<ui::OSExchangeData> data; | 916 scoped_ptr<ui::OSExchangeData> data; |
| 879 scoped_ptr<ui::DropTargetEvent> drop_target_event; | 917 scoped_ptr<ui::DropTargetEvent> drop_target_event; |
| 880 DragDropDelegate* delegate = NULL; | 918 DragDropDelegate* delegate = NULL; |
| 881 DragTranslate(screen_point, &data, &drop_target_event, &delegate); | 919 DragTranslate(screen_point, &data, &drop_target_event, &delegate); |
| 882 if (delegate) | 920 if (delegate) |
| 883 drag_operation = delegate->OnDragUpdated(*drop_target_event); | 921 drag_operation = delegate->OnDragUpdated(*drop_target_event); |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1022 // success or failure, and when it fails, it then sends an internal | 1060 // success or failure, and when it fails, it then sends an internal |
| 1023 // GdkEvent about the failed drag. (And sending this message doesn't appear | 1061 // GdkEvent about the failed drag. (And sending this message doesn't appear |
| 1024 // to go through normal xlib machinery, but instead passes through the low | 1062 // to go through normal xlib machinery, but instead passes through the low |
| 1025 // level xProto (the x11 wire format) that I don't understand. | 1063 // level xProto (the x11 wire format) that I don't understand. |
| 1026 // | 1064 // |
| 1027 // I'm unsure if I have to jump through those hoops, or if XSendEvent is | 1065 // I'm unsure if I have to jump through those hoops, or if XSendEvent is |
| 1028 // sufficient. | 1066 // sufficient. |
| 1029 XSendEvent(xdisplay_, xid, False, 0, xev); | 1067 XSendEvent(xdisplay_, xid, False, 0, xev); |
| 1030 } | 1068 } |
| 1031 | 1069 |
| 1070 void DesktopDragDropClientAuraX11::SetDragImage(const gfx::ImageSkia& image, | |
| 1071 gfx::Vector2dF offset) { | |
| 1072 drag_image_ = image; | |
| 1073 drag_offset_ = offset; | |
| 1074 // Reset the Y offset, so that the drag-image is always just below the cursor, | |
| 1075 // so that it is possible to see where the cursor is going. | |
| 1076 drag_offset_.set_y(0.f); | |
| 1077 } | |
| 1078 | |
| 1079 void DesktopDragDropClientAuraX11::CreateDragImageWindow() { | |
| 1080 Widget* widget = new Widget; | |
| 1081 Widget::InitParams params(Widget::InitParams::TYPE_DRAG); | |
| 1082 params.opacity = Widget::InitParams::OPAQUE_WINDOW; | |
|
sadrul
2014/05/23 14:39:53
Should this be TRANSLUCENT_WINDOW?
varkha
2014/05/23 15:38:36
Done.
| |
| 1083 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
| 1084 params.accept_events = false; | |
| 1085 | |
| 1086 if (drag_image_.isNull()) { | |
| 1087 params.bounds = null_drag_widget_bounds_; | |
| 1088 } else { | |
| 1089 params.bounds = gfx::Rect( | |
| 1090 gfx::ToFlooredPoint( | |
| 1091 gfx::Screen::GetNativeScreen()->GetCursorScreenPoint() - | |
| 1092 drag_offset_), | |
| 1093 drag_image_.size()); | |
| 1094 } | |
| 1095 widget->set_focus_on_creation(false); | |
| 1096 widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE); | |
| 1097 widget->Init(params); | |
| 1098 widget->SetOpacity(kDragWidgetOpacity); | |
| 1099 widget->GetNativeWindow()->SetName("DragWindow"); | |
| 1100 | |
| 1101 if (!drag_image_.isNull()) { | |
| 1102 ImageView* image = new ImageView(); | |
| 1103 image->SetImage(drag_image_); | |
| 1104 image->SetBounds(0, 0, drag_image_.width(), drag_image_.height()); | |
| 1105 widget->SetContentsView(image); | |
| 1106 } | |
| 1107 | |
| 1108 widget->Show(); | |
| 1109 widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false); | |
| 1110 drag_widget_.reset(widget); | |
| 1111 } | |
| 1112 | |
| 1032 } // namespace views | 1113 } // namespace views |
| OLD | NEW |