123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857 |
- /* Desktop Icons GNOME Shell extension
- *
- * Copyright (C) 2017 Carlos Soriano <csoriano@redhat.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- const Gtk = imports.gi.Gtk;
- const Clutter = imports.gi.Clutter;
- const GObject = imports.gi.GObject;
- const Gio = imports.gi.Gio;
- const GLib = imports.gi.GLib;
- const St = imports.gi.St;
- const Mainloop = imports.mainloop;
- const Meta = imports.gi.Meta;
- const Animation = imports.ui.animation;
- const Background = imports.ui.background;
- const DND = imports.ui.dnd;
- const Main = imports.ui.main;
- const GrabHelper = imports.ui.grabHelper;
- const ExtensionUtils = imports.misc.extensionUtils;
- const Me = ExtensionUtils.getCurrentExtension();
- const Extension = Me.imports.extension;
- const DesktopGrid = Me.imports.desktopGrid;
- const FileItem = Me.imports.fileItem;
- const Prefs = Me.imports.prefs;
- const DBusUtils = Me.imports.dbusUtils;
- const DesktopIconsUtil = Me.imports.desktopIconsUtil;
- const { loadInterfaceXML } = imports.misc.fileUtils;
- const Clipboard = St.Clipboard.get_default();
- const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD;
- var S_IWOTH = 0x00002;
- function getDpy() {
- return global.screen || global.display;
- }
- function findMonitorIndexForPos(x, y) {
- return getDpy().get_monitor_index_for_rect(new Meta.Rectangle({x, y}));
- }
- var DesktopManager = GObject.registerClass({
- Properties: {
- 'writable-by-others': GObject.ParamSpec.boolean(
- 'writable-by-others',
- 'WritableByOthers',
- 'Whether the desktop\'s directory can be written by others (o+w unix permission)',
- GObject.ParamFlags.READABLE,
- false
- )
- }
- }, class DesktopManager extends GObject.Object {
- _init(params) {
- super._init(params);
- this._layoutChildrenId = 0;
- this._deleteChildrenId = 0;
- this._monitorDesktopDir = null;
- this._desktopMonitorCancellable = null;
- this._desktopGrids = {};
- this._fileItemHandlers = new Map();
- this._fileItems = new Map();
- this._dragCancelled = false;
- this._queryFileInfoCancellable = null;
- this._unixMode = null;
- this._writableByOthers = null;
- this._discreteGpuAvailable = false;
- this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => this._recreateDesktopIcons());
- this._rubberBand = new St.Widget({ style_class: 'rubber-band' });
- this._rubberBand.hide();
- Main.layoutManager._backgroundGroup.add_child(this._rubberBand);
- this._grabHelper = new GrabHelper.GrabHelper(global.stage);
- this._mountMonitor = Gio.VolumeMonitor.get();
- this._mountAddedId = this._mountMonitor.connect('mount-added', (monitor, mount) => {
- this._recreateDesktopIcons(); });
- this._mountRemovedId = this._mountMonitor.connect('mount-removed', (monitor, mount) => {
- this._recreateDesktopIcons(); });
- this._addDesktopIcons();
- this._monitorDesktopFolder();
- this.settingsId = Prefs.settings.connect('changed', () => this._recreateDesktopIcons());
- this.gtkSettingsId = Prefs.gtkSettings.connect('changed', (obj, key) => {
- if (key == 'show-hidden')
- this._recreateDesktopIcons();
- });
- this.nautilusSettingsId = Prefs.nautilusSettings.connect('changed', (obj, key) => {
- if (key == 'show-image-thumbnails')
- this._recreateDesktopIcons();
- });
- this._selection = new Set();
- this._currentSelection = new Set();
- this._inDrag = false;
- this._dragXStart = Number.POSITIVE_INFINITY;
- this._dragYStart = Number.POSITIVE_INFINITY;
- this._switcherooNotifyId = global.connect('notify::switcheroo-control',
- () => this._updateDiscreteGpuAvailable());
- this._updateDiscreteGpuAvailable();
- }
- _updateDiscreteGpuAvailable() {
- this._switcherooProxy = global.get_switcheroo_control();
- if (this._switcherooProxy) {
- let prop = this._switcherooProxy.get_cached_property('HasDualGpu');
- this._discreteGpuAvailable = prop ? prop.unpack() : false;
- } else {
- this._discreteGpuAvailable = false;
- }
- }
- startRubberBand(x, y) {
- this._rubberBandInitialX = x;
- this._rubberBandInitialY = y;
- this._initRubberBandColor();
- this._updateRubberBand(x, y);
- this._rubberBand.show();
- this._grabHelper.grab({ actor: global.stage });
- Extension.lockActivitiesButton = true;
- this._stageReleaseEventId = global.stage.connect('button-release-event', (actor, event) => {
- this.endRubberBand();
- });
- this._rubberBandId = global.stage.connect('motion-event', (actor, event) => {
- /* In some cases, when the user starts a rubberband selection and ends it
- * (by releasing the left button) over a window instead of doing it over
- * the desktop, the stage doesn't receive the "button-release" event.
- * This happens currently with, at least, Dash to Dock extension, but
- * it probably also happens with other applications or extensions.
- * To fix this, we also end the rubberband selection if we detect mouse
- * motion in the stage without the left button pressed during a
- * rubberband selection.
- * */
- let button = event.get_state();
- if (!(button & Clutter.ModifierType.BUTTON1_MASK)) {
- this.endRubberBand();
- return;
- }
- [x, y] = event.get_coords();
- this._updateRubberBand(x, y);
- let x0, y0, x1, y1;
- if (x >= this._rubberBandInitialX) {
- x0 = this._rubberBandInitialX;
- x1 = x;
- } else {
- x1 = this._rubberBandInitialX;
- x0 = x;
- }
- if (y >= this._rubberBandInitialY) {
- y0 = this._rubberBandInitialY;
- y1 = y;
- } else {
- y1 = this._rubberBandInitialY;
- y0 = y;
- }
- for (let [fileUri, fileItem] of this._fileItems) {
- fileItem.emit('selected', true, true,
- fileItem.intersectsWith(x0, y0, x1 - x0, y1 - y0));
- }
- });
- }
- endRubberBand() {
- this._rubberBand.hide();
- Extension.lockActivitiesButton = false;
- this._grabHelper.ungrab();
- global.stage.disconnect(this._rubberBandId);
- global.stage.disconnect(this._stageReleaseEventId);
- this._rubberBandId = 0;
- this._stageReleaseEventId = 0;
- this._selection = new Set([...this._selection, ...this._currentSelection]);
- this._currentSelection.clear();
- }
- _updateRubberBand(currentX, currentY) {
- let x = this._rubberBandInitialX < currentX ? this._rubberBandInitialX
- : currentX;
- let y = this._rubberBandInitialY < currentY ? this._rubberBandInitialY
- : currentY;
- let width = Math.abs(this._rubberBandInitialX - currentX);
- let height = Math.abs(this._rubberBandInitialY - currentY);
- /* TODO: Convert to gobject.set for 3.30 */
- this._rubberBand.set_position(x, y);
- this._rubberBand.set_size(width, height);
- }
- _recreateDesktopIcons() {
- this.clearSelection();
- this._destroyDesktopIcons();
- this._addDesktopIcons();
- }
- _addDesktopIcons() {
- let first_element = true;
- forEachBackgroundManager(bgManager => {
- let newGrid = new DesktopGrid.DesktopGrid(bgManager);
- newGrid.connect('destroy', (actor) => {
- // if a grid loses its actor, remove it from the grid list
- for (let grid in this._desktopGrids)
- if (this._desktopGrids[grid] == actor) {
- delete this._desktopGrids[grid];
- break;
- }
- });
- newGrid.isFirst = first_element;
- first_element = false;
- this._desktopGrids[bgManager._monitorIndex] = newGrid;
- });
- this._scanFiles();
- }
- _destroyDesktopIcons() {
- Object.values(this._desktopGrids).forEach(grid => grid.destroy());
- this._desktopGrids = {};
- }
- /**
- * Initialize rubberband color from the GTK rubberband class
- * */
- _initRubberBandColor() {
- let rgba = DesktopIconsUtil.getGtkClassBackgroundColor('rubberband', Gtk.StateFlags.NORMAL);
- let background_color =
- 'rgba(' + rgba.red * 255 + ', ' + rgba.green * 255 + ', ' + rgba.blue * 255 + ', 0.4)';
- this._rubberBand.set_style('background-color: ' + background_color);
- }
- async _scanFiles() {
- for (let [fileItem, fileItemHandler] of this._fileItemHandlers)
- Object.values(fileItemHandler).forEach(id => fileItem.disconnect(id));
- this._fileItemHandlers = new Map();
- if (!this._unixMode) {
- let desktopDir = DesktopIconsUtil.getDesktopDir();
- let fileInfo = desktopDir.query_info(Gio.FILE_ATTRIBUTE_UNIX_MODE,
- Gio.FileQueryInfoFlags.NONE,
- null);
- this._unixMode = fileInfo.get_attribute_uint32(Gio.FILE_ATTRIBUTE_UNIX_MODE);
- this._setWritableByOthers((this._unixMode & S_IWOTH) != 0);
- }
- try {
- let items = [];
- for (let item of await this._enumerateDesktop())
- items.push(item);
- for (let item of this._getMounts())
- items.push(item);
- let tmpFileItems = new Map();
- for (let [file, info, extra] of items) {
- let fileItem = new FileItem.FileItem(file, info, extra);
- tmpFileItems.set(fileItem.file.get_uri(), fileItem);
- let fileItemHandler = {}
- fileItemHandler.selectedId = fileItem.connect('selected',
- this._onFileItemSelected.bind(this));
- fileItemHandler.destroyId = fileItem.connect('destroy', () => {
- this._fileItemHandlers.delete(fileItem);
- });
- this._fileItemHandlers.set(fileItem, fileItemHandler);
- }
- this._fileItems = tmpFileItems;
- } catch (e) {
- if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
- log(`Error loading desktop files ${e.message}`, logError(e));
- return;
- }
- this.scheduleReLayoutChildren();
- }
- getDesktopFileNames () {
- let fileList = [];
- for (let [uri, item] of this._fileItems) {
- fileList.push(item.fileName);
- }
- return fileList;
- }
- _enumerateDesktop() {
- return new Promise((resolve, reject) => {
- if (this._desktopEnumerateCancellable)
- this._desktopEnumerateCancellable.cancel();
- this._desktopEnumerateCancellable = new Gio.Cancellable();
- let desktopDir = DesktopIconsUtil.getDesktopDir();
- desktopDir.enumerate_children_async(DesktopIconsUtil.DEFAULT_ATTRIBUTES,
- Gio.FileQueryInfoFlags.NONE,
- GLib.PRIORITY_DEFAULT,
- this._desktopEnumerateCancellable,
- (source, result) => {
- try {
- let fileEnum = source.enumerate_children_finish(result);
- let resultGenerator = function *() {
- let info;
- for (let [newFolder, extras] of DesktopIconsUtil.getExtraFolders()) {
- yield [newFolder, newFolder.query_info(DesktopIconsUtil.DEFAULT_ATTRIBUTES, Gio.FileQueryInfoFlags.NONE, this._desktopEnumerateCancellable), extras];
- }
- while ((info = fileEnum.next_file(null)))
- yield [fileEnum.get_child(info), info, Prefs.FileType.NONE];
- }.bind(this);
- resolve(resultGenerator());
- } catch (e) {
- reject(e);
- }
- });
- });
- }
- _monitorDesktopFolder() {
- if (this._monitorDesktopDir) {
- this._monitorDesktopDir.cancel();
- this._monitorDesktopDir = null;
- }
- let desktopDir = DesktopIconsUtil.getDesktopDir();
- this._monitorDesktopDir = desktopDir.monitor_directory(Gio.FileMonitorFlags.WATCH_MOVES, null);
- this._monitorDesktopDir.set_rate_limit(1000);
- this._monitorDesktopDir.connect('changed', (obj, file, otherFile, eventType) => this._updateDesktopIfChanged(file, otherFile, eventType));
- }
- _getMounts() {
- let files = [];
- if (!Prefs.settings.get_boolean('show-mount'))
- return files;
- this._mountMonitor.get_mounts().forEach( mount => {
- if (this._isNetworkMount(mount))
- return;
- let file = mount.get_root();
- let info = file.query_info(DesktopIconsUtil.DEFAULT_ATTRIBUTES,
- Gio.FileQueryInfoFlags.NONE,
- null);
- files.push([file, info, Prefs.FileType.MOUNT_DISK]);
- });
- return files;
- }
- _isNetworkMount(mount) {
- let volume = mount.get_volume();
- if (!volume)
- return true;
- return volume.get_identifier('class') == 'network';
- }
- checkIfSpecialFilesAreSelected() {
- for (let fileItem of this._selection) {
- if (fileItem.isSpecial)
- return true;
- }
- return false;
- }
- getNumberOfSelectedItems() {
- return this._selection.size;
- }
- get writableByOthers() {
- return this._writableByOthers;
- }
- _setWritableByOthers(value) {
- if (value == this._writableByOthers)
- return;
- this._writableByOthers = value
- this.notify('writable-by-others');
- }
- get discreteGpuAvailable() {
- return this._discreteGpuAvailable;
- }
- get switcherooProxyGPUs() {
- if (!this._switcherooProxy) {
- log('Could not apply discrete GPU environment, switcheroo-control not available');
- return null;
- }
- let prop = this._switcherooProxy.get_cached_property("GPUs");
- return prop ? prop.unpack() : null;
- }
- _updateDesktopIfChanged (file, otherFile, eventType) {
- let {
- DELETED, MOVED_IN, MOVED_OUT, CREATED, RENAMED, CHANGES_DONE_HINT, ATTRIBUTE_CHANGED
- } = Gio.FileMonitorEvent;
- let fileUri = file.get_uri();
- let fileItem = this._fileItems.get(fileUri);
- switch(eventType) {
- case RENAMED:
- this._fileItems.delete(fileUri);
- this._fileItems.set(otherFile.get_uri(), fileItem);
- fileItem.onFileRenamed(otherFile);
- return;
- case CHANGES_DONE_HINT:
- case ATTRIBUTE_CHANGED:
- /* a file changed, rather than the desktop itself */
- let desktopDir = DesktopIconsUtil.getDesktopDir();
- if (fileItem && file.get_uri() != desktopDir.get_uri()) {
- fileItem.onAttributeChanged();
- return;
- }
- if (this._queryFileInfoCancellable)
- this._queryFileInfoCancellable.cancel();
- file.query_info_async(Gio.FILE_ATTRIBUTE_UNIX_MODE,
- Gio.FileQueryInfoFlags.NONE,
- GLib.PRIORITY_DEFAULT,
- this._queryFileInfoCancellable,
- (source, result) => {
- try {
- let info = source.query_info_finish(result);
- this._queryFileInfoCancellable = null;
- this._unixMode = info.get_attribute_uint32(Gio.FILE_ATTRIBUTE_UNIX_MODE);
- this._setWritableByOthers((this._unixMode & S_IWOTH) != 0);
- if (this._writableByOthers)
- log(`desktop-icons: Desktop is writable by others - will not allow launching any desktop files`);
- } catch(error) {
- if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
- global.log('Error getting desktop unix mode: ' + error);
- }
- });
- return;
- }
- // Only get a subset of events we are interested in.
- // Note that CREATED will emit a CHANGES_DONE_HINT
- if (![DELETED, MOVED_IN, MOVED_OUT, CREATED].includes(eventType))
- return;
- this._recreateDesktopIcons();
- }
- _setupDnD() {
- this._draggableContainer = new St.Widget({
- visible: true,
- width: 1,
- height: 1,
- x: 0,
- y: 0,
- style_class: 'draggable'
- });
- this._draggableContainer._delegate = this;
- this._draggable = DND.makeDraggable(this._draggableContainer,
- {
- manualMode: true,
- dragActorOpacity: 100
- });
- this._draggable.connect('drag-cancelled', () => this._onDragCancelled());
- this._draggable.connect('drag-end', () => this._onDragEnd());
- this._draggable._dragActorDropped = event => this._dragActorDropped(event);
- }
- dragStart() {
- if (this._inDrag) {
- return;
- }
- this._setupDnD();
- let event = Clutter.get_current_event();
- let [x, y] = event.get_coords();
- [this._dragXStart, this._dragYStart] = event.get_coords();
- this._inDrag = true;
- for (let fileItem of this._selection) {
- let clone = new Clutter.Clone({
- source: fileItem,
- reactive: false
- });
- clone.x = fileItem.get_transformed_position()[0];
- clone.y = fileItem.get_transformed_position()[1];
- this._draggableContainer.add_child(clone);
- }
- Main.layoutManager.uiGroup.add_child(this._draggableContainer);
- if (this._draggableContainer.get_fixed_position !== undefined)
- this._draggableContainer.allocate_preferred_size(0, 0);
- this._draggable.startDrag(x, y, global.get_current_time(), event.get_event_sequence());
- }
- _onDragCancelled() {
- let event = Clutter.get_current_event();
- let [x, y] = event.get_coords();
- this._dragCancelled = true;
- }
- _onDragEnd() {
- this._inDrag = false;
- Main.layoutManager.uiGroup.remove_child(this._draggableContainer);
- }
- _dragActorDropped(event) {
- let [dropX, dropY] = event.get_coords();
- let target = this._draggable._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
- dropX, dropY);
- // We call observers only once per motion with the innermost
- // target actor. If necessary, the observer can walk the
- // parent itself.
- let dropEvent = {
- dropActor: this._draggable._dragActor,
- targetActor: target,
- clutterEvent: event
- };
- for (let dragMonitor of DND.dragMonitors) {
- let dropFunc = dragMonitor.dragDrop;
- if (dropFunc)
- switch (dropFunc(dropEvent)) {
- case DragDropResult.FAILURE:
- case DragDropResult.SUCCESS:
- return true;
- case DragDropResult.CONTINUE:
- continue;
- }
- }
- // At this point it is too late to cancel a drag by destroying
- // the actor, the fate of which is decided by acceptDrop and its
- // side-effects
- this._draggable._dragCancellable = false;
- let destroyActor = false;
- while (target) {
- if (target._delegate && target._delegate.acceptDrop) {
- let [r, targX, targY] = target.transform_stage_point(dropX, dropY);
- if (target._delegate.acceptDrop(this._draggable.actor._delegate,
- this._draggable._dragActor,
- targX,
- targY,
- event.get_time())) {
- // If it accepted the drop without taking the actor,
- // handle it ourselves.
- if (this._draggable._dragActor.get_parent() == Main.uiGroup) {
- if (this._draggable._restoreOnSuccess) {
- this._draggable._restoreDragActor(event.get_time());
- return true;
- }
- else {
- // We need this in order to make sure drag-end is fired
- destroyActor = true;
- }
- }
- this._draggable._dragInProgress = false;
- getDpy().set_cursor(Meta.Cursor.DEFAULT);
- this._draggable.emit('drag-end', event.get_time(), true);
- if (destroyActor) {
- this._draggable._dragActor.destroy();
- }
- this._draggable._dragComplete();
- return true;
- }
- }
- target = target.get_parent();
- }
- this._draggable._cancelDrag(event.get_time());
- return true;
- }
- acceptDrop(xEnd, yEnd) {
- let savedCoordinates = new Map();
- let [xDiff, yDiff] = [xEnd - this._dragXStart, yEnd - this._dragYStart];
- /* Remove all items before dropping new ones, so we can freely reposition
- * them.
- */
- for (let item of this._selection) {
- let [itemX, itemY] = item.get_transformed_position();
- let monitorIndex = findMonitorIndexForPos(itemX, itemY);
- savedCoordinates.set(item, [itemX, itemY]);
- this._desktopGrids[monitorIndex].removeFileItem(item);
- }
- for (let item of this._selection) {
- let [itemX, itemY] = savedCoordinates.get(item);
- /* Set the new ideal position where the item drop should happen */
- let newFileX = Math.round(xDiff + itemX);
- let newFileY = Math.round(yDiff + itemY);
- let monitorIndex = findMonitorIndexForPos(newFileX, newFileY);
- this._desktopGrids[monitorIndex].addFileItemCloseTo(item, newFileX, newFileY, DesktopGrid.StoredCoordinates.OVERWRITE);
- }
- return true;
- }
- selectionDropOnFileItem (fileItemDestination) {
- if (!fileItemDestination.isDirectory)
- return false;
- let droppedUris = [];
- for (let fileItem of this._selection) {
- if (fileItem.isSpecial)
- return false;
- if (fileItemDestination.file.get_uri() == fileItem.file.get_uri())
- return false;
- droppedUris.push(fileItem.file.get_uri());
- }
- if (droppedUris.length == 0)
- return true;
- DBusUtils.NautilusFileOperationsProxy.MoveURIsRemote(droppedUris,
- fileItemDestination.file.get_uri(),
- (result, error) => {
- if (error)
- throw new Error('Error moving files: ' + error.message);
- }
- );
- for (let fileItem of this._selection) {
- fileItem.state = FileItem.State.GONE;
- }
- this._recreateDesktopIcons();
- return true;
- }
- _resetGridsAndScheduleLayout() {
- this._deleteChildrenId = 0;
- Object.values(this._desktopGrids).forEach((grid) => grid.reset());
- if (!this._layoutChildrenId)
- this._layoutChildrenId = GLib.idle_add(GLib.PRIORITY_LOW, () => this._layoutChildren());
- return GLib.SOURCE_REMOVE;
- }
- scheduleReLayoutChildren() {
- if (this._deleteChildrenId != 0)
- return;
- if (this._layoutChildrenId != 0) {
- GLib.source_remove(this._layoutChildrenId);
- this._layoutChildrenId = 0;
- }
- this._deleteChildrenId = GLib.idle_add(GLib.PRIORITY_LOW, () => this._resetGridsAndScheduleLayout());
- }
- _addFileItemCloseTo(item) {
- let coordinates;
- let x = 0;
- let y = 0;
- let coordinatesAction = DesktopGrid.StoredCoordinates.ASSIGN;
- if (item.savedCoordinates != null) {
- [x, y] = item.savedCoordinates;
- coordinatesAction = DesktopGrid.StoredCoordinates.PRESERVE;
- }
- let monitorIndex = findMonitorIndexForPos(x, y);
- let desktopGrid = this._desktopGrids[monitorIndex];
- try {
- desktopGrid.addFileItemCloseTo(item, x, y, coordinatesAction);
- } catch (e) {
- log(`Error adding children to desktop: ${e.message}`);
- }
- }
- _layoutChildren() {
- let showHidden = Prefs.gtkSettings.get_boolean('show-hidden');
- /*
- * Paint the icons in two passes:
- * * first pass paints those that have their coordinates defined in the metadata
- * * second pass paints those new files that still don't have their definitive coordinates
- */
- for (let [fileUri, fileItem] of this._fileItems) {
- if (fileItem.savedCoordinates == null)
- continue;
- if (fileItem.state != FileItem.State.NORMAL)
- continue;
- if (!showHidden && fileItem.isHidden)
- continue;
- this._addFileItemCloseTo(fileItem);
- }
- for (let [fileUri, fileItem] of this._fileItems) {
- if (fileItem.savedCoordinates !== null)
- continue;
- if (fileItem.state != FileItem.State.NORMAL)
- continue;
- if (!showHidden && fileItem.isHidden)
- continue;
- this._addFileItemCloseTo(fileItem);
- }
- this._layoutChildrenId = 0;
- return GLib.SOURCE_REMOVE;
- }
- doRename() {
- if (this._selection.size != 1)
- return;
- let item = [...this._selection][0];
- if (item.canRename())
- item.doRename();
- }
- doPreview() {
- if (this._selection.size == 0)
- return;
- let item = [...this._selection][0];
- DBusUtils.GnomeNautilusPreviewProxy.ShowFileRemote(item.file.get_uri(), 0, false);
- }
- doOpen() {
- for (let fileItem of this._selection)
- fileItem.doOpen();
- }
- doTrash() {
- DBusUtils.NautilusFileOperationsProxy.TrashFilesRemote([...this._selection].map((x) => { return x.file.get_uri(); }),
- (source, error) => {
- if (error)
- throw new Error('Error trashing files on the desktop: ' + error.message);
- }
- );
- }
- doEmptyTrash() {
- DBusUtils.NautilusFileOperationsProxy.EmptyTrashRemote( (source, error) => {
- if (error)
- throw new Error('Error trashing files on the desktop: ' + error.message);
- });
- }
- _onFileItemSelected(fileItem, keepCurrentSelection, rubberBandSelection, addToSelection) {
- if (!keepCurrentSelection && !this._inDrag)
- this.clearSelection();
- let selection = keepCurrentSelection && rubberBandSelection ? this._currentSelection : this._selection;
- if (addToSelection)
- selection.add(fileItem);
- else
- selection.delete(fileItem);
- for (let [fileUri, fileItem] of this._fileItems)
- fileItem.isSelected = this._currentSelection.has(fileItem) || this._selection.has(fileItem);
- }
- clearSelection() {
- for (let [fileUri, fileItem] of this._fileItems)
- fileItem.isSelected = false;
- this._selection = new Set();
- this._currentSelection = new Set();
- }
- _getClipboardText(isCopy) {
- let action = isCopy ? 'copy' : 'cut';
- let text = `x-special/nautilus-clipboard\n${action}\n${
- [...this._selection].map(s => s.file.get_uri()).join('\n')
- }\n`;
- return text;
- }
- doCopy() {
- Clipboard.set_text(CLIPBOARD_TYPE, this._getClipboardText(true));
- }
- doCut() {
- Clipboard.set_text(CLIPBOARD_TYPE, this._getClipboardText(false));
- }
- destroy() {
- if (this._monitorDesktopDir)
- this._monitorDesktopDir.cancel();
- this._monitorDesktopDir = null;
- if (this._mountAddedId)
- this._mountMonitor.disconnect(this._mountAddedId);
- this._mountAddedId = 0;
- if (this._mountRemovedId)
- this._mountMonitor.disconnect(this._mountRemovedId);
- this._mountRemovedId = 0;
- if (this.settingsId)
- Prefs.settings.disconnect(this.settingsId);
- this.settingsId = 0;
- if (this.gtkSettingsId)
- Prefs.gtkSettings.disconnect(this.gtkSettingsId);
- this.gtkSettingsId = 0;
- if (this.nautilusSettingsId)
- Prefs.nautilusSettings.disconnect(this.nautilusSettingsId);
- this.nautilusSettingsId = 0;
- if (this._layoutChildrenId)
- GLib.source_remove(this._layoutChildrenId);
- this._layoutChildrenId = 0;
- if (this._deleteChildrenId)
- GLib.source_remove(this._deleteChildrenId);
- this._deleteChildrenId = 0;
- if (this._monitorsChangedId)
- Main.layoutManager.disconnect(this._monitorsChangedId);
- this._monitorsChangedId = 0;
- if (this._stageReleaseEventId)
- global.stage.disconnect(this._stageReleaseEventId);
- this._stageReleaseEventId = 0;
- if (this._rubberBandId)
- global.stage.disconnect(this._rubberBandId);
- this._rubberBandId = 0;
- this._rubberBand.destroy();
- if (this._queryFileInfoCancellable)
- this._queryFileInfoCancellable.cancel();
- Object.values(this._desktopGrids).forEach(grid => grid.destroy());
- this._desktopGrids = {}
- }
- });
- function forEachBackgroundManager(func) {
- Main.layoutManager._bgManagers.forEach(func);
- }
|