| 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 bool CheckIfIconValid(const gfx::ImageSkia& drag_image) { |
| 41 // Because we need a GL context per window, we do a quick check so that we |
| 42 // don't make another context if the window would just be displaying a mostly |
| 43 // transparent image. |
| 44 const SkBitmap* in_bitmap = drag_image.bitmap(); |
| 45 SkAutoLockPixels in_lock(*in_bitmap); |
| 46 for (int y = 0; y < in_bitmap->height(); ++y) { |
| 47 uint32* in_row = in_bitmap->getAddr32(0, y); |
| 48 |
| 49 for (int x = 0; x < in_bitmap->width(); ++x) { |
| 50 if (SkColorGetA(in_row[x]) > kMinAlpha) |
| 51 return true; |
| 52 } |
| 53 } |
| 54 |
| 55 return false; |
| 56 } |
| 57 |
| 32 const int kMinXdndVersion = 5; | 58 const int kMinXdndVersion = 5; |
| 33 | 59 |
| 34 const int kWillAcceptDrop = 1; | 60 const int kWillAcceptDrop = 1; |
| 35 const int kWantFurtherPosEvents = 2; | 61 const int kWantFurtherPosEvents = 2; |
| 36 | 62 |
| 37 const char kXdndActionCopy[] = "XdndActionCopy"; | 63 const char kXdndActionCopy[] = "XdndActionCopy"; |
| 38 const char kXdndActionMove[] = "XdndActionMove"; | 64 const char kXdndActionMove[] = "XdndActionMove"; |
| 39 const char kXdndActionLink[] = "XdndActionLink"; | 65 const char kXdndActionLink[] = "XdndActionLink"; |
| 40 const char kXdndActionDirectSave[] = "XdndActionDirectSave"; | 66 const char kXdndActionDirectSave[] = "XdndActionDirectSave"; |
| 41 | 67 |
| (...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 // We were waiting on the status message so we could send the XdndDrop. | 516 // We were waiting on the status message so we could send the XdndDrop. |
| 491 if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) { | 517 if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) { |
| 492 move_loop_.EndMoveLoop(); | 518 move_loop_.EndMoveLoop(); |
| 493 return; | 519 return; |
| 494 } | 520 } |
| 495 source_state_ = SOURCE_STATE_DROPPED; | 521 source_state_ = SOURCE_STATE_DROPPED; |
| 496 SendXdndDrop(source_window); | 522 SendXdndDrop(source_window); |
| 497 return; | 523 return; |
| 498 } | 524 } |
| 499 | 525 |
| 500 switch (negotiated_operation_) { | 526 UpdateCursor(); |
| 501 case ui::DragDropTypes::DRAG_COPY: | |
| 502 move_loop_.UpdateCursor(copy_grab_cursor_); | |
| 503 break; | |
| 504 case ui::DragDropTypes::DRAG_MOVE: | |
| 505 move_loop_.UpdateCursor(move_grab_cursor_); | |
| 506 break; | |
| 507 default: | |
| 508 move_loop_.UpdateCursor(grab_cursor_); | |
| 509 break; | |
| 510 } | |
| 511 | 527 |
| 512 // Note: event.data.[2,3] specify a rectangle. It is a request by the other | 528 // Note: event.data.[2,3] specify a rectangle. It is a request by the other |
| 513 // window to not send further XdndPosition messages while the cursor is | 529 // window to not send further XdndPosition messages while the cursor is |
| 514 // within it. However, it is considered advisory and (at least according to | 530 // within it. However, it is considered advisory and (at least according to |
| 515 // the spec) the other side must handle further position messages within | 531 // the spec) the other side must handle further position messages within |
| 516 // it. GTK+ doesn't bother with this, so neither should we. | 532 // it. GTK+ doesn't bother with this, so neither should we. |
| 517 | 533 |
| 518 if (next_position_message_.get()) { | 534 if (next_position_message_.get()) { |
| 519 // We were waiting on the status message so we could send off the next | 535 // We were waiting on the status message so we could send off the next |
| 520 // position message we queued up. | 536 // position message we queued up. |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 | 634 |
| 619 // It is possible for the DesktopWindowTreeHostX11 to be destroyed during the | 635 // It is possible for the DesktopWindowTreeHostX11 to be destroyed during the |
| 620 // move loop, which would also destroy this drag-client. So keep track of | 636 // move loop, which would also destroy this drag-client. So keep track of |
| 621 // whether it is alive after the drag ends. | 637 // whether it is alive after the drag ends. |
| 622 base::WeakPtr<DesktopDragDropClientAuraX11> alive( | 638 base::WeakPtr<DesktopDragDropClientAuraX11> alive( |
| 623 weak_ptr_factory_.GetWeakPtr()); | 639 weak_ptr_factory_.GetWeakPtr()); |
| 624 | 640 |
| 625 // Windows has a specific method, DoDragDrop(), which performs the entire | 641 // Windows has a specific method, DoDragDrop(), which performs the entire |
| 626 // drag. We have to emulate this, so we spin off a nested runloop which will | 642 // drag. We have to emulate this, so we spin off a nested runloop which will |
| 627 // track all cursor movement and reroute events to a specific handler. | 643 // track all cursor movement and reroute events to a specific handler. |
| 628 move_loop_.SetDragImage(source_provider_->GetDragImage(), | 644 SetDragImage(source_provider_->GetDragImage(), |
| 629 source_provider_->GetDragImageOffset()); | 645 source_provider_->GetDragImageOffset()); |
| 630 move_loop_.RunMoveLoop(source_window, grab_cursor_); | 646 if (!drag_image_.isNull() && CheckIfIconValid(drag_image_)) |
| 647 CreateDragImageWindow(); |
| 648 move_loop_.RunMoveLoop(grab_cursor_); |
| 631 | 649 |
| 632 if (alive) { | 650 if (alive) { |
| 633 move_loop_.SetDragImage(gfx::ImageSkia(), gfx::Vector2dF()); | 651 SetDragImage(gfx::ImageSkia(), gfx::Vector2dF()); |
| 634 | 652 |
| 635 source_provider_ = NULL; | 653 source_provider_ = NULL; |
| 636 g_current_drag_drop_client = NULL; | 654 g_current_drag_drop_client = NULL; |
| 637 drag_operation_ = 0; | 655 drag_operation_ = 0; |
| 638 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList")); | 656 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList")); |
| 639 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndDirectSave0)); | 657 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndDirectSave0)); |
| 640 | 658 |
| 641 return negotiated_operation_; | 659 return negotiated_operation_; |
| 642 } | 660 } |
| 643 return ui::DragDropTypes::DRAG_NONE; | 661 return ui::DragDropTypes::DRAG_NONE; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 665 DCHECK_EQ(target_window_, window); | 683 DCHECK_EQ(target_window_, window); |
| 666 target_window_ = NULL; | 684 target_window_ = NULL; |
| 667 } | 685 } |
| 668 | 686 |
| 669 void DesktopDragDropClientAuraX11::OnMouseMovement(XMotionEvent* event) { | 687 void DesktopDragDropClientAuraX11::OnMouseMovement(XMotionEvent* event) { |
| 670 gfx::Point screen_point(event->x_root, event->y_root); | 688 gfx::Point screen_point(event->x_root, event->y_root); |
| 671 | 689 |
| 672 if (source_state_ != SOURCE_STATE_OTHER) | 690 if (source_state_ != SOURCE_STATE_OTHER) |
| 673 return; | 691 return; |
| 674 | 692 |
| 693 if (drag_widget_.get()) { |
| 694 gfx::Point location = gfx::ToFlooredPoint(screen_point - drag_offset_); |
| 695 drag_widget_->SetBounds(gfx::Rect(location, drag_image_.size())); |
| 696 drag_widget_->StackAtTop(); |
| 697 } |
| 698 |
| 675 // Find the current window the cursor is over. | 699 // Find the current window the cursor is over. |
| 676 ::Window mouse_window = None; | 700 ::Window mouse_window = None; |
| 677 ::Window dest_window = None; | 701 ::Window dest_window = None; |
| 678 FindWindowFor(screen_point, &mouse_window, &dest_window); | 702 FindWindowFor(screen_point, &mouse_window, &dest_window); |
| 679 | 703 |
| 680 if (source_current_window_ != dest_window) { | 704 if (source_current_window_ != dest_window) { |
| 681 if (source_current_window_ != None) | 705 if (source_current_window_ != None) |
| 682 SendXdndLeave(source_current_window_); | 706 SendXdndLeave(source_current_window_); |
| 683 | 707 |
| 684 source_current_window_ = dest_window; | 708 source_current_window_ = dest_window; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 729 // an XdndFinished message. | 753 // an XdndFinished message. |
| 730 StartEndMoveLoopTimer(); | 754 StartEndMoveLoopTimer(); |
| 731 return; | 755 return; |
| 732 } | 756 } |
| 733 } | 757 } |
| 734 | 758 |
| 735 move_loop_.EndMoveLoop(); | 759 move_loop_.EndMoveLoop(); |
| 736 } | 760 } |
| 737 | 761 |
| 738 void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { | 762 void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { |
| 763 drag_widget_.reset(); |
| 739 if (source_current_window_ != None) { | 764 if (source_current_window_ != None) { |
| 740 SendXdndLeave(source_current_window_); | 765 SendXdndLeave(source_current_window_); |
| 741 source_current_window_ = None; | 766 source_current_window_ = None; |
| 742 } | 767 } |
| 743 target_current_context_.reset(); | 768 target_current_context_.reset(); |
| 744 end_move_loop_timer_.Stop(); | 769 end_move_loop_timer_.Stop(); |
| 745 } | 770 } |
| 746 | 771 |
| 747 void DesktopDragDropClientAuraX11::StartEndMoveLoopTimer() { | 772 void DesktopDragDropClientAuraX11::StartEndMoveLoopTimer() { |
| 748 end_move_loop_timer_.Start(FROM_HERE, | 773 end_move_loop_timer_.Start(FROM_HERE, |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 842 if (drag_operation_ & ui::DragDropTypes::DRAG_LINK) | 867 if (drag_operation_ & ui::DragDropTypes::DRAG_LINK) |
| 843 operations.push_back(atom_cache_.GetAtom(kXdndActionLink)); | 868 operations.push_back(atom_cache_.GetAtom(kXdndActionLink)); |
| 844 return operations; | 869 return operations; |
| 845 } | 870 } |
| 846 | 871 |
| 847 ui::SelectionFormatMap DesktopDragDropClientAuraX11::GetFormatMap() const { | 872 ui::SelectionFormatMap DesktopDragDropClientAuraX11::GetFormatMap() const { |
| 848 return source_provider_ ? source_provider_->GetFormatMap() : | 873 return source_provider_ ? source_provider_->GetFormatMap() : |
| 849 ui::SelectionFormatMap(); | 874 ui::SelectionFormatMap(); |
| 850 } | 875 } |
| 851 | 876 |
| 877 void DesktopDragDropClientAuraX11::UpdateCursor() { |
| 878 gfx::NativeCursor cursor = grab_cursor_; |
| 879 switch (negotiated_operation_) { |
| 880 case ui::DragDropTypes::DRAG_COPY: |
| 881 cursor = copy_grab_cursor_; |
| 882 break; |
| 883 case ui::DragDropTypes::DRAG_MOVE: |
| 884 cursor = move_grab_cursor_; |
| 885 break; |
| 886 default: |
| 887 break; |
| 888 } |
| 889 |
| 890 // Update the pointer with the updated cursor if a grab is active. |
| 891 XChangeActivePointerGrab( |
| 892 xdisplay_, |
| 893 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, |
| 894 cursor.platform(), |
| 895 CurrentTime); |
| 896 } |
| 897 |
| 852 void DesktopDragDropClientAuraX11::CompleteXdndPosition( | 898 void DesktopDragDropClientAuraX11::CompleteXdndPosition( |
| 853 ::Window source_window, | 899 ::Window source_window, |
| 854 const gfx::Point& screen_point) { | 900 const gfx::Point& screen_point) { |
| 855 int drag_operation = ui::DragDropTypes::DRAG_NONE; | 901 int drag_operation = ui::DragDropTypes::DRAG_NONE; |
| 856 scoped_ptr<ui::OSExchangeData> data; | 902 scoped_ptr<ui::OSExchangeData> data; |
| 857 scoped_ptr<ui::DropTargetEvent> drop_target_event; | 903 scoped_ptr<ui::DropTargetEvent> drop_target_event; |
| 858 DragDropDelegate* delegate = NULL; | 904 DragDropDelegate* delegate = NULL; |
| 859 DragTranslate(screen_point, &data, &drop_target_event, &delegate); | 905 DragTranslate(screen_point, &data, &drop_target_event, &delegate); |
| 860 if (delegate) | 906 if (delegate) |
| 861 drag_operation = delegate->OnDragUpdated(*drop_target_event); | 907 drag_operation = delegate->OnDragUpdated(*drop_target_event); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 989 // success or failure, and when it fails, it then sends an internal | 1035 // success or failure, and when it fails, it then sends an internal |
| 990 // GdkEvent about the failed drag. (And sending this message doesn't appear | 1036 // GdkEvent about the failed drag. (And sending this message doesn't appear |
| 991 // to go through normal xlib machinery, but instead passes through the low | 1037 // to go through normal xlib machinery, but instead passes through the low |
| 992 // level xProto (the x11 wire format) that I don't understand. | 1038 // level xProto (the x11 wire format) that I don't understand. |
| 993 // | 1039 // |
| 994 // I'm unsure if I have to jump through those hoops, or if XSendEvent is | 1040 // I'm unsure if I have to jump through those hoops, or if XSendEvent is |
| 995 // sufficient. | 1041 // sufficient. |
| 996 XSendEvent(xdisplay_, xid, False, 0, xev); | 1042 XSendEvent(xdisplay_, xid, False, 0, xev); |
| 997 } | 1043 } |
| 998 | 1044 |
| 1045 void DesktopDragDropClientAuraX11::SetDragImage(const gfx::ImageSkia& image, |
| 1046 gfx::Vector2dF offset) { |
| 1047 drag_image_ = image; |
| 1048 drag_offset_ = offset; |
| 1049 // Reset the Y offset, so that the drag-image is always just below the cursor, |
| 1050 // so that it is possible to see where the cursor is going. |
| 1051 drag_offset_.set_y(0.f); |
| 1052 } |
| 1053 |
| 1054 void DesktopDragDropClientAuraX11::CreateDragImageWindow() { |
| 1055 Widget* widget = new Widget; |
| 1056 Widget::InitParams params(Widget::InitParams::TYPE_DRAG); |
| 1057 params.opacity = Widget::InitParams::OPAQUE_WINDOW; |
| 1058 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 1059 params.accept_events = false; |
| 1060 |
| 1061 gfx::Point location = gfx::ToFlooredPoint( |
| 1062 gfx::Screen::GetNativeScreen()->GetCursorScreenPoint() - drag_offset_); |
| 1063 params.bounds = gfx::Rect(location, drag_image_.size()); |
| 1064 widget->set_focus_on_creation(false); |
| 1065 widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE); |
| 1066 widget->Init(params); |
| 1067 widget->SetOpacity(kDragWidgetOpacity); |
| 1068 widget->GetNativeWindow()->SetName("DragWindow"); |
| 1069 |
| 1070 ImageView* image = new ImageView(); |
| 1071 image->SetImage(drag_image_); |
| 1072 image->SetBounds(0, 0, drag_image_.width(), drag_image_.height()); |
| 1073 widget->SetContentsView(image); |
| 1074 widget->Show(); |
| 1075 widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false); |
| 1076 widget->GetNativeWindow()->SetCapture(); |
| 1077 drag_widget_.reset(widget); |
| 1078 } |
| 1079 |
| 999 } // namespace views | 1080 } // namespace views |
| OLD | NEW |