diff options
author | Zeno Albisser <zeno.albisser@theqtcompany.com> | 2014-12-05 15:04:29 +0100 |
---|---|---|
committer | Andras Becsi <andras.becsi@theqtcompany.com> | 2014-12-09 10:49:28 +0100 |
commit | af6588f8d723931a298c995fa97259bb7f7deb55 (patch) | |
tree | 060ca707847ba1735f01af2372e0d5e494dc0366 /chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc | |
parent | 2fff84d821cc7b1c785f6404e0f8091333283e74 (diff) | |
download | qtwebengine-chromium-af6588f8d723931a298c995fa97259bb7f7deb55.tar.gz |
BASELINE: Update chromium to 40.0.2214.28 and ninja to 1.5.3.
Change-Id: I759465284fd64d59ad120219cbe257f7402c4181
Reviewed-by: Andras Becsi <andras.becsi@theqtcompany.com>
Diffstat (limited to 'chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc')
-rw-r--r-- | chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc | 189 |
1 files changed, 152 insertions, 37 deletions
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc index d8a76e66559..64433279ad5 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc @@ -9,6 +9,8 @@ #include "base/event_types.h" #include "base/lazy_instance.h" #include "base/message_loop/message_loop.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/aura/client/capture_client.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" #include "ui/base/clipboard/clipboard.h" @@ -16,11 +18,17 @@ #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h" #include "ui/base/x/selection_utils.h" +#include "ui/base/x/x11_foreign_window_manager.h" #include "ui/base/x/x11_util.h" #include "ui/events/event.h" #include "ui/events/platform/platform_event_source.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/screen.h" +#include "ui/views/controls/image_view.h" #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h" #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h" +#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h" +#include "ui/views/widget/widget.h" #include "ui/wm/public/drag_drop_client.h" #include "ui/wm/public/drag_drop_delegate.h" @@ -76,6 +84,13 @@ const int kEndMoveLoopTimeoutMs = 1000; // stacking order has changed and |source_current_window_| needs to be updated. const int kRepeatMouseMoveTimeoutMs = 350; +// The minimum alpha before we declare a pixel transparent when searching in +// our source image. +const uint32 kMinAlpha = 32; + +// |drag_widget_|'s opacity. +const unsigned char kDragWidgetOpacity = 0xc0; + static base::LazyInstance< std::map< ::Window, views::DesktopDragDropClientAuraX11*> >::Leaky g_live_client_map = LAZY_INSTANCE_INITIALIZER; @@ -93,7 +108,7 @@ class DesktopDragDropClientAuraX11::X11DragContext X11DragContext(ui::X11AtomCache* atom_cache, ::Window local_window, const XClientMessageEvent& event); - virtual ~X11DragContext(); + ~X11DragContext() override; // When we receive an XdndPosition message, we need to have all the data // copied from the other window before we process the XdndPosition @@ -126,11 +141,11 @@ class DesktopDragDropClientAuraX11::X11DragContext private: // Masks the X11 atom |xdnd_operation|'s views representation onto // |drag_operation|. - void MaskOpeartion(::Atom xdnd_operation, int* drag_operation) const; + void MaskOperation(::Atom xdnd_operation, int* drag_operation) const; // ui::PlatformEventDispatcher: - virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE; - virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE; + bool CanDispatchEvent(const ui::PlatformEvent& event) override; + uint32_t DispatchEvent(const ui::PlatformEvent& event) override; // The atom cache owned by our parent. ui::X11AtomCache* atom_cache_; @@ -141,6 +156,14 @@ class DesktopDragDropClientAuraX11::X11DragContext // The XID of the window that's initiated the drag. unsigned long source_window_; + // The DesktopDragDropClientAuraX11 for |source_window_| if |source_window_| + // belongs to a Chrome window. + DesktopDragDropClientAuraX11* source_client_; + + // Used to unselect PropertyChangeMask on |source_window_| if |source_window_| + // does not belong to a Chrome window when X11DragContext is destroyed. + int foreign_window_manager_source_window_id_; + // The client we inform once we're done with requesting data. DesktopDragDropClientAuraX11* drag_drop_client_; @@ -175,6 +198,9 @@ DesktopDragDropClientAuraX11::X11DragContext::X11DragContext( : atom_cache_(atom_cache), local_window_(local_window), source_window_(event.data.l[0]), + source_client_( + DesktopDragDropClientAuraX11::GetForWindow(source_window_)), + foreign_window_manager_source_window_id_(0), drag_drop_client_(NULL), waiting_to_handle_position_(false), suggested_action_(None) { @@ -195,13 +221,13 @@ DesktopDragDropClientAuraX11::X11DragContext::X11DragContext( } } - DesktopDragDropClientAuraX11* client = - DesktopDragDropClientAuraX11::GetForWindow(source_window_); - if (!client) { + if (!source_client_) { // The window doesn't have a DesktopDragDropClientAuraX11, that means it's // created by some other process. Listen for messages on it. ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); - XSelectInput(gfx::GetXDisplay(), source_window_, PropertyChangeMask); + foreign_window_manager_source_window_id_ = + ui::XForeignWindowManager::GetInstance()->RequestEvents( + source_window_, PropertyChangeMask); // We must perform a full sync here because we could be racing // |source_window_|. @@ -210,7 +236,7 @@ DesktopDragDropClientAuraX11::X11DragContext::X11DragContext( // This drag originates from an aura window within our process. This means // that we can shortcut the X11 server and ask the owning SelectionOwner // for the data it's offering. - fetched_targets_ = client->GetFormatMap(); + fetched_targets_ = source_client_->GetFormatMap(); unfetched_targets_.clear(); } @@ -218,8 +244,12 @@ DesktopDragDropClientAuraX11::X11DragContext::X11DragContext( } DesktopDragDropClientAuraX11::X11DragContext::~X11DragContext() { - // Unsubscribe from message events. - ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); + if (!source_client_) { + // Unsubscribe from message events. + ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); + ui::XForeignWindowManager::GetInstance()->CancelRequest( + foreign_window_manager_source_window_id_); + } } void DesktopDragDropClientAuraX11::X11DragContext::OnStartXdndPositionMessage( @@ -269,7 +299,7 @@ void DesktopDragDropClientAuraX11::X11DragContext::OnSelectionNotify( scoped_refptr<base::RefCountedMemory> data; ::Atom type = None; if (ui::GetRawBytesOfProperty(local_window_, event.property, - &data, NULL, NULL, &type)) { + &data, NULL, &type)) { fetched_targets_.Insert(event.target, data); } @@ -283,9 +313,7 @@ void DesktopDragDropClientAuraX11::X11DragContext::OnSelectionNotify( } void DesktopDragDropClientAuraX11::X11DragContext::ReadActions() { - DesktopDragDropClientAuraX11* client = - DesktopDragDropClientAuraX11::GetForWindow(source_window_); - if (!client) { + if (!source_client_) { std::vector<Atom> atom_array; if (!ui::GetAtomArrayProperty(source_window_, "XdndActionList", @@ -298,7 +326,7 @@ void DesktopDragDropClientAuraX11::X11DragContext::ReadActions() { // We have a property notify set up for other windows in case they change // their action list. Thankfully, the views interface is static and you // can't change the action list after you enter StartDragAndDrop(). - actions_ = client->GetOfferedDragOperations(); + actions_ = source_client_->GetOfferedDragOperations(); } } @@ -306,15 +334,15 @@ int DesktopDragDropClientAuraX11::X11DragContext::GetDragOperation() const { int drag_operation = ui::DragDropTypes::DRAG_NONE; for (std::vector<Atom>::const_iterator it = actions_.begin(); it != actions_.end(); ++it) { - MaskOpeartion(*it, &drag_operation); + MaskOperation(*it, &drag_operation); } - MaskOpeartion(suggested_action_, &drag_operation); + MaskOperation(suggested_action_, &drag_operation); return drag_operation; } -void DesktopDragDropClientAuraX11::X11DragContext::MaskOpeartion( +void DesktopDragDropClientAuraX11::X11DragContext::MaskOperation( ::Atom xdnd_operation, int* drag_operation) const { if (xdnd_operation == atom_cache_->GetAtom(kXdndActionCopy)) @@ -347,8 +375,7 @@ DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11( views::DesktopNativeCursorManager* cursor_manager, Display* xdisplay, ::Window xwindow) - : move_loop_(this), - root_window_(root_window), + : root_window_(root_window), xdisplay_(xdisplay), xwindow_(xwindow), atom_cache_(xdisplay_, kAtomsToCache), @@ -393,6 +420,10 @@ DesktopDragDropClientAuraX11* DesktopDragDropClientAuraX11::GetForWindow( return it->second; } +void DesktopDragDropClientAuraX11::Init() { + move_loop_ = CreateMoveLoop(this); +} + void DesktopDragDropClientAuraX11::OnXdndEnter( const XClientMessageEvent& event) { DVLOG(1) << "XdndEnter"; @@ -469,7 +500,7 @@ void DesktopDragDropClientAuraX11::OnXdndStatus( if (source_state_ == SOURCE_STATE_PENDING_DROP) { // We were waiting on the status message so we could send the XdndDrop. if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) { - move_loop_.EndMoveLoop(); + move_loop_->EndMoveLoop(); return; } source_state_ = SOURCE_STATE_DROPPED; @@ -479,13 +510,13 @@ void DesktopDragDropClientAuraX11::OnXdndStatus( switch (negotiated_operation_) { case ui::DragDropTypes::DRAG_COPY: - move_loop_.UpdateCursor(copy_grab_cursor_); + move_loop_->UpdateCursor(copy_grab_cursor_); break; case ui::DragDropTypes::DRAG_MOVE: - move_loop_.UpdateCursor(move_grab_cursor_); + move_loop_->UpdateCursor(move_grab_cursor_); break; default: - move_loop_.UpdateCursor(grab_cursor_); + move_loop_->UpdateCursor(grab_cursor_); break; } @@ -520,7 +551,7 @@ void DesktopDragDropClientAuraX11::OnXdndFinished( // Clear |source_current_window_| to avoid sending XdndLeave upon ending the // move loop. source_current_window_ = None; - move_loop_.EndMoveLoop(); + move_loop_->EndMoveLoop(); } void DesktopDragDropClientAuraX11::OnXdndDrop( @@ -604,6 +635,18 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop( } ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions); + gfx::ImageSkia drag_image = source_provider_->GetDragImage(); + if (IsValidDragImage(drag_image)) { + CreateDragWidget(drag_image); + drag_widget_offset_ = source_provider_->GetDragImageOffset(); + } + + // Chrome expects starting drag and drop to release capture. + aura::Window* capture_window = + aura::client::GetCaptureClient(root_window)->GetGlobalCaptureWindow(); + if (capture_window) + capture_window->ReleaseCapture(); + // It is possible for the DesktopWindowTreeHostX11 to be destroyed during the // move loop, which would also destroy this drag-client. So keep track of // whether it is alive after the drag ends. @@ -613,12 +656,10 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop( // Windows has a specific method, DoDragDrop(), which performs the entire // drag. We have to emulate this, so we spin off a nested runloop which will // track all cursor movement and reroute events to a specific handler. - move_loop_.SetDragImage(source_provider_->GetDragImage(), - source_provider_->GetDragImageOffset()); - move_loop_.RunMoveLoop(source_window, grab_cursor_); + move_loop_->RunMoveLoop(source_window, grab_cursor_); if (alive) { - move_loop_.SetDragImage(gfx::ImageSkia(), gfx::Vector2dF()); + drag_widget_.reset(); source_provider_ = NULL; g_current_drag_drop_client = NULL; @@ -642,7 +683,7 @@ void DesktopDragDropClientAuraX11::Drop(aura::Window* target, } void DesktopDragDropClientAuraX11::DragCancel() { - move_loop_.EndMoveLoop(); + move_loop_->EndMoveLoop(); } bool DesktopDragDropClientAuraX11::IsDragDropInProgress() { @@ -655,8 +696,16 @@ void DesktopDragDropClientAuraX11::OnWindowDestroyed(aura::Window* window) { } void DesktopDragDropClientAuraX11::OnMouseMovement(XMotionEvent* event) { + gfx::Point screen_point(event->x_root, event->y_root); + if (drag_widget_.get()) { + drag_widget_->SetBounds( + gfx::Rect(screen_point - drag_widget_offset_, + drag_widget_->GetWindowBoundsInScreen().size())); + drag_widget_->StackAtTop(); + } + repeat_mouse_move_timer_.Stop(); - ProcessMouseMove(gfx::Point(event->x_root, event->y_root), event->time); + ProcessMouseMove(screen_point, event->time); } void DesktopDragDropClientAuraX11::OnMouseReleased() { @@ -665,7 +714,7 @@ void DesktopDragDropClientAuraX11::OnMouseReleased() { if (source_state_ != SOURCE_STATE_OTHER) { // The user has previously released the mouse and is clicking in // frustration. - move_loop_.EndMoveLoop(); + move_loop_->EndMoveLoop(); return; } @@ -682,7 +731,7 @@ void DesktopDragDropClientAuraX11::OnMouseReleased() { return; } - move_loop_.EndMoveLoop(); + move_loop_->EndMoveLoop(); return; } @@ -701,7 +750,7 @@ void DesktopDragDropClientAuraX11::OnMouseReleased() { } } - move_loop_.EndMoveLoop(); + move_loop_->EndMoveLoop(); } void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { @@ -714,6 +763,11 @@ void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { end_move_loop_timer_.Stop(); } +scoped_ptr<X11MoveLoop> DesktopDragDropClientAuraX11::CreateMoveLoop( + X11MoveLoopDelegate* delegate) { + return scoped_ptr<X11MoveLoop>(new X11WholeScreenMoveLoop(this)); +} + XID DesktopDragDropClientAuraX11::FindWindowFor( const gfx::Point& screen_point) { views::X11TopmostWindowFinder finder; @@ -818,7 +872,7 @@ void DesktopDragDropClientAuraX11::StartEndMoveLoopTimer() { } void DesktopDragDropClientAuraX11::EndMoveLoop() { - move_loop_.EndMoveLoop(); + move_loop_->EndMoveLoop(); } void DesktopDragDropClientAuraX11::DragTranslate( @@ -854,11 +908,23 @@ void DesktopDragDropClientAuraX11::DragTranslate( target_window_location_ = location; target_window_root_location_ = root_location; + int drag_op = target_current_context_->GetDragOperation(); + // KDE-based file browsers such as Dolphin change the drag operation depending + // on whether alt/ctrl/shift was pressed. However once Chromium gets control + // over the X11 events, the source application does no longer receive X11 + // events for key modifier changes, so the dnd operation gets stuck in an + // incorrect state. Blink can only dnd-open files of type DRAG_COPY, so the + // DRAG_COPY mask is added if the dnd object is a file. + if (drag_op & (ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_LINK) && + data->get()->HasFile()) { + drag_op |= ui::DragDropTypes::DRAG_COPY; + } + event->reset(new ui::DropTargetEvent( *(data->get()), location, root_location, - target_current_context_->GetDragOperation())); + drag_op)); if (target_window_changed) (*delegate)->OnDragEntered(*event->get()); } @@ -1031,4 +1097,53 @@ void DesktopDragDropClientAuraX11::SendXdndDrop(::Window dest_window) { SendXClientEvent(dest_window, &xev); } +void DesktopDragDropClientAuraX11::CreateDragWidget( + const gfx::ImageSkia& image) { + Widget* widget = new Widget; + Widget::InitParams params(Widget::InitParams::TYPE_DRAG); + params.opacity = Widget::InitParams::OPAQUE_WINDOW; + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.accept_events = false; + + gfx::Point location = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint() - + drag_widget_offset_; + params.bounds = gfx::Rect(location, image.size()); + widget->set_focus_on_creation(false); + widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE); + widget->Init(params); + widget->SetOpacity(kDragWidgetOpacity); + widget->GetNativeWindow()->SetName("DragWindow"); + + ImageView* image_view = new ImageView(); + image_view->SetImage(image); + image_view->SetBounds(0, 0, image.width(), image.height()); + widget->SetContentsView(image_view); + widget->Show(); + widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false); + + drag_widget_.reset(widget); +} + +bool DesktopDragDropClientAuraX11::IsValidDragImage( + const gfx::ImageSkia& image) { + if (image.isNull()) + return false; + + // Because we need a GL context per window, we do a quick check so that we + // don't make another context if the window would just be displaying a mostly + // transparent image. + const SkBitmap* in_bitmap = image.bitmap(); + SkAutoLockPixels in_lock(*in_bitmap); + for (int y = 0; y < in_bitmap->height(); ++y) { + uint32* in_row = in_bitmap->getAddr32(0, y); + + for (int x = 0; x < in_bitmap->width(); ++x) { + if (SkColorGetA(in_row[x]) > kMinAlpha) + return true; + } + } + + return false; +} + } // namespace views |