Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Side by Side Diff: ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc

Issue 262893002: Removes grab input window and extra grab and ungrab in X11WholeScreenMoveLoop Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removes grab input window and extra grab and ungrab in X11WholeScreenMoveLoop (order in TabDragCont… Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 81
74 // The time to wait since sending the last XdndPosition message before 82 // The time to wait since sending the last XdndPosition message before
75 // reprocessing the most recent mouse move event in case that the window 83 // reprocessing the most recent mouse move event in case that the window
76 // stacking order has changed and |source_current_window_| needs to be updated. 84 // stacking order has changed and |source_current_window_| needs to be updated.
77 const int kRepeatMouseMoveTimeoutMs = 350; 85 const int kRepeatMouseMoveTimeoutMs = 350;
78 86
79 static base::LazyInstance< 87 static base::LazyInstance<
80 std::map< ::Window, views::DesktopDragDropClientAuraX11*> >::Leaky 88 std::map< ::Window, views::DesktopDragDropClientAuraX11*> >::Leaky
81 g_live_client_map = LAZY_INSTANCE_INITIALIZER; 89 g_live_client_map = LAZY_INSTANCE_INITIALIZER;
82 90
91 // Checks to see if |drag_image| is an image that has any visible regions
92 // (defined as having a pixel with alpha > 32). If so, returns true.
93 bool CheckIfIconValid(const gfx::ImageSkia& drag_image) {
94 // Because we need a GL context per window, we do a quick check if the window
95 // would just be displaying a mostly transparent image.
96 const SkBitmap* in_bitmap = drag_image.bitmap();
97 SkAutoLockPixels in_lock(*in_bitmap);
98 for (int y = 0; y < in_bitmap->height(); ++y) {
99 uint32* in_row = in_bitmap->getAddr32(0, y);
100
101 for (int x = 0; x < in_bitmap->width(); ++x) {
102 if (SkColorGetA(in_row[x]) > kMinAlpha)
103 return true;
104 }
105 }
106
107 return false;
108 }
109
83 } // namespace 110 } // namespace
84 111
85 namespace views { 112 namespace views {
86 113
87 DesktopDragDropClientAuraX11* 114 DesktopDragDropClientAuraX11*
88 DesktopDragDropClientAuraX11::g_current_drag_drop_client = NULL; 115 DesktopDragDropClientAuraX11::g_current_drag_drop_client = NULL;
89 116
90 class DesktopDragDropClientAuraX11::X11DragContext 117 class DesktopDragDropClientAuraX11::X11DragContext
91 : public ui::PlatformEventDispatcher { 118 : public ui::PlatformEventDispatcher {
92 public: 119 public:
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 waiting_on_status_(false), 383 waiting_on_status_(false),
357 status_received_since_enter_(false), 384 status_received_since_enter_(false),
358 source_provider_(NULL), 385 source_provider_(NULL),
359 source_current_window_(None), 386 source_current_window_(None),
360 source_state_(SOURCE_STATE_OTHER), 387 source_state_(SOURCE_STATE_OTHER),
361 drag_operation_(0), 388 drag_operation_(0),
362 negotiated_operation_(ui::DragDropTypes::DRAG_NONE), 389 negotiated_operation_(ui::DragDropTypes::DRAG_NONE),
363 grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorGrabbing)), 390 grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorGrabbing)),
364 copy_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorCopy)), 391 copy_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorCopy)),
365 move_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorMove)), 392 move_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorMove)),
393 null_drag_widget_bounds_(-100, -100, 1, 1),
366 weak_ptr_factory_(this) { 394 weak_ptr_factory_(this) {
367 // Some tests change the DesktopDragDropClientAuraX11 associated with an 395 // Some tests change the DesktopDragDropClientAuraX11 associated with an
368 // |xwindow|. 396 // |xwindow|.
369 g_live_client_map.Get()[xwindow] = this; 397 g_live_client_map.Get()[xwindow] = this;
370 398
371 // Mark that we are aware of drag and drop concepts. 399 // Mark that we are aware of drag and drop concepts.
372 unsigned long xdnd_version = kMinXdndVersion; 400 unsigned long xdnd_version = kMinXdndVersion;
373 XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndAware"), 401 XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndAware"),
374 XA_ATOM, 32, PropModeReplace, 402 XA_ATOM, 32, PropModeReplace,
375 reinterpret_cast<unsigned char*>(&xdnd_version), 1); 403 reinterpret_cast<unsigned char*>(&xdnd_version), 1);
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 // We were waiting on the status message so we could send the XdndDrop. 498 // We were waiting on the status message so we could send the XdndDrop.
471 if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) { 499 if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) {
472 move_loop_.EndMoveLoop(); 500 move_loop_.EndMoveLoop();
473 return; 501 return;
474 } 502 }
475 source_state_ = SOURCE_STATE_DROPPED; 503 source_state_ = SOURCE_STATE_DROPPED;
476 SendXdndDrop(source_window); 504 SendXdndDrop(source_window);
477 return; 505 return;
478 } 506 }
479 507
480 switch (negotiated_operation_) { 508 UpdateCursor();
481 case ui::DragDropTypes::DRAG_COPY:
482 move_loop_.UpdateCursor(copy_grab_cursor_);
483 break;
484 case ui::DragDropTypes::DRAG_MOVE:
485 move_loop_.UpdateCursor(move_grab_cursor_);
486 break;
487 default:
488 move_loop_.UpdateCursor(grab_cursor_);
489 break;
490 }
491 509
492 // Note: event.data.[2,3] specify a rectangle. It is a request by the other 510 // Note: event.data.[2,3] specify a rectangle. It is a request by the other
493 // window to not send further XdndPosition messages while the cursor is 511 // window to not send further XdndPosition messages while the cursor is
494 // within it. However, it is considered advisory and (at least according to 512 // within it. However, it is considered advisory and (at least according to
495 // the spec) the other side must handle further position messages within 513 // the spec) the other side must handle further position messages within
496 // it. GTK+ doesn't bother with this, so neither should we. 514 // it. GTK+ doesn't bother with this, so neither should we.
497 515
498 if (next_position_message_.get()) { 516 if (next_position_message_.get()) {
499 // We were waiting on the status message so we could send off the next 517 // We were waiting on the status message so we could send off the next
500 // position message we queued up. 518 // position message we queued up.
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 source_provider_->file_contents_name().AsUTF8Unsafe()); 621 source_provider_->file_contents_name().AsUTF8Unsafe());
604 } 622 }
605 ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions); 623 ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions);
606 624
607 // It is possible for the DesktopWindowTreeHostX11 to be destroyed during the 625 // It is possible for the DesktopWindowTreeHostX11 to be destroyed during the
608 // move loop, which would also destroy this drag-client. So keep track of 626 // move loop, which would also destroy this drag-client. So keep track of
609 // whether it is alive after the drag ends. 627 // whether it is alive after the drag ends.
610 base::WeakPtr<DesktopDragDropClientAuraX11> alive( 628 base::WeakPtr<DesktopDragDropClientAuraX11> alive(
611 weak_ptr_factory_.GetWeakPtr()); 629 weak_ptr_factory_.GetWeakPtr());
612 630
631 SetDragImage(source_provider_->GetDragImage(),
632 source_provider_->GetDragImageOffset());
633 CreateDragImageWindow();
634 // Capture drag widget to continue receiving events even if the drag source
635 // gets destroyed during the drag such as when we drag an item out of a menu
636 // and the menu closes.
637 drag_widget_->GetNativeWindow()->SetCapture();
638
613 // Windows has a specific method, DoDragDrop(), which performs the entire 639 // Windows has a specific method, DoDragDrop(), which performs the entire
614 // drag. We have to emulate this, so we spin off a nested runloop which will 640 // drag. We have to emulate this, so we spin off a nested runloop which will
615 // track all cursor movement and reroute events to a specific handler. 641 // track all cursor movement and reroute events to a specific handler.
616 move_loop_.SetDragImage(source_provider_->GetDragImage(), 642 move_loop_.RunMoveLoop();
617 source_provider_->GetDragImageOffset());
618 move_loop_.RunMoveLoop(source_window, grab_cursor_);
619 643
620 if (alive) { 644 if (alive) {
621 move_loop_.SetDragImage(gfx::ImageSkia(), gfx::Vector2dF()); 645 SetDragImage(gfx::ImageSkia(), gfx::Vector2dF());
622 646
623 source_provider_ = NULL; 647 source_provider_ = NULL;
624 g_current_drag_drop_client = NULL; 648 g_current_drag_drop_client = NULL;
625 drag_operation_ = 0; 649 drag_operation_ = 0;
626 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList")); 650 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList"));
627 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndDirectSave0)); 651 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndDirectSave0));
628 652
629 return negotiated_operation_; 653 return negotiated_operation_;
630 } 654 }
631 return ui::DragDropTypes::DRAG_NONE; 655 return ui::DragDropTypes::DRAG_NONE;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 // an XdndFinished message. 719 // an XdndFinished message.
696 StartEndMoveLoopTimer(); 720 StartEndMoveLoopTimer();
697 return; 721 return;
698 } 722 }
699 } 723 }
700 724
701 move_loop_.EndMoveLoop(); 725 move_loop_.EndMoveLoop();
702 } 726 }
703 727
704 void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { 728 void DesktopDragDropClientAuraX11::OnMoveLoopEnded() {
729 drag_widget_.reset();
705 if (source_current_window_ != None) { 730 if (source_current_window_ != None) {
706 SendXdndLeave(source_current_window_); 731 SendXdndLeave(source_current_window_);
707 source_current_window_ = None; 732 source_current_window_ = None;
708 } 733 }
709 target_current_context_.reset(); 734 target_current_context_.reset();
710 repeat_mouse_move_timer_.Stop(); 735 repeat_mouse_move_timer_.Stop();
711 end_move_loop_timer_.Stop(); 736 end_move_loop_timer_.Stop();
712 } 737 }
713 738
714 XID DesktopDragDropClientAuraX11::FindWindowFor( 739 XID DesktopDragDropClientAuraX11::FindWindowFor(
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
772 // sufficient. 797 // sufficient.
773 XSendEvent(xdisplay_, xid, False, 0, xev); 798 XSendEvent(xdisplay_, xid, False, 0, xev);
774 } 799 }
775 800
776 void DesktopDragDropClientAuraX11::ProcessMouseMove( 801 void DesktopDragDropClientAuraX11::ProcessMouseMove(
777 const gfx::Point& screen_point, 802 const gfx::Point& screen_point,
778 unsigned long event_time) { 803 unsigned long event_time) {
779 if (source_state_ != SOURCE_STATE_OTHER) 804 if (source_state_ != SOURCE_STATE_OTHER)
780 return; 805 return;
781 806
807 if (drag_widget_.get()) {
808 if (drag_image_.isNull()) {
809 drag_widget_->SetBounds(null_drag_widget_bounds_);
810 } else {
811 drag_widget_->SetBounds(gfx::Rect(
812 gfx::ToFlooredPoint(screen_point - drag_offset_),
813 drag_image_.size()));
814 }
815 drag_widget_->StackAtTop();
816 }
817
782 // Find the current window the cursor is over. 818 // Find the current window the cursor is over.
783 ::Window dest_window = FindWindowFor(screen_point); 819 ::Window dest_window = FindWindowFor(screen_point);
784 820
785 if (source_current_window_ != dest_window) { 821 if (source_current_window_ != dest_window) {
786 if (source_current_window_ != None) 822 if (source_current_window_ != None)
787 SendXdndLeave(source_current_window_); 823 SendXdndLeave(source_current_window_);
788 824
789 source_current_window_ = dest_window; 825 source_current_window_ = dest_window;
790 waiting_on_status_ = false; 826 waiting_on_status_ = false;
791 next_position_message_.reset(); 827 next_position_message_.reset();
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
904 if (drag_operation_ & ui::DragDropTypes::DRAG_LINK) 940 if (drag_operation_ & ui::DragDropTypes::DRAG_LINK)
905 operations.push_back(atom_cache_.GetAtom(kXdndActionLink)); 941 operations.push_back(atom_cache_.GetAtom(kXdndActionLink));
906 return operations; 942 return operations;
907 } 943 }
908 944
909 ui::SelectionFormatMap DesktopDragDropClientAuraX11::GetFormatMap() const { 945 ui::SelectionFormatMap DesktopDragDropClientAuraX11::GetFormatMap() const {
910 return source_provider_ ? source_provider_->GetFormatMap() : 946 return source_provider_ ? source_provider_->GetFormatMap() :
911 ui::SelectionFormatMap(); 947 ui::SelectionFormatMap();
912 } 948 }
913 949
950 void DesktopDragDropClientAuraX11::UpdateCursor() {
951 gfx::NativeCursor cursor = grab_cursor_;
952 switch (negotiated_operation_) {
953 case ui::DragDropTypes::DRAG_COPY:
954 cursor = copy_grab_cursor_;
955 break;
956 case ui::DragDropTypes::DRAG_MOVE:
957 cursor = move_grab_cursor_;
958 break;
959 default:
960 break;
961 }
962
963 // Update the pointer with the new cursor if a grab is active.
964 XChangeActivePointerGrab(
965 xdisplay_,
966 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
967 cursor.platform(),
968 CurrentTime);
969 }
970
914 void DesktopDragDropClientAuraX11::CompleteXdndPosition( 971 void DesktopDragDropClientAuraX11::CompleteXdndPosition(
915 ::Window source_window, 972 ::Window source_window,
916 const gfx::Point& screen_point) { 973 const gfx::Point& screen_point) {
917 int drag_operation = ui::DragDropTypes::DRAG_NONE; 974 int drag_operation = ui::DragDropTypes::DRAG_NONE;
918 scoped_ptr<ui::OSExchangeData> data; 975 scoped_ptr<ui::OSExchangeData> data;
919 scoped_ptr<ui::DropTargetEvent> drop_target_event; 976 scoped_ptr<ui::DropTargetEvent> drop_target_event;
920 DragDropDelegate* delegate = NULL; 977 DragDropDelegate* delegate = NULL;
921 DragTranslate(screen_point, &data, &drop_target_event, &delegate); 978 DragTranslate(screen_point, &data, &drop_target_event, &delegate);
922 if (delegate) 979 if (delegate)
923 drag_operation = delegate->OnDragUpdated(*drop_target_event); 980 drag_operation = delegate->OnDragUpdated(*drop_target_event);
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1021 xev.xclient.format = 32; 1078 xev.xclient.format = 32;
1022 xev.xclient.window = dest_window; 1079 xev.xclient.window = dest_window;
1023 xev.xclient.data.l[0] = xwindow_; 1080 xev.xclient.data.l[0] = xwindow_;
1024 xev.xclient.data.l[1] = 0; 1081 xev.xclient.data.l[1] = 0;
1025 xev.xclient.data.l[2] = CurrentTime; 1082 xev.xclient.data.l[2] = CurrentTime;
1026 xev.xclient.data.l[3] = None; 1083 xev.xclient.data.l[3] = None;
1027 xev.xclient.data.l[4] = None; 1084 xev.xclient.data.l[4] = None;
1028 SendXClientEvent(dest_window, &xev); 1085 SendXClientEvent(dest_window, &xev);
1029 } 1086 }
1030 1087
1088 void DesktopDragDropClientAuraX11::SetDragImage(const gfx::ImageSkia& image,
1089 const gfx::Vector2dF& offset) {
1090 drag_image_ = image;
1091 drag_offset_ = offset;
1092 // Reset the Y offset, so that the drag-image is always just below the cursor,
1093 // so that it is possible to see where the cursor is going.
1094 drag_offset_.set_y(0.f);
1095 }
1096
1097 void DesktopDragDropClientAuraX11::CreateDragImageWindow() {
1098 Widget* widget = new Widget;
1099 Widget::InitParams params(Widget::InitParams::TYPE_DRAG);
1100 params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW;
1101 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1102 params.accept_events = false;
1103
1104 if (!drag_image_.isNull() && !CheckIfIconValid(drag_image_)) {
1105 // Show drag widget off screen if the image is mostly transparent.
1106 drag_image_ = gfx::ImageSkia();
1107 drag_offset_ = gfx::Vector2dF();
1108 }
1109
1110 if (drag_image_.isNull()) {
1111 params.bounds = null_drag_widget_bounds_;
1112 } else {
1113 params.bounds = gfx::Rect(
1114 gfx::ToFlooredPoint(
1115 gfx::Screen::GetNativeScreen()->GetCursorScreenPoint() -
1116 drag_offset_),
1117 drag_image_.size());
1118 }
1119 widget->set_focus_on_creation(false);
1120 widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE);
1121 widget->Init(params);
1122 widget->SetOpacity(kDragWidgetOpacity);
1123 widget->GetNativeWindow()->SetName("DragWindow");
1124
1125 if (!drag_image_.isNull()) {
1126 ImageView* image = new ImageView();
1127 image->SetImage(drag_image_);
1128 image->SetBounds(0, 0, drag_image_.width(), drag_image_.height());
1129 widget->SetContentsView(image);
1130 }
1131
1132 widget->Show();
1133 widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false);
1134 drag_widget_.reset(widget);
1135 }
1136
1031 } // namespace views 1137 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698