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 | |
40 // Drag widget is positioned off screen when drag image is not set or is | |
41 // completely transparent. | |
42 const gfx::Size kNullDragWidgetSize = gfx::Size(1, 1); | |
43 const gfx::Point kNullDragWidgetLocation = gfx::Point(-100, -100); | |
pkotwicz
2014/05/12 16:04:29
I do not know if there is much precedent for non p
varkha
2014/05/20 17:13:35
Good catch. https://engdoc.corp.google.com/eng/doc
| |
44 | |
45 bool CheckIfIconValid(const gfx::ImageSkia& drag_image) { | |
pkotwicz
2014/05/12 16:04:29
Is CheckIfIconValid() still needed in a world wher
varkha
2014/05/20 17:13:35
Done.
| |
46 // Because we need a GL context per window, we do a quick check so that we | |
47 // don't make another context if the window would just be displaying a mostly | |
48 // transparent image. | |
49 const SkBitmap* in_bitmap = drag_image.bitmap(); | |
50 SkAutoLockPixels in_lock(*in_bitmap); | |
51 for (int y = 0; y < in_bitmap->height(); ++y) { | |
52 uint32* in_row = in_bitmap->getAddr32(0, y); | |
53 | |
54 for (int x = 0; x < in_bitmap->width(); ++x) { | |
55 if (SkColorGetA(in_row[x]) > kMinAlpha) | |
56 return true; | |
57 } | |
58 } | |
59 | |
60 return false; | |
61 } | |
62 | |
32 const int kMinXdndVersion = 5; | 63 const int kMinXdndVersion = 5; |
33 | 64 |
34 const int kWillAcceptDrop = 1; | 65 const int kWillAcceptDrop = 1; |
35 const int kWantFurtherPosEvents = 2; | 66 const int kWantFurtherPosEvents = 2; |
36 | 67 |
37 const char kXdndActionCopy[] = "XdndActionCopy"; | 68 const char kXdndActionCopy[] = "XdndActionCopy"; |
38 const char kXdndActionMove[] = "XdndActionMove"; | 69 const char kXdndActionMove[] = "XdndActionMove"; |
39 const char kXdndActionLink[] = "XdndActionLink"; | 70 const char kXdndActionLink[] = "XdndActionLink"; |
40 const char kXdndActionDirectSave[] = "XdndActionDirectSave"; | 71 const char kXdndActionDirectSave[] = "XdndActionDirectSave"; |
41 | 72 |
(...skipping 455 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. | 528 // We were waiting on the status message so we could send the XdndDrop. |
498 if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) { | 529 if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) { |
499 move_loop_.EndMoveLoop(); | 530 move_loop_.EndMoveLoop(); |
500 return; | 531 return; |
501 } | 532 } |
502 source_state_ = SOURCE_STATE_DROPPED; | 533 source_state_ = SOURCE_STATE_DROPPED; |
503 SendXdndDrop(source_window); | 534 SendXdndDrop(source_window); |
504 return; | 535 return; |
505 } | 536 } |
506 | 537 |
507 switch (negotiated_operation_) { | 538 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 | 539 |
519 // Note: event.data.[2,3] specify a rectangle. It is a request by the other | 540 // 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 | 541 // window to not send further XdndPosition messages while the cursor is |
521 // within it. However, it is considered advisory and (at least according to | 542 // within it. However, it is considered advisory and (at least according to |
522 // the spec) the other side must handle further position messages within | 543 // the spec) the other side must handle further position messages within |
523 // it. GTK+ doesn't bother with this, so neither should we. | 544 // it. GTK+ doesn't bother with this, so neither should we. |
524 | 545 |
525 if (next_position_message_.get()) { | 546 if (next_position_message_.get()) { |
526 // We were waiting on the status message so we could send off the next | 547 // We were waiting on the status message so we could send off the next |
527 // position message we queued up. | 548 // 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()); | 644 source_provider_->file_contents_name().AsUTF8Unsafe()); |
624 } | 645 } |
625 ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions); | 646 ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions); |
626 | 647 |
627 // It is possible for the DesktopWindowTreeHostX11 to be destroyed during the | 648 // 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 | 649 // move loop, which would also destroy this drag-client. So keep track of |
629 // whether it is alive after the drag ends. | 650 // whether it is alive after the drag ends. |
630 base::WeakPtr<DesktopDragDropClientAuraX11> alive( | 651 base::WeakPtr<DesktopDragDropClientAuraX11> alive( |
631 weak_ptr_factory_.GetWeakPtr()); | 652 weak_ptr_factory_.GetWeakPtr()); |
632 | 653 |
654 SetDragImage(source_provider_->GetDragImage(), | |
655 source_provider_->GetDragImageOffset()); | |
656 CreateDragImageWindow(); | |
633 // Windows has a specific method, DoDragDrop(), which performs the entire | 657 // 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 | 658 // 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. | 659 // track all cursor movement and reroute events to a specific handler. |
636 move_loop_.SetDragImage(source_provider_->GetDragImage(), | 660 move_loop_.RunMoveLoop(); |
637 source_provider_->GetDragImageOffset()); | |
638 move_loop_.RunMoveLoop(source_window, grab_cursor_); | |
639 | 661 |
640 if (alive) { | 662 if (alive) { |
641 move_loop_.SetDragImage(gfx::ImageSkia(), gfx::Vector2dF()); | 663 SetDragImage(gfx::ImageSkia(), gfx::Vector2dF()); |
642 | 664 |
643 source_provider_ = NULL; | 665 source_provider_ = NULL; |
644 g_current_drag_drop_client = NULL; | 666 g_current_drag_drop_client = NULL; |
645 drag_operation_ = 0; | 667 drag_operation_ = 0; |
646 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList")); | 668 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList")); |
647 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndDirectSave0)); | 669 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndDirectSave0)); |
648 | 670 |
649 return negotiated_operation_; | 671 return negotiated_operation_; |
650 } | 672 } |
651 return ui::DragDropTypes::DRAG_NONE; | 673 return ui::DragDropTypes::DRAG_NONE; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
715 // an XdndFinished message. | 737 // an XdndFinished message. |
716 StartEndMoveLoopTimer(); | 738 StartEndMoveLoopTimer(); |
717 return; | 739 return; |
718 } | 740 } |
719 } | 741 } |
720 | 742 |
721 move_loop_.EndMoveLoop(); | 743 move_loop_.EndMoveLoop(); |
722 } | 744 } |
723 | 745 |
724 void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { | 746 void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { |
747 drag_widget_.reset(); | |
725 if (source_current_window_ != None) { | 748 if (source_current_window_ != None) { |
726 SendXdndLeave(source_current_window_); | 749 SendXdndLeave(source_current_window_); |
727 source_current_window_ = None; | 750 source_current_window_ = None; |
728 } | 751 } |
729 target_current_context_.reset(); | 752 target_current_context_.reset(); |
730 repeat_mouse_move_timer_.Stop(); | 753 repeat_mouse_move_timer_.Stop(); |
731 end_move_loop_timer_.Stop(); | 754 end_move_loop_timer_.Stop(); |
732 } | 755 } |
733 | 756 |
734 void DesktopDragDropClientAuraX11::ProcessMouseMove( | 757 void DesktopDragDropClientAuraX11::ProcessMouseMove( |
735 const gfx::Point& screen_point, | 758 const gfx::Point& screen_point, |
736 unsigned long event_time) { | 759 unsigned long event_time) { |
737 if (source_state_ != SOURCE_STATE_OTHER) | 760 if (source_state_ != SOURCE_STATE_OTHER) |
738 return; | 761 return; |
739 | 762 |
763 if (drag_widget_.get()) { | |
pkotwicz
2014/05/12 16:04:29
If we intentionally moved |drag_widget_| offscreen
varkha
2014/05/20 17:13:35
I am using drag_image_.isNull() for that (and rese
| |
764 gfx::Point location = drag_image_.isNull() ? | |
765 kNullDragWidgetLocation : | |
766 gfx::ToFlooredPoint(screen_point - drag_offset_); | |
767 drag_widget_->SetBounds(gfx::Rect( | |
768 location, | |
769 drag_image_.isNull() ? kNullDragWidgetSize : drag_image_.size())); | |
770 drag_widget_->StackAtTop(); | |
771 } | |
772 | |
740 // Find the current window the cursor is over. | 773 // Find the current window the cursor is over. |
741 ::Window mouse_window = None; | 774 ::Window mouse_window = None; |
742 ::Window dest_window = None; | 775 ::Window dest_window = None; |
743 FindWindowFor(screen_point, &mouse_window, &dest_window); | 776 FindWindowFor(screen_point, &mouse_window, &dest_window); |
744 | 777 |
745 if (source_current_window_ != dest_window) { | 778 if (source_current_window_ != dest_window) { |
746 if (source_current_window_ != None) | 779 if (source_current_window_ != None) |
747 SendXdndLeave(source_current_window_); | 780 SendXdndLeave(source_current_window_); |
748 | 781 |
749 source_current_window_ = dest_window; | 782 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) | 897 if (drag_operation_ & ui::DragDropTypes::DRAG_LINK) |
865 operations.push_back(atom_cache_.GetAtom(kXdndActionLink)); | 898 operations.push_back(atom_cache_.GetAtom(kXdndActionLink)); |
866 return operations; | 899 return operations; |
867 } | 900 } |
868 | 901 |
869 ui::SelectionFormatMap DesktopDragDropClientAuraX11::GetFormatMap() const { | 902 ui::SelectionFormatMap DesktopDragDropClientAuraX11::GetFormatMap() const { |
870 return source_provider_ ? source_provider_->GetFormatMap() : | 903 return source_provider_ ? source_provider_->GetFormatMap() : |
871 ui::SelectionFormatMap(); | 904 ui::SelectionFormatMap(); |
872 } | 905 } |
873 | 906 |
907 void DesktopDragDropClientAuraX11::UpdateCursor() { | |
908 gfx::NativeCursor cursor = grab_cursor_; | |
909 switch (negotiated_operation_) { | |
910 case ui::DragDropTypes::DRAG_COPY: | |
911 cursor = copy_grab_cursor_; | |
912 break; | |
913 case ui::DragDropTypes::DRAG_MOVE: | |
914 cursor = move_grab_cursor_; | |
915 break; | |
916 default: | |
917 break; | |
918 } | |
919 | |
920 // Update the pointer with the new cursor if a grab is active. | |
921 XChangeActivePointerGrab( | |
922 xdisplay_, | |
923 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, | |
924 cursor.platform(), | |
925 CurrentTime); | |
926 } | |
927 | |
874 void DesktopDragDropClientAuraX11::CompleteXdndPosition( | 928 void DesktopDragDropClientAuraX11::CompleteXdndPosition( |
875 ::Window source_window, | 929 ::Window source_window, |
876 const gfx::Point& screen_point) { | 930 const gfx::Point& screen_point) { |
877 int drag_operation = ui::DragDropTypes::DRAG_NONE; | 931 int drag_operation = ui::DragDropTypes::DRAG_NONE; |
878 scoped_ptr<ui::OSExchangeData> data; | 932 scoped_ptr<ui::OSExchangeData> data; |
879 scoped_ptr<ui::DropTargetEvent> drop_target_event; | 933 scoped_ptr<ui::DropTargetEvent> drop_target_event; |
880 DragDropDelegate* delegate = NULL; | 934 DragDropDelegate* delegate = NULL; |
881 DragTranslate(screen_point, &data, &drop_target_event, &delegate); | 935 DragTranslate(screen_point, &data, &drop_target_event, &delegate); |
882 if (delegate) | 936 if (delegate) |
883 drag_operation = delegate->OnDragUpdated(*drop_target_event); | 937 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 | 1076 // 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 | 1077 // 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 | 1078 // to go through normal xlib machinery, but instead passes through the low |
1025 // level xProto (the x11 wire format) that I don't understand. | 1079 // level xProto (the x11 wire format) that I don't understand. |
1026 // | 1080 // |
1027 // I'm unsure if I have to jump through those hoops, or if XSendEvent is | 1081 // I'm unsure if I have to jump through those hoops, or if XSendEvent is |
1028 // sufficient. | 1082 // sufficient. |
1029 XSendEvent(xdisplay_, xid, False, 0, xev); | 1083 XSendEvent(xdisplay_, xid, False, 0, xev); |
1030 } | 1084 } |
1031 | 1085 |
1086 void DesktopDragDropClientAuraX11::SetDragImage(const gfx::ImageSkia& image, | |
1087 gfx::Vector2dF offset) { | |
1088 /*if (drag_image_.isNull() || !CheckIfIconValid(drag_image_))*/ { | |
pkotwicz
2014/05/12 16:04:29
Remove the if block entirely. It is not needed.
varkha
2014/05/20 17:13:35
Done.
| |
1089 drag_image_ = gfx::ImageSkia(); | |
1090 drag_offset_ = gfx::Vector2dF(); | |
1091 return; | |
1092 } | |
1093 drag_image_ = image; | |
1094 drag_offset_ = offset; | |
1095 // Reset the Y offset, so that the drag-image is always just below the cursor, | |
1096 // so that it is possible to see where the cursor is going. | |
1097 drag_offset_.set_y(0.f); | |
1098 } | |
1099 | |
1100 void DesktopDragDropClientAuraX11::CreateDragImageWindow() { | |
1101 Widget* widget = new Widget; | |
1102 Widget::InitParams params(Widget::InitParams::TYPE_DRAG); | |
1103 params.opacity = Widget::InitParams::OPAQUE_WINDOW; | |
1104 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
1105 params.accept_events = false; | |
1106 | |
1107 gfx::Point location = drag_image_.isNull() ? | |
pkotwicz
2014/05/12 16:04:29
I will defer to sadrul@/erg@ as to whether they li
varkha
2014/05/20 17:13:35
Right. Keeping the drag widget offscreen matches t
| |
1108 kNullDragWidgetLocation : | |
1109 gfx::ToFlooredPoint( | |
1110 gfx::Screen::GetNativeScreen()->GetCursorScreenPoint() - | |
1111 drag_offset_); | |
1112 params.bounds = gfx::Rect( | |
1113 location, | |
1114 drag_image_.isNull() ? kNullDragWidgetSize : drag_image_.size()); | |
1115 widget->set_focus_on_creation(false); | |
1116 widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE); | |
1117 widget->Init(params); | |
1118 widget->SetOpacity(kDragWidgetOpacity); | |
1119 widget->GetNativeWindow()->SetName("DragWindow"); | |
1120 | |
1121 if (!drag_image_.isNull()) { | |
1122 ImageView* image = new ImageView(); | |
1123 image->SetImage(drag_image_); | |
1124 image->SetBounds(0, 0, drag_image_.width(), drag_image_.height()); | |
1125 widget->SetContentsView(image); | |
1126 } | |
1127 | |
1128 widget->Show(); | |
1129 widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false); | |
pkotwicz
2014/05/12 16:04:29
We should have a comment as to why we set capture
varkha
2014/05/20 17:13:35
Done.
| |
1130 widget->GetNativeWindow()->SetCapture(); | |
1131 drag_widget_.reset(widget); | |
1132 } | |
1133 | |
1032 } // namespace views | 1134 } // namespace views |
OLD | NEW |