Abstract drag-and-drop a bit and add application/recent document DND. #569717
This commit is contained in:
parent
e79c776c2e
commit
11561fd902
181
js/ui/dnd.js
Normal file
181
js/ui/dnd.js
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */
|
||||||
|
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const Gtk = imports.gi.Gtk;
|
||||||
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
|
const SNAP_BACK_ANIMATION_TIME = 0.25;
|
||||||
|
|
||||||
|
function _Draggable(actor) {
|
||||||
|
this._init(actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
_Draggable.prototype = {
|
||||||
|
_init : function(actor) {
|
||||||
|
this.actor = actor;
|
||||||
|
this.actor.connect('button-press-event',
|
||||||
|
Lang.bind(this, this._onButtonPress));
|
||||||
|
},
|
||||||
|
|
||||||
|
_onButtonPress : function (actor, event) {
|
||||||
|
// FIXME: we should make sure it's button 1, but we can't currently
|
||||||
|
// check that from JavaScript
|
||||||
|
if (Tweener.getTweenCount(actor))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this._grabActor(actor);
|
||||||
|
|
||||||
|
let [stageX, stageY] = event.get_coords();
|
||||||
|
this._dragStartX = stageX;
|
||||||
|
this._dragStartY = stageY;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_grabActor : function (actor) {
|
||||||
|
Clutter.grab_pointer(actor);
|
||||||
|
|
||||||
|
// We intercept motion and button-release events so that when
|
||||||
|
// you release after dragging, the app doesn't see that and
|
||||||
|
// think you just clicked. We connect to 'event' rather than
|
||||||
|
// 'captured-event' because the capturing phase doesn't happen
|
||||||
|
// when you've grabbed the pointer.
|
||||||
|
this._onEventId = actor.connect('event',
|
||||||
|
Lang.bind(this, this._onEvent));
|
||||||
|
},
|
||||||
|
|
||||||
|
_ungrabActor : function (actor) {
|
||||||
|
Clutter.ungrab_pointer();
|
||||||
|
actor.disconnect(this._onEventId);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onEvent : function (actor, event) {
|
||||||
|
if (this._dragActor) {
|
||||||
|
if (actor != this._dragActor )
|
||||||
|
return false;
|
||||||
|
} else if (actor != this.actor)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (event.type() == Clutter.EventType.BUTTON_RELEASE)
|
||||||
|
return this._onButtonRelease(actor, event);
|
||||||
|
else if (event.type() == Clutter.EventType.MOTION)
|
||||||
|
return this._onMotion(actor, event);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onMotion : function (actor, event) {
|
||||||
|
let [stageX, stageY] = event.get_coords();
|
||||||
|
|
||||||
|
// If we haven't begun a drag, see if the user has moved the
|
||||||
|
// mouse enough to trigger a drag
|
||||||
|
let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
|
||||||
|
if (!this._dragActor &&
|
||||||
|
(Math.abs(stageX - this._dragStartX) > threshold ||
|
||||||
|
Math.abs(stageY - this._dragStartY) > threshold)) {
|
||||||
|
this.emit('drag-begin', event.get_time());
|
||||||
|
|
||||||
|
if (this.actor._delegate && this.actor._delegate.getDragActor) {
|
||||||
|
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
|
||||||
|
this._dragOrigParent = undefined;
|
||||||
|
this._ungrabActor(actor);
|
||||||
|
this._grabActor(this._dragActor);
|
||||||
|
|
||||||
|
this._dragOffsetX = this._dragActor.x - this._dragStartX;
|
||||||
|
this._dragOffsetY = this._dragActor.y - this._dragStartY;
|
||||||
|
} else {
|
||||||
|
this._dragActor = actor;
|
||||||
|
this._dragOrigParent = actor.get_parent();
|
||||||
|
this._dragOrigX = this._dragActor.x;
|
||||||
|
this._dragOrigY = this._dragActor.y;
|
||||||
|
this._dragOrigScale = this._dragActor.scale_x;
|
||||||
|
|
||||||
|
let [actorStageX, actorStageY] = actor.get_transformed_position();
|
||||||
|
this._dragOffsetX = actorStageX - this._dragStartX;
|
||||||
|
this._dragOffsetY = actorStageY - this._dragStartY;
|
||||||
|
|
||||||
|
// Set the actor's scale such that it will keep the same
|
||||||
|
// transformed size when it's reparented to the stage
|
||||||
|
let [scaledWidth, scaledHeight] = actor.get_transformed_size();
|
||||||
|
actor.set_scale(scaledWidth / actor.width,
|
||||||
|
scaledHeight / actor.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._dragActor.reparent(actor.get_stage());
|
||||||
|
this._dragActor.raise_top();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are dragging, update the position
|
||||||
|
if (this._dragActor) {
|
||||||
|
this._dragActor.set_position(stageX + this._dragOffsetX,
|
||||||
|
stageY + this._dragOffsetY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onButtonRelease : function (actor, event) {
|
||||||
|
this._ungrabActor(actor);
|
||||||
|
|
||||||
|
let dragging = (actor == this._dragActor);
|
||||||
|
this._dragActor = undefined;
|
||||||
|
|
||||||
|
if (!dragging)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this.emit('drag-end', event.get_time());
|
||||||
|
|
||||||
|
// Find a drop target
|
||||||
|
actor.hide();
|
||||||
|
let [dropX, dropY] = event.get_coords();
|
||||||
|
let target = actor.get_stage().get_actor_at_pos(dropX, dropY);
|
||||||
|
actor.show();
|
||||||
|
while (target) {
|
||||||
|
if (target._delegate && target._delegate.acceptDrop) {
|
||||||
|
let [targX, targY] = target.get_transformed_position();
|
||||||
|
if (target._delegate.acceptDrop(this.actor._delegate, actor,
|
||||||
|
(dropX + this._xOffset - targX) / target.scale_x,
|
||||||
|
(dropY + this._yOffset - targY) / target.scale_y,
|
||||||
|
event.get_time())) {
|
||||||
|
// If it accepted the drop without taking the actor,
|
||||||
|
// destroy it.
|
||||||
|
if (actor.get_parent() == actor.get_stage())
|
||||||
|
actor.destroy();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
target = target.get_parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// No target, so snap back
|
||||||
|
Tweener.addTween(actor,
|
||||||
|
{ x: this._dragStartX + this._dragOffsetX,
|
||||||
|
y: this._dragStartY + this._dragOffsetY,
|
||||||
|
time: SNAP_BACK_ANIMATION_TIME,
|
||||||
|
transition: "easeOutQuad",
|
||||||
|
onComplete: this._onSnapBackComplete,
|
||||||
|
onCompleteScope: this,
|
||||||
|
onCompleteParams: [actor]
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onSnapBackComplete : function (dragActor) {
|
||||||
|
if (this._dragOrigParent) {
|
||||||
|
dragActor.reparent(this._dragOrigParent);
|
||||||
|
dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
|
||||||
|
dragActor.set_position(this._dragOrigX, this._dragOrigY);
|
||||||
|
} else
|
||||||
|
dragActor.destroy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Signals.addSignalMethods(_Draggable.prototype);
|
||||||
|
|
||||||
|
function makeDraggable(actor) {
|
||||||
|
return new _Draggable(actor);
|
||||||
|
}
|
@ -4,11 +4,14 @@ const Big = imports.gi.Big;
|
|||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
|
const Lang = imports.lang;
|
||||||
const Pango = imports.gi.Pango;
|
const Pango = imports.gi.Pango;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Tidy = imports.gi.Tidy;
|
const Tidy = imports.gi.Tidy;
|
||||||
|
|
||||||
|
const DND = imports.ui.dnd;
|
||||||
|
|
||||||
const ITEM_DISPLAY_NAME_COLOR = new Clutter.Color();
|
const ITEM_DISPLAY_NAME_COLOR = new Clutter.Color();
|
||||||
ITEM_DISPLAY_NAME_COLOR.from_pixel(0xffffffff);
|
ITEM_DISPLAY_NAME_COLOR.from_pixel(0xffffffff);
|
||||||
const ITEM_DISPLAY_DESCRIPTION_COLOR = new Clutter.Color();
|
const ITEM_DISPLAY_DESCRIPTION_COLOR = new Clutter.Color();
|
||||||
@ -37,16 +40,18 @@ function GenericDisplayItem(availableWidth) {
|
|||||||
GenericDisplayItem.prototype = {
|
GenericDisplayItem.prototype = {
|
||||||
_init: function(availableWidth) {
|
_init: function(availableWidth) {
|
||||||
this._availableWidth = availableWidth;
|
this._availableWidth = availableWidth;
|
||||||
let me = this;
|
|
||||||
|
|
||||||
this.actor = new Clutter.Group({ reactive: true,
|
this.actor = new Clutter.Group({ reactive: true,
|
||||||
width: availableWidth,
|
width: availableWidth,
|
||||||
height: ITEM_DISPLAY_HEIGHT });
|
height: ITEM_DISPLAY_HEIGHT });
|
||||||
this.actor.connect('button-press-event', function(group, e) {
|
this.actor._delegate = this;
|
||||||
me.emit('activate');
|
this.actor.connect('button-release-event',
|
||||||
return true;
|
Lang.bind(this,
|
||||||
});
|
function(draggable, e) {
|
||||||
|
this.activate();
|
||||||
|
}));
|
||||||
|
|
||||||
|
DND.makeDraggable(this.actor);
|
||||||
this._bg = new Big.Box({ background_color: ITEM_DISPLAY_BACKGROUND_COLOR,
|
this._bg = new Big.Box({ background_color: ITEM_DISPLAY_BACKGROUND_COLOR,
|
||||||
corner_radius: 4,
|
corner_radius: 4,
|
||||||
x: 0, y: 0,
|
x: 0, y: 0,
|
||||||
@ -58,6 +63,25 @@ GenericDisplayItem.prototype = {
|
|||||||
this._icon = null;
|
this._icon = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
//// Draggable interface ////
|
||||||
|
getDragActor: function(stageX, stageY) {
|
||||||
|
// FIXME: assumes this._icon is a Clutter.Texture
|
||||||
|
let icon = new Clutter.CloneTexture({ parent_texture: this._icon });
|
||||||
|
[icon.width, icon.height] = this._icon.get_transformed_size();
|
||||||
|
|
||||||
|
// If the user dragged from the icon itself, then position
|
||||||
|
// the dragActor over the original icon. Otherwise center it
|
||||||
|
// around the pointer
|
||||||
|
let [iconX, iconY] = this._icon.get_transformed_position();
|
||||||
|
let [iconWidth, iconHeight] = this._icon.get_transformed_size();
|
||||||
|
if (stageX > iconX && stageX <= iconX + iconWidth &&
|
||||||
|
stageY > iconY && stageY <= iconY + iconHeight)
|
||||||
|
icon.set_position(iconX, iconY);
|
||||||
|
else
|
||||||
|
icon.set_position(stageX - icon.width / 2, stageY - icon.height / 2);
|
||||||
|
return icon;
|
||||||
|
},
|
||||||
|
|
||||||
//// Public methods ////
|
//// Public methods ////
|
||||||
|
|
||||||
// Highlights the item by setting a different background color than the default
|
// Highlights the item by setting a different background color than the default
|
||||||
@ -71,6 +95,11 @@ GenericDisplayItem.prototype = {
|
|||||||
this._bg.background_color = color;
|
this._bg.background_color = color;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Activates the item, as though it was clicked
|
||||||
|
activate: function() {
|
||||||
|
this.emit('activate');
|
||||||
|
},
|
||||||
|
|
||||||
//// Pure virtual public methods ////
|
//// Pure virtual public methods ////
|
||||||
|
|
||||||
// Performes an action associated with launching this item, such as opening a file or an application.
|
// Performes an action associated with launching this item, such as opening a file or an application.
|
||||||
|
@ -11,6 +11,8 @@ const Pango = imports.gi.Pango;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
const DND = imports.ui.dnd;
|
||||||
|
const GenericDisplay = imports.ui.genericDisplay;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Overlay = imports.ui.overlay;
|
const Overlay = imports.ui.overlay;
|
||||||
const Panel = imports.ui.panel;
|
const Panel = imports.ui.panel;
|
||||||
@ -19,7 +21,6 @@ const Tweener = imports.ui.tweener;
|
|||||||
// Windows are slightly translucent in the overlay mode
|
// Windows are slightly translucent in the overlay mode
|
||||||
const WINDOW_OPACITY = 0.9 * 255;
|
const WINDOW_OPACITY = 0.9 * 255;
|
||||||
const FOCUS_ANIMATION_TIME = 0.15;
|
const FOCUS_ANIMATION_TIME = 0.15;
|
||||||
const SNAP_BACK_ANIMATION_TIME = 0.25;
|
|
||||||
|
|
||||||
const WINDOWCLONE_BG_COLOR = new Clutter.Color();
|
const WINDOWCLONE_BG_COLOR = new Clutter.Color();
|
||||||
WINDOWCLONE_BG_COLOR.from_pixel(0x000000f0);
|
WINDOWCLONE_BG_COLOR.from_pixel(0x000000f0);
|
||||||
@ -64,20 +65,19 @@ WindowClone.prototype = {
|
|||||||
this.origX = realWindow.x;
|
this.origX = realWindow.x;
|
||||||
this.origY = realWindow.y;
|
this.origY = realWindow.y;
|
||||||
|
|
||||||
this.actor.connect('button-press-event',
|
|
||||||
Lang.bind(this, this._onButtonPress));
|
|
||||||
this.actor.connect('button-release-event',
|
this.actor.connect('button-release-event',
|
||||||
Lang.bind(this, this._onButtonRelease));
|
Lang.bind(this, this._onButtonRelease));
|
||||||
|
|
||||||
this.actor.connect('enter-event',
|
this.actor.connect('enter-event',
|
||||||
Lang.bind(this, this._onEnter));
|
Lang.bind(this, this._onEnter));
|
||||||
this.actor.connect('leave-event',
|
this.actor.connect('leave-event',
|
||||||
Lang.bind(this, this._onLeave));
|
Lang.bind(this, this._onLeave));
|
||||||
this.actor.connect('motion-event',
|
|
||||||
Lang.bind(this, this._onMotion));
|
|
||||||
|
|
||||||
this._havePointer = false;
|
this._havePointer = false;
|
||||||
|
|
||||||
|
this._draggable = DND.makeDraggable(this.actor);
|
||||||
|
this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
|
||||||
|
this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
|
||||||
this._inDrag = false;
|
this._inDrag = false;
|
||||||
this._buttonDown = false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function () {
|
destroy: function () {
|
||||||
@ -85,7 +85,7 @@ WindowClone.prototype = {
|
|||||||
if (this._title)
|
if (this._title)
|
||||||
this._title.destroy();
|
this._title.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onEnter: function (actor, event) {
|
_onEnter: function (actor, event) {
|
||||||
// If the user drags faster than we can follow, he'll end up
|
// If the user drags faster than we can follow, he'll end up
|
||||||
// leaving the window temporarily and then re-entering it
|
// leaving the window temporarily and then re-entering it
|
||||||
@ -113,100 +113,25 @@ WindowClone.prototype = {
|
|||||||
this._updateTitle();
|
this._updateTitle();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onButtonPress : function (actor, event) {
|
_onButtonRelease : function (actor, event) {
|
||||||
if (Tweener.isTweening(this.actor))
|
this.emit('selected', event.get_time());
|
||||||
return;
|
},
|
||||||
|
|
||||||
actor.raise_top();
|
|
||||||
|
|
||||||
let [stageX, stageY] = event.get_coords();
|
|
||||||
|
|
||||||
this._buttonDown = true;
|
|
||||||
this._dragStartX = stageX;
|
|
||||||
this._dragStartY = stageY;
|
|
||||||
|
|
||||||
Clutter.grab_pointer(actor);
|
|
||||||
|
|
||||||
|
_onDragBegin : function (draggable, time) {
|
||||||
|
this._inDrag = true;
|
||||||
this._updateTitle();
|
this._updateTitle();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onMotion : function (actor, event) {
|
_onDragEnd : function (draggable, time) {
|
||||||
if (!this._buttonDown)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let [stageX, stageY] = event.get_coords();
|
|
||||||
|
|
||||||
// If we haven't begun a drag, see if the user has moved the mouse enough
|
|
||||||
// to trigger a drag
|
|
||||||
let dragThreshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
|
|
||||||
if (!this._inDrag &&
|
|
||||||
(Math.abs(stageX - this._dragStartX) > dragThreshold ||
|
|
||||||
Math.abs(stageY - this._dragStartY) > dragThreshold)) {
|
|
||||||
this._inDrag = true;
|
|
||||||
|
|
||||||
this._dragOrigParent = actor.get_parent();
|
|
||||||
this._dragOrigX = actor.x;
|
|
||||||
this._dragOrigY = actor.y;
|
|
||||||
this._dragOrigScale = actor.scale_x;
|
|
||||||
|
|
||||||
let [cloneStageX, cloneStageY] = actor.get_transformed_position();
|
|
||||||
this._dragOffsetX = cloneStageX - this._dragStartX;
|
|
||||||
this._dragOffsetY = cloneStageY - this._dragStartY;
|
|
||||||
|
|
||||||
// Reparent the clone onto the stage, but keeping the same scale.
|
|
||||||
// (the set_position call below will take care of position.)
|
|
||||||
let [scaledWidth, scaledHeight] = actor.get_transformed_size();
|
|
||||||
actor.reparent(actor.get_stage());
|
|
||||||
actor.raise_top();
|
|
||||||
actor.set_scale(scaledWidth / actor.width,
|
|
||||||
scaledHeight / actor.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are dragging, update the position
|
|
||||||
if (this._inDrag) {
|
|
||||||
actor.set_position(stageX + this._dragOffsetX,
|
|
||||||
stageY + this._dragOffsetY);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_onButtonRelease : function (actor, event) {
|
|
||||||
Clutter.ungrab_pointer();
|
|
||||||
|
|
||||||
let inDrag = this._inDrag;
|
|
||||||
this._buttonDown = false;
|
|
||||||
this._inDrag = false;
|
this._inDrag = false;
|
||||||
|
|
||||||
if (inDrag) {
|
// Most likely, the clone is going to move away from the
|
||||||
let [stageX, stageY] = event.get_coords();
|
// pointer now. But that won't cause a leave-event, so
|
||||||
|
// do this by hand. Of course, if the window only snaps
|
||||||
let origWorkspace = this.realWindow.get_workspace();
|
// back a short distance, this might be wrong, but it's
|
||||||
this.emit('dragged', stageX, stageY, event.get_time());
|
// better to have the label mysteriously missing than
|
||||||
if (this.realWindow.get_workspace() == origWorkspace) {
|
// mysteriously present
|
||||||
// Didn't get moved elsewhere, restore position
|
this._havePointer = false;
|
||||||
Tweener.addTween(this.actor,
|
|
||||||
{ x: this._dragStartX + this._dragOffsetX,
|
|
||||||
y: this._dragStartY + this._dragOffsetY,
|
|
||||||
time: SNAP_BACK_ANIMATION_TIME,
|
|
||||||
transition: "easeOutQuad",
|
|
||||||
onComplete: this._onSnapBackComplete,
|
|
||||||
onCompleteScope: this
|
|
||||||
});
|
|
||||||
// Most likely, the clone is going to move away from the
|
|
||||||
// pointer now. But that won't cause a leave-event, so
|
|
||||||
// do this by hand. Of course, if the window only snaps
|
|
||||||
// back a short distance, this might be wrong, but it's
|
|
||||||
// better to have the label mysteriously missing than
|
|
||||||
// mysteriously present
|
|
||||||
this._havePointer = false;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
this.emit('selected', event.get_time());
|
|
||||||
},
|
|
||||||
|
|
||||||
_onSnapBackComplete : function () {
|
|
||||||
this.actor.reparent(this._dragOrigParent);
|
|
||||||
this.actor.set_scale(this._dragOrigScale, this._dragOrigScale);
|
|
||||||
this.actor.set_position(this._dragOrigX, this._dragOrigY);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Called by Tweener
|
// Called by Tweener
|
||||||
@ -290,7 +215,7 @@ WindowClone.prototype = {
|
|||||||
|
|
||||||
_updateTitle : function () {
|
_updateTitle : function () {
|
||||||
let shouldShow = (this._havePointer &&
|
let shouldShow = (this._havePointer &&
|
||||||
!this._buttonDown &&
|
!this._inDrag &&
|
||||||
!Tweener.isTweening(this.actor));
|
!Tweener.isTweening(this.actor));
|
||||||
|
|
||||||
if (shouldShow)
|
if (shouldShow)
|
||||||
@ -345,6 +270,7 @@ Workspace.prototype = {
|
|||||||
this._metaWorkspace = global.screen.get_workspace_by_index(workspaceNum);
|
this._metaWorkspace = global.screen.get_workspace_by_index(workspaceNum);
|
||||||
|
|
||||||
this.actor = new Clutter.Group();
|
this.actor = new Clutter.Group();
|
||||||
|
this.actor._delegate = this;
|
||||||
this.scale = 1.0;
|
this.scale = 1.0;
|
||||||
|
|
||||||
let windows = global.get_windows().filter(this._isMyWindow, this);
|
let windows = global.get_windows().filter(this._isMyWindow, this);
|
||||||
@ -391,7 +317,6 @@ Workspace.prototype = {
|
|||||||
this.leavingOverlay = false;
|
this.leavingOverlay = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
updateRemovable : function() {
|
updateRemovable : function() {
|
||||||
let global = Shell.Global.get();
|
let global = Shell.Global.get();
|
||||||
let removable = (this._windows.length == 1 /* just desktop */ &&
|
let removable = (this._windows.length == 1 /* just desktop */ &&
|
||||||
@ -535,6 +460,7 @@ Workspace.prototype = {
|
|||||||
|
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._windows.splice(index, 1);
|
this._windows.splice(index, 1);
|
||||||
|
|
||||||
// If metaWin.get_compositor_private() returned non-NULL, that
|
// If metaWin.get_compositor_private() returned non-NULL, that
|
||||||
@ -714,6 +640,7 @@ Workspace.prototype = {
|
|||||||
destroy : function() {
|
destroy : function() {
|
||||||
let global = Shell.Global.get();
|
let global = Shell.Global.get();
|
||||||
|
|
||||||
|
Tweener.removeTweens(this.actor);
|
||||||
this.actor.destroy();
|
this.actor.destroy();
|
||||||
this.actor = null;
|
this.actor = null;
|
||||||
|
|
||||||
@ -797,6 +724,37 @@ Workspace.prototype = {
|
|||||||
|
|
||||||
screen.remove_workspace(workspace, event.get_time());
|
screen.remove_workspace(workspace, event.get_time());
|
||||||
return true;
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Draggable target interface
|
||||||
|
acceptDrop : function(source, actor, x, y, time) {
|
||||||
|
let global = Shell.Global.get();
|
||||||
|
|
||||||
|
if (source instanceof WindowClone) {
|
||||||
|
let win = source.realWindow;
|
||||||
|
if (this._isMyWindow(win))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Set a hint on the Mutter.Window so its initial position
|
||||||
|
// in the new workspace will be correct
|
||||||
|
win._overlayHint = {
|
||||||
|
x: actor.x,
|
||||||
|
y: actor.y,
|
||||||
|
scale: actor.scale_x
|
||||||
|
};
|
||||||
|
|
||||||
|
let metaWindow = win.get_meta_window();
|
||||||
|
metaWindow.change_workspace_by_index(this.workspaceNum,
|
||||||
|
false, // don't create workspace
|
||||||
|
time);
|
||||||
|
return true;
|
||||||
|
} else if (source instanceof GenericDisplay.GenericDisplayItem) {
|
||||||
|
this._metaWorkspace.activate(time);
|
||||||
|
source.activate();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1119,8 +1077,6 @@ Workspaces.prototype = {
|
|||||||
_addWorkspaceActor : function(workspaceNum) {
|
_addWorkspaceActor : function(workspaceNum) {
|
||||||
let workspace = new Workspace(workspaceNum);
|
let workspace = new Workspace(workspaceNum);
|
||||||
this._workspaces[workspaceNum] = workspace;
|
this._workspaces[workspaceNum] = workspace;
|
||||||
workspace.connect('window-dragged',
|
|
||||||
Lang.bind(this, this._onWindowDragged));
|
|
||||||
this.actor.add_actor(workspace.actor);
|
this.actor.add_actor(workspace.actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1128,48 +1084,6 @@ Workspaces.prototype = {
|
|||||||
let global = Shell.Global.get();
|
let global = Shell.Global.get();
|
||||||
|
|
||||||
global.screen.append_new_workspace(false, event.get_time());
|
global.screen.append_new_workspace(false, event.get_time());
|
||||||
},
|
|
||||||
|
|
||||||
_onWindowDragged : function(sourceWorkspace, clone, stageX, stageY, time) {
|
|
||||||
let global = Shell.Global.get();
|
|
||||||
|
|
||||||
// Positions in stage coordinates
|
|
||||||
let [myX, myY] = this.actor.get_transformed_position();
|
|
||||||
let [windowX, windowY] = clone.actor.get_transformed_position();
|
|
||||||
|
|
||||||
let targetWorkspace = null;
|
|
||||||
let targetX, targetY, targetScale;
|
|
||||||
|
|
||||||
for (let w = 0; w < this._workspaces.length; w++) {
|
|
||||||
let workspace = this._workspaces[w];
|
|
||||||
|
|
||||||
// Drag point relative to the new workspace
|
|
||||||
let relX = stageX - myX - workspace.gridX;
|
|
||||||
let relY = stageY - myY - workspace.gridY;
|
|
||||||
|
|
||||||
if (relX > 0 && relY > 0 &&
|
|
||||||
relX < global.screen_width * workspace.scale &&
|
|
||||||
relY < global.screen_height * workspace.scale)
|
|
||||||
{
|
|
||||||
targetWorkspace = workspace;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetWorkspace == null || targetWorkspace == sourceWorkspace)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Set a hint on the Mutter.Window so its initial position in the
|
|
||||||
// overlay will be correct
|
|
||||||
clone.realWindow._overlayHint = {
|
|
||||||
x: clone.actor.x,
|
|
||||||
y: clone.actor.y,
|
|
||||||
scale: clone.actor.scale_x
|
|
||||||
};
|
|
||||||
|
|
||||||
clone.metaWindow.change_workspace_by_index(targetWorkspace.workspaceNum,
|
|
||||||
false, // don't create workspace
|
|
||||||
time);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user