Commit 984ecfa3 authored by Alexander Dunaev's avatar Alexander Dunaev Committed by Commit Bot

[ozone/x11] Moved most X11-dependent code to XDragDropClient.

This CL continues the refactor of drag'n'drop on Linux.  Here the most
part of code that doesn't depend on Aura and views is moved.

Bug: 1014860
Change-Id: I47380c8ab0291485b2de544ba12342c09163e2a2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2007573Reviewed-by: default avatarThomas Anderson <thomasanderson@chromium.org>
Commit-Queue: Alexander Dunaev <adunaev@igalia.com>
Cr-Commit-Position: refs/heads/master@{#733267}
parent 95502153
This diff is collapsed.
......@@ -8,6 +8,7 @@
#include <vector>
#include "base/component_export.h"
#include "base/timer/timer.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_drag_context.h"
......@@ -30,8 +31,10 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragDropClient {
// Handling XdndPosition can be paused while waiting for more data; this is
// called either synchronously from OnXdndPosition, or asynchronously after
// we've received data requested from the other window.
virtual void CompleteXdndPosition(XID source_window,
const gfx::Point& screen_point) = 0;
void CompleteXdndPosition(XID source_window, const gfx::Point& screen_point);
void ProcessMouseMove(const gfx::Point& screen_point,
unsigned long event_time);
int current_modifier_state() const { return current_modifier_state_; }
......@@ -40,24 +43,61 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragDropClient {
// processes.
std::vector<Atom> GetOfferedDragOperations() const;
virtual void OnXdndEnter(const XClientMessageEvent& event);
virtual void OnXdndPosition(const XClientMessageEvent& event);
virtual void OnXdndStatus(const XClientMessageEvent& event);
virtual void OnXdndLeave(const XClientMessageEvent& event);
virtual void OnXdndDrop(const XClientMessageEvent& event);
virtual void OnXdndFinished(const XClientMessageEvent& event);
// These methods handle the various X11 client messages from the platform.
void OnXdndEnter(const XClientMessageEvent& event);
void OnXdndPosition(const XClientMessageEvent& event);
void OnXdndStatus(const XClientMessageEvent& event);
void OnXdndLeave(const XClientMessageEvent& event);
void OnXdndDrop(const XClientMessageEvent& event);
void OnXdndFinished(const XClientMessageEvent& event);
// Called when XSelection data has been copied to our process.
void OnSelectionNotify(const XSelectionEvent& xselection);
protected:
enum class SourceState {
// |source_current_window_| will receive a drop once we receive an
// XdndStatus from it.
kPendingDrop,
// The move looped will be ended once we receive XdndFinished from
// |source_current_window_|. We should not send XdndPosition to
// |source_current_window_| while in this state.
kDropped,
// There is no drag in progress or there is a drag in progress and the
// user has not yet released the mouse.
kOther,
};
XDragDropClient(Display* xdisplay, XID xwindow);
virtual ~XDragDropClient();
XDragDropClient(const XDragDropClient&) = delete;
XDragDropClient& operator=(const XDragDropClient&) = delete;
// We maintain a mapping of live XDragDropClient objects to their X11 windows,
// so that we'd able to short circuit sending X11 messages to windows in our
// process.
static XDragDropClient* GetForWindow(XID window);
XDragDropClient(const XDragDropClient&) = delete;
XDragDropClient& operator=(const XDragDropClient&) = delete;
// Handlers and callbacks that the subclass should implement.
virtual std::unique_ptr<XTopmostWindowFinder> CreateWindowFinder() = 0;
virtual SelectionFormatMap GetFormatMap() const = 0;
virtual void RetrieveTargets(std::vector<Atom>* targets) const = 0;
virtual int GetDragOperation(const gfx::Point& screen_point) = 0;
// Drops data at the current location and returns the resulting operation.
virtual int PerformDrop() = 0;
// Called when data from another application enters the window.
virtual void OnBeginForeignDrag(XID window) = 0;
// Called when data from another application is about to leave the window.
virtual void OnEndForeignDrag() = 0;
virtual void UpdateCursor(
DragDropTypes::DragOperation negotiated_operation) = 0;
// Called just before the drag leaves the window.
virtual void OnBeforeDragLeave() = 0;
// Called to end the move loop that is maintained by the subclass.
virtual void EndMoveLoop() = 0;
Display* xdisplay() const { return xdisplay_; }
XID xwindow() const { return xwindow_; }
......@@ -70,12 +110,35 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragDropClient {
XDragContext* target_current_context() {
return target_current_context_.get();
}
void set_target_current_context(std::unique_ptr<XDragContext> context) {
target_current_context_ = std::move(context);
SourceState source_state() const { return source_state_; }
void set_source_state(SourceState state) { source_state_ = state; }
bool waiting_on_status() const { return waiting_on_status_; }
int drag_operation() const { return drag_operation_; }
DragDropTypes::DragOperation negotiated_operation() const {
return negotiated_operation_;
}
bool status_received_since_enter() const {
return status_received_since_enter_;
}
// Resets the drag context. Overrides should call this implementation.
virtual void ResetDragContext();
// Resets the drag state so the object is ready to handle the drag.
void InitDrag(int operation);
void UpdateModifierState(int flags);
// Resets the drag context.
void ResetDragContext();
void StopRepeatMouseMoveTimer();
// Start timer to end the move loop if the target is too slow to respond after
// the mouse is released.
void StartEndMoveLoopTimer();
void StopEndMoveLoopTimer();
void HandleMouseReleased();
// Creates an XEvent and fills it in with values typical for XDND messages:
// the type of event is set to ClientMessage, the format is set to 32 (longs),
......@@ -88,25 +151,17 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragDropClient {
// Virtual for testing.
virtual XID FindWindowFor(const gfx::Point& screen_point);
virtual std::unique_ptr<XTopmostWindowFinder> CreateWindowFinder() = 0;
// Sends |xev| to |xid|, optionally short circuiting the round trip to the X
// server.
virtual void SendXClientEvent(XID xid, XEvent* xev);
void SendXdndEnter(XID dest_window, const std::vector<Atom>& targets);
void SendXdndPosition(XID dest_window,
const gfx::Point& screen_point,
unsigned long event_time);
void SendXdndLeave(XID dest_window);
void SendXdndDrop(XID dest_window);
virtual SelectionFormatMap GetFormatMap() const = 0;
// The operation bitfield as requested by StartDragAndDrop.
int drag_operation_ = 0;
// The modifier state for the most recent mouse move. Used to bypass an
// asynchronous roundtrip through the X11 server.
int current_modifier_state_ = 0;
private:
Display* const xdisplay_;
const XID xwindow_;
......@@ -114,7 +169,45 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragDropClient {
// Target side information.
std::unique_ptr<XDragContext> target_current_context_;
// Source side information.
XID source_current_window_ = x11::None;
SourceState source_state_ = SourceState::kOther;
// The operation bitfield as requested by StartDragAndDrop.
int drag_operation_ = 0;
// The modifier state for the most recent mouse move. Used to bypass an
// asynchronous roundtrip through the X11 server.
int current_modifier_state_ = 0;
// We offer the other window a list of possible operations,
// XdndActionsList. This is the requested action from the other window. This
// is DRAG_NONE if we haven't sent out an XdndPosition message yet, haven't
// yet received an XdndStatus or if the other window has told us that there's
// no action that we can agree on.
DragDropTypes::DragOperation negotiated_operation_ = DragDropTypes::DRAG_NONE;
// In the Xdnd protocol, we aren't supposed to send another XdndPosition
// message until we have received a confirming XdndStatus message.
bool waiting_on_status_ = false;
// If we would send an XdndPosition message while we're waiting for an
// XdndStatus response, we need to cache the latest details we'd send.
std::unique_ptr<std::pair<gfx::Point, unsigned long>> next_position_message_;
// Reprocesses the most recent mouse move event if the mouse has not moved
// in a while in case the window stacking order has changed and
// |source_current_window_| needs to be updated.
base::OneShotTimer repeat_mouse_move_timer_;
// Ends the move loop if the target is too slow to respond after the mouse is
// released.
base::OneShotTimer end_move_loop_timer_;
// When the mouse is released, we need to wait for the last XdndStatus message
// only if we have previously received a status message from
// |source_current_window_|.
bool status_received_since_enter_ = false;
};
} // namespace ui
......
......@@ -9,16 +9,13 @@
#include <set>
#include <vector>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/window_observer.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/x/x11_drag_drop_client.h"
#include "ui/events/event_constants.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/events/x/x11_window_event_manager.h"
#include "ui/gfx/geometry/point.h"
......@@ -35,7 +32,6 @@ class DragDropDelegate;
}
namespace gfx {
class ImageSkia;
class Point;
}
......@@ -64,22 +60,12 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
DesktopDragDropClientAuraX11(
aura::Window* root_window,
views::DesktopNativeCursorManager* cursor_manager,
::Display* xdisplay,
::Window xwindow);
Display* xdisplay,
XID xwindow);
~DesktopDragDropClientAuraX11() override;
void Init();
// These methods handle the various X11 client messages from the platform.
void OnXdndEnter(const XClientMessageEvent& event) override;
void OnXdndLeave(const XClientMessageEvent& event) override;
void OnXdndStatus(const XClientMessageEvent& event) override;
void OnXdndFinished(const XClientMessageEvent& event) override;
void OnXdndDrop(const XClientMessageEvent& event) override;
// Called when XSelection data has been copied to our process.
void OnSelectionNotify(const XSelectionEvent& xselection);
// Overridden from aura::client::DragDropClient:
int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
aura::Window* root_window,
......@@ -107,43 +93,18 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
void OnMoveLoopEnded() override;
protected:
// The following methods are virtual for the sake of testing.
// Getter for tests.
Widget* drag_widget() { return drag_widget_.get(); }
// Creates a move loop.
// Creates a move loop. Virtual for testing.
virtual std::unique_ptr<X11MoveLoop> CreateMoveLoop(
X11MoveLoopDelegate* delegate);
protected:
Widget* drag_widget() { return drag_widget_.get(); }
private:
enum class SourceState {
// |source_current_window_| will receive a drop once we receive an
// XdndStatus from it.
kPendingDrop,
// The move looped will be ended once we receive XdndFinished from
// |source_current_window_|. We should not send XdndPosition to
// |source_current_window_| while in this state.
kDropped,
// There is no drag in progress or there is a drag in progress and the
// user has not yet released the mouse.
kOther,
};
// Processes a mouse move at |screen_point|.
void ProcessMouseMove(const gfx::Point& screen_point,
unsigned long event_time);
// Start timer to end the move loop if the target is too slow to respond after
// the mouse is released.
void StartEndMoveLoopTimer();
// Ends the move loop.
void EndMoveLoop();
void EndMoveLoop() override;
// When we receive an position x11 message, we need to translate that into
// When we receive a position X11 message, we need to translate that into
// the underlying aura::Window representation, as moves internal to the X11
// window can cause internal drag leave and enter messages.
void DragTranslate(const gfx::Point& root_window_location,
......@@ -151,8 +112,8 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
std::unique_ptr<ui::DropTargetEvent>* event,
aura::client::DragDropDelegate** delegate);
// Called when we need to notify the current aura::Window that we're no
// longer dragging over it.
// Notifies |target_window_|'s drag delegate that we're no longer dragging,
// then unsubscribes |target_window_| from ourselves and forgets it.
void NotifyDragLeave();
// This returns a representation of the data we're offering in this
......@@ -163,21 +124,15 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
// Handling XdndPosition can be paused while waiting for more data; this is
// called either synchronously from OnXdndPosition, or asynchronously after
// we've received data requested from the other window.
void CompleteXdndPosition(::Window source_window,
const gfx::Point& screen_point) override;
void SendXdndPosition(::Window dest_window,
const gfx::Point& screen_point,
unsigned long event_time);
// Creates a widget for the user to drag around.
void CreateDragWidget(const gfx::ImageSkia& image);
int GetDragOperation(const gfx::Point& screen_point) override;
int PerformDrop() override;
void OnBeginForeignDrag(XID window) override;
void OnEndForeignDrag() override;
void UpdateCursor(
ui::DragDropTypes::DragOperation negotiated_operation) override;
void OnBeforeDragLeave() override;
// Returns true if |image| has any visible regions (defined as having a pixel
// with alpha > 32).
bool IsValidDragImage(const gfx::ImageSkia& image);
void ResetDragContext() override;
void RetrieveTargets(std::vector<Atom>* targets) const override;
std::unique_ptr<ui::XTopmostWindowFinder> CreateWindowFinder() override;
......@@ -205,45 +160,14 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
gfx::Point target_window_location_;
gfx::Point target_window_root_location_;
// In the Xdnd protocol, we aren't supposed to send another XdndPosition
// message until we have received a confirming XdndStatus message.
bool waiting_on_status_ = false;
// If we would send an XdndPosition message while we're waiting for an
// XdndStatus response, we need to cache the latest details we'd send.
std::unique_ptr<std::pair<gfx::Point, unsigned long>> next_position_message_;
// Reprocesses the most recent mouse move event if the mouse has not moved
// in a while in case the window stacking order has changed and
// |source_current_window_| needs to be updated.
base::OneShotTimer repeat_mouse_move_timer_;
// When the mouse is released, we need to wait for the last XdndStatus message
// only if we have previously received a status message from
// |source_current_window_|.
bool status_received_since_enter_ = false;
// Source side information.
ui::OSExchangeDataProviderAuraX11 const* source_provider_ = nullptr;
SourceState source_state_ = SourceState::kOther;
// The current drag-drop client that has an active operation. Since we have
// multiple root windows and multiple DesktopDragDropClientAuraX11 instances
// it is important to maintain only one drag and drop operation at any time.
static DesktopDragDropClientAuraX11* g_current_drag_drop_client;
// We offer the other window a list of possible operations,
// XdndActionsList. This is the requested action from the other window. This
// is DRAG_NONE if we haven't sent out an XdndPosition message yet, haven't
// yet received an XdndStatus or if the other window has told us that there's
// no action that we can agree on.
ui::DragDropTypes::DragOperation negotiated_operation_ =
ui::DragDropTypes::DRAG_NONE;
// Ends the move loop if the target is too slow to respond after the mouse is
// released.
base::OneShotTimer end_move_loop_timer_;
// Widget that the user drags around. May be NULL.
std::unique_ptr<Widget> drag_widget_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment