2011-09-28 13:16:26 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2011-01-05 14:47:27 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
import Clutter from 'gi://Clutter';
|
|
|
|
import * as Signals from '../misc/signals.js';
|
2019-02-09 03:21:36 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
import * as DND from './dnd.js';
|
|
|
|
import * as Main from './main.js';
|
2011-01-05 14:47:27 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export class XdndHandler extends Signals.EventEmitter {
|
2017-10-31 01:19:44 +00:00
|
|
|
constructor() {
|
2022-07-04 22:30:44 +00:00
|
|
|
super();
|
|
|
|
|
2011-01-05 14:47:27 +00:00
|
|
|
// Used to display a clone of the cursor window when the
|
|
|
|
// window group is hidden (like it happens in the overview)
|
|
|
|
this._cursorWindowClone = null;
|
|
|
|
|
|
|
|
// Used as a drag actor in case we don't have a cursor window clone
|
2013-05-09 01:53:20 +00:00
|
|
|
this._dummy = new Clutter.Actor({ width: 1, height: 1, opacity: 0 });
|
2013-02-15 06:58:21 +00:00
|
|
|
Main.uiGroup.add_actor(this._dummy);
|
2011-01-05 14:47:27 +00:00
|
|
|
this._dummy.hide();
|
|
|
|
|
2020-04-21 16:04:56 +00:00
|
|
|
var dnd = global.backend.get_dnd();
|
2017-12-02 00:27:35 +00:00
|
|
|
dnd.connect('dnd-enter', this._onEnter.bind(this));
|
|
|
|
dnd.connect('dnd-position-change', this._onPositionChanged.bind(this));
|
|
|
|
dnd.connect('dnd-leave', this._onLeave.bind(this));
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-01-05 14:47:27 +00:00
|
|
|
|
|
|
|
// Called when the user cancels the drag (i.e release the button)
|
2017-10-31 00:03:21 +00:00
|
|
|
_onLeave() {
|
2021-08-15 22:36:59 +00:00
|
|
|
global.window_group.disconnectObject(this);
|
2011-03-04 07:57:46 +00:00
|
|
|
if (this._cursorWindowClone) {
|
|
|
|
this._cursorWindowClone.destroy();
|
|
|
|
this._cursorWindowClone = null;
|
|
|
|
}
|
|
|
|
|
2011-01-05 14:47:27 +00:00
|
|
|
this.emit('drag-end');
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-01-05 14:47:27 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onEnter() {
|
2021-08-15 22:36:59 +00:00
|
|
|
global.window_group.connectObject('notify::visible',
|
|
|
|
this._onWindowGroupVisibilityChanged.bind(this), this);
|
2011-01-05 14:47:27 +00:00
|
|
|
|
|
|
|
this.emit('drag-begin', global.get_current_time());
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-01-05 14:47:27 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onWindowGroupVisibilityChanged() {
|
2011-01-05 14:47:27 +00:00
|
|
|
if (!global.window_group.visible) {
|
|
|
|
if (this._cursorWindowClone)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let windows = global.get_window_actors();
|
|
|
|
let cursorWindow = windows[windows.length - 1];
|
|
|
|
|
|
|
|
// FIXME: more reliable way?
|
2013-11-05 02:24:27 +00:00
|
|
|
if (!cursorWindow.get_meta_window().is_override_redirect())
|
2011-01-05 14:47:27 +00:00
|
|
|
return;
|
|
|
|
|
2020-03-29 21:51:13 +00:00
|
|
|
const constraintPosition = new Clutter.BindConstraint({
|
|
|
|
coordinate: Clutter.BindCoordinate.POSITION,
|
|
|
|
source: cursorWindow,
|
|
|
|
});
|
2011-01-05 14:47:27 +00:00
|
|
|
|
|
|
|
this._cursorWindowClone = new Clutter.Clone({ source: cursorWindow });
|
2013-03-03 19:15:28 +00:00
|
|
|
Main.uiGroup.add_actor(this._cursorWindowClone);
|
2011-01-05 14:47:27 +00:00
|
|
|
|
|
|
|
// Make sure that the clone has the same position as the source
|
2019-01-31 13:43:52 +00:00
|
|
|
this._cursorWindowClone.add_constraint(constraintPosition);
|
2011-01-05 14:47:27 +00:00
|
|
|
} else {
|
2019-08-20 02:10:46 +00:00
|
|
|
if (!this._cursorWindowClone)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._cursorWindowClone.destroy();
|
|
|
|
this._cursorWindowClone = null;
|
2011-01-05 14:47:27 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-01-05 14:47:27 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onPositionChanged(obj, x, y) {
|
2013-02-22 18:58:38 +00:00
|
|
|
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
2011-01-05 14:47:27 +00:00
|
|
|
|
|
|
|
// Make sure that the cursor window is on top
|
|
|
|
if (this._cursorWindowClone)
|
2019-11-05 19:17:19 +00:00
|
|
|
Main.uiGroup.set_child_above_sibling(this._cursorWindowClone, null);
|
2011-01-05 14:47:27 +00:00
|
|
|
|
|
|
|
let dragEvent = {
|
2019-08-19 19:06:04 +00:00
|
|
|
x,
|
|
|
|
y,
|
2020-08-12 18:59:01 +00:00
|
|
|
dragActor: this._cursorWindowClone ?? this._dummy,
|
2011-01-05 14:47:27 +00:00
|
|
|
source: this,
|
2019-08-20 21:43:54 +00:00
|
|
|
targetActor: pickedActor,
|
2011-01-05 14:47:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
for (let i = 0; i < DND.dragMonitors.length; i++) {
|
|
|
|
let motionFunc = DND.dragMonitors[i].dragMotion;
|
|
|
|
if (motionFunc) {
|
|
|
|
let result = motionFunc(dragEvent);
|
|
|
|
if (result != DND.DragMotionResult.CONTINUE)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (pickedActor) {
|
2019-01-29 19:36:54 +00:00
|
|
|
if (pickedActor._delegate && pickedActor._delegate.handleDragOver) {
|
2019-01-31 14:08:00 +00:00
|
|
|
let [r_, targX, targY] = pickedActor.transform_stage_point(x, y);
|
2019-01-29 19:36:54 +00:00
|
|
|
let result = pickedActor._delegate.handleDragOver(this,
|
|
|
|
dragEvent.dragActor,
|
|
|
|
targX,
|
|
|
|
targY,
|
|
|
|
global.get_current_time());
|
|
|
|
if (result != DND.DragMotionResult.CONTINUE)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pickedActor = pickedActor.get_parent();
|
2011-01-05 14:47:27 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-10 09:53:00 +00:00
|
|
|
}
|