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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |