BossBey File Manager
PHP:
8.2.30
OS:
Linux
User:
htmlandpixel
Root
/
usr
/
share
/
gnome-shell
/
extensions
/
desktop-icons@gnome-shell-extensions.gcampax.github.com
š¤ Upload
š New File
š New Folder
Close
Editing: fileItem.js
/* 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 Clutter = imports.gi.Clutter; const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const GObject = imports.gi.GObject; const St = imports.gi.St; const Pango = imports.gi.Pango; const Meta = imports.gi.Meta; const GdkPixbuf = imports.gi.GdkPixbuf; const Cogl = imports.gi.Cogl; const GnomeDesktop = imports.gi.GnomeDesktop; const Mainloop = imports.mainloop; const Config = imports.misc.config; const Background = imports.ui.background; const Main = imports.ui.main; const PopupMenu = imports.ui.popupMenu; const Util = imports.misc.util; const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Extension = Me.imports.extension; const Prefs = Me.imports.prefs; const DBusUtils = Me.imports.dbusUtils; const DesktopIconsUtil = Me.imports.desktopIconsUtil; const Gettext = imports.gettext.domain('gnome-shell-extensions'); const _ = Gettext.gettext; const DRAG_TRESHOLD = 8; var S_IXUSR = 0o00100; var S_IWOTH = 0o00002; var State = { NORMAL: 0, GONE: 1, }; var FileItem = GObject.registerClass({ GTypeName: 'DesktopIcons_FileItem', Signals: { 'rename-clicked': {}, 'selected': { param_types: [GObject.TYPE_BOOLEAN, GObject.TYPE_BOOLEAN, GObject.TYPE_BOOLEAN] } } }, class FileItem extends St.Bin { _init(file, fileInfo, fileExtra) { super._init({ visible: true }); this._fileExtra = fileExtra; this._loadThumbnailDataCancellable = null; this._thumbnailScriptWatch = 0; this._setMetadataCancellable = null; this._queryFileInfoCancellable = null; this._isSpecial = this._fileExtra != Prefs.FileType.NONE; this._lastClickTime = 0; this._lastClickButton = 0; this._clickCount = 0; this._file = file; this._mount = null; if (this._fileExtra == Prefs.FileType.MOUNT_DISK) this._mount = this._file.find_enclosing_mount(null); this._savedCoordinates = null; let savedCoordinates = fileInfo.get_attribute_as_string('metadata::nautilus-icon-position'); if (savedCoordinates != null) this._savedCoordinates = savedCoordinates.split(',').map(x => Number(x)); this._state = State.NORMAL; try { this.set_fill(true, true); } catch(error) {} let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; this._delegate = this; this.connect('destroy', () => this._onDestroy()); this._container = new St.BoxLayout({ reactive: true, track_hover: true, can_focus: true, style_class: 'file-item', x_expand: true, y_expand: true, x_align: Clutter.ActorAlign.FILL, vertical: true }); this.set_child(this._container); this._icon = new St.Bin(); this._icon.set_height(Prefs.get_icon_size() * scaleFactor); this._iconAllocationIdleId = 0; this._iconAllocationId = this._icon.connect("notify::allocation", () => { if (this._iconAllocationIdleId) GLib.source_remove(this._iconAllocationIdleId); this._iconAllocationIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { GLib.source_remove(this._iconAllocationIdleId); this._iconAllocationIdleId = 0; this._updateIcon(); return GLib.SOURCE_REMOVE; }); }); this._iconContainer = new St.Bin({ visible: true }); this._iconContainer.child = this._icon; this._container.add_child(this._iconContainer); this._label = new St.Label({ style_class: 'name-label' }); this._container.add_child(this._label); let clutterText = this._label.get_clutter_text(); /* TODO: Convert to gobject.set for 3.30 */ clutterText.set_line_wrap(true); clutterText.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR); clutterText.set_ellipsize(Pango.EllipsizeMode.END); this._container.connect('button-press-event', (actor, event) => this._onPressButton(actor, event)); this._container.connect('motion-event', (actor, event) => this._onMotion(actor, event)); this._container.connect('leave-event', (actor, event) => this._onLeave(actor, event)); this._container.connect('enter-event', (actor, event) => this._onEnter(actor, event)); this._container.connect('button-release-event', (actor, event) => this._onReleaseButton(actor, event)); this._container.connect('touch-event', (actor, event) => this._onTouchEvent(actor, event)); /* Set the metadata and update relevant UI */ this._updateMetadataFromFileInfo(fileInfo); this._menuManager = null; this._menu = null; this._updateIcon(); this._isSelected = false; this._primaryButtonPressed = false; if (this._attributeCanExecute && !this._isValidDesktopFile) this._execLine = this.file.get_path(); if (fileExtra == Prefs.FileType.USER_DIRECTORY_TRASH) { // if this icon is the trash, monitor the state of the directory to update the icon this._trashChanged = false; this._queryTrashInfoCancellable = null; this._scheduleTrashRefreshId = 0; this._monitorTrashDir = this._file.monitor_directory(Gio.FileMonitorFlags.WATCH_MOVES, null); this._monitorTrashId = this._monitorTrashDir.connect('changed', (obj, file, otherFile, eventType) => { switch(eventType) { case Gio.FileMonitorEvent.DELETED: case Gio.FileMonitorEvent.MOVED_OUT: case Gio.FileMonitorEvent.CREATED: case Gio.FileMonitorEvent.MOVED_IN: if (this._queryTrashInfoCancellable || this._scheduleTrashRefreshId) { if (this._scheduleTrashRefreshId) GLib.source_remove(this._scheduleTrashRefreshId); this._scheduleTrashRefreshId = Mainloop.timeout_add(200, () => this._refreshTrashIcon()); } else { this._refreshTrashIcon(); } break; } }); } this._writebleByOthersId = Extension.desktopManager.connect('notify::writable-by-others', () => { if (!this._isValidDesktopFile) return; this._refreshMetadataAsync(true); }); } set_margins(width, height) { let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; this.set_width(Prefs.getDesiredWidth(scaleFactor, width)); this.set_height(Prefs.getDesiredHeight(scaleFactor, height)); } onAttributeChanged() { this._refreshMetadataAsync(this._isDesktopFile); } _onDestroy() { /* Regular file data */ if (this._setMetadataCancellable) this._setMetadataCancellable.cancel(); if (this._queryFileInfoCancellable) this._queryFileInfoCancellable.cancel(); Extension.desktopManager.disconnect(this._writebleByOthersId); /* Thumbnailing */ if (this._thumbnailScriptWatch) GLib.source_remove(this._thumbnailScriptWatch); if (this._loadThumbnailDataCancellable) this._loadThumbnailDataCancellable.cancel(); /* Desktop file */ if (this._monitorDesktopFileId) { this._monitorDesktopFile.disconnect(this._monitorDesktopFileId); this._monitorDesktopFile.cancel(); } /* Trash */ if (this._monitorTrashDir) { this._monitorTrashDir.disconnect(this._monitorTrashId); this._monitorTrashDir.cancel(); } if (this._queryTrashInfoCancellable) this._queryTrashInfoCancellable.cancel(); if (this._scheduleTrashRefreshId) GLib.source_remove(this._scheduleTrashRefreshId); /* Icon */ this._icon.disconnect(this._iconAllocationId); if (this._iconAllocationIdleId) GLib.source_remove(this._iconAllocationIdleId); if (this._longPressTimeoutId) GLib.source_remove(this._longPressTimeoutId); delete this._longPressTimeoutId; /* Menu */ this._removeMenu(); } _refreshMetadataAsync(rebuild) { if (this._queryFileInfoCancellable) this._queryFileInfoCancellable.cancel(); this._queryFileInfoCancellable = new Gio.Cancellable(); this._file.query_info_async(DesktopIconsUtil.DEFAULT_ATTRIBUTES, Gio.FileQueryInfoFlags.NONE, GLib.PRIORITY_DEFAULT, this._queryFileInfoCancellable, (source, result) => { try { let newFileInfo = source.query_info_finish(result); this._queryFileInfoCancellable = null; this._updateMetadataFromFileInfo(newFileInfo); if (rebuild) this._recreateMenu(); this._updateIcon(); } catch(error) { if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) global.log("Error getting the file info: " + error); } }); } _updateMetadataFromFileInfo(fileInfo) { this._fileInfo = fileInfo; let oldLabelText = this._label.text; this._displayName = fileInfo.get_attribute_as_string('standard::display-name'); this._attributeCanExecute = fileInfo.get_attribute_boolean('access::can-execute'); this._unixmode = fileInfo.get_attribute_uint32('unix::mode'); this._writableByOthers = (this._unixmode & S_IWOTH) != 0; this._trusted = fileInfo.get_attribute_as_string('metadata::trusted') == 'true'; this._attributeContentType = fileInfo.get_content_type(); this._isDesktopFile = this._attributeContentType == 'application/x-desktop'; if (this._isDesktopFile && this._writableByOthers) log(`desktop-icons: File ${this._displayName} is writable by others - will not allow launching`); if (this._isDesktopFile) { this._desktopFile = Gio.DesktopAppInfo.new_from_filename(this._file.get_path()); if (!this._desktopFile) { log(`Couldnāt parse ${this._displayName} as a desktop file, will treat it as a regular file.`); this._isValidDesktopFile = false; } else { this._isValidDesktopFile = true; } } else { this._isValidDesktopFile = false; } if (this.displayName != oldLabelText) { this._label.text = this.displayName; } this._fileType = fileInfo.get_file_type(); this._isDirectory = this._fileType == Gio.FileType.DIRECTORY; this._isSpecial = this._fileExtra != Prefs.FileType.NONE; this._isHidden = fileInfo.get_is_hidden() | fileInfo.get_is_backup(); this._isSymlink = fileInfo.get_is_symlink(); this._modifiedTime = this._fileInfo.get_attribute_uint64("time::modified"); /* * This is a glib trick to detect broken symlinks. If a file is a symlink, the filetype * points to the final file, unless it is broken; thus if the file type is SYMBOLIC_LINK, * it must be a broken link. * https://developer.gnome.org/gio/stable/GFile.html#g-file-query-info */ this._isBrokenSymlink = this._isSymlink && this._fileType == Gio.FileType.SYMBOLIC_LINK; } onFileRenamed(file) { this._file = file; this._refreshMetadataAsync(false); } _updateIcon() { if (this._fileExtra == Prefs.FileType.USER_DIRECTORY_TRASH) { this._icon.child = this._createEmblemedStIcon(this._fileInfo.get_icon(), null); return; } if (this._fileExtra == Prefs.FileType.MOUNT_DISK) { this._icon.child = this._createEmblemedStIcon(this._mount.get_icon(), null); return; } let thumbnailFactory = GnomeDesktop.DesktopThumbnailFactory.new(GnomeDesktop.DesktopThumbnailSize.LARGE); if ((Prefs.nautilusSettings.get_string('show-image-thumbnails') != 'never') && (thumbnailFactory.can_thumbnail(this._file.get_uri(), this._attributeContentType, this._modifiedTime))) { let thumbnail = thumbnailFactory.lookup(this._file.get_uri(), this._modifiedTime); if (thumbnail == null) { if (!thumbnailFactory.has_valid_failed_thumbnail(this._file.get_uri(), this._modifiedTime)) { let argv = []; argv.push(GLib.build_filenamev([ExtensionUtils.getCurrentExtension().path, 'createThumbnail.js'])); argv.push(this._file.get_path()); let [success, pid] = GLib.spawn_async(null, argv, null, GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, null); if (this._thumbnailScriptWatch) GLib.source_remove(this._thumbnailScriptWatch); this._thumbnailScriptWatch = GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, (pid, exitCode) => { this._thumbnailScriptWatch = 0; if (exitCode == 0) this._updateIcon(); else global.log('Failed to generate thumbnail for ' + this._filePath); GLib.spawn_close_pid(pid); return false; } ); } } else { if (this._loadThumbnailDataCancellable) this._loadThumbnailDataCancellable.cancel(); this._loadThumbnailDataCancellable = new Gio.Cancellable(); let thumbnailFile = Gio.File.new_for_path(thumbnail); thumbnailFile.load_bytes_async(this._loadThumbnailDataCancellable, (source, result) => { try { this._loadThumbnailDataCancellable = null; let [thumbnailData, etag_out] = source.load_bytes_finish(result); let thumbnailStream = Gio.MemoryInputStream.new_from_bytes(thumbnailData); let thumbnailPixbuf = GdkPixbuf.Pixbuf.new_from_stream(thumbnailStream, null); if (thumbnailPixbuf != null) { let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; let thumbnailImage = new Clutter.Image(); thumbnailImage.set_data(thumbnailPixbuf.get_pixels(), thumbnailPixbuf.has_alpha ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888, thumbnailPixbuf.width, thumbnailPixbuf.height, thumbnailPixbuf.rowstride ); let icon = new Clutter.Actor(); icon.set_content(thumbnailImage); let containerWidth = (this._icon.allocation.x2 - this._icon.allocation.x1) * scaleFactor; let containerHeight = Prefs.get_icon_size() * scaleFactor; let containerAspectRatio = containerWidth / containerHeight; let iconAspectRatio = thumbnailPixbuf.width / thumbnailPixbuf.height; if (containerAspectRatio > iconAspectRatio) { let iconWidth = containerHeight * iconAspectRatio; icon.set_size(iconWidth, containerHeight); let margin = (containerWidth - iconWidth) / 2; icon.margin_left = Math.ceil(margin); icon.margin_right = Math.floor(margin); } else { let iconHeight = containerWidth / iconAspectRatio; icon.set_size(containerWidth, iconHeight); let margin = (containerHeight - iconHeight) / 2; icon.margin_top = Math.ceil(margin); icon.margin_bottom = Math.floor(margin); } this._icon.child = icon; } } catch (error) { if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { global.log('Error while loading thumbnail: ' + error); this._icon.child = this._createEmblemedStIcon(this._fileInfo.get_icon(), null); } } } ); } } if (this._isBrokenSymlink) { this._icon.child = this._createEmblemedStIcon(null, 'text-x-generic'); } else { if (this.trustedDesktopFile && this._desktopFile.has_key('Icon')) this._icon.child = this._createEmblemedStIcon(null, this._desktopFile.get_string('Icon')); else this._icon.child = this._createEmblemedStIcon(this._fileInfo.get_icon(), null); } } _refreshTrashIcon() { if (this._queryTrashInfoCancellable) this._queryTrashInfoCancellable.cancel(); this._queryTrashInfoCancellable = new Gio.Cancellable(); this._file.query_info_async(DesktopIconsUtil.DEFAULT_ATTRIBUTES, Gio.FileQueryInfoFlags.NONE, GLib.PRIORITY_DEFAULT, this._queryTrashInfoCancellable, (source, result) => { try { this._fileInfo = source.query_info_finish(result); this._queryTrashInfoCancellable = null; this._updateIcon(); } catch(error) { if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) global.log('Error getting the number of files in the trash: ' + error); } }); this._scheduleTrashRefreshId = 0; return false; } get file() { return this._file; } get isHidden() { return this._isHidden; } _createEmblemedStIcon(icon, iconName) { if (icon == null) { if (GLib.path_is_absolute(iconName)) { let iconFile = Gio.File.new_for_commandline_arg(iconName); icon = new Gio.FileIcon({ file: iconFile }); } else { icon = Gio.ThemedIcon.new_with_default_fallbacks(iconName); } } let itemIcon = Gio.EmblemedIcon.new(icon, null); if (this._isSymlink) { if (this._isBrokenSymlink) itemIcon.add_emblem(Gio.Emblem.new(Gio.ThemedIcon.new('emblem-unreadable'))); else itemIcon.add_emblem(Gio.Emblem.new(Gio.ThemedIcon.new('emblem-symbolic-link'))); } else if (this.trustedDesktopFile) { itemIcon.add_emblem(Gio.Emblem.new(Gio.ThemedIcon.new('emblem-symbolic-link'))); } return new St.Icon({ gicon: itemIcon, icon_size: Prefs.get_icon_size() }); } doRename() { if (!this.canRename()) { log (`Error: ${this.file.get_uri()} cannot be renamed`); return; } this.emit('rename-clicked'); } _doOpenContext(context) { if (this._isBrokenSymlink) { log(`Error: Canāt open ${this.file.get_uri()} because it is a broken symlink.`); return; } if (this.trustedDesktopFile) { this._desktopFile.launch_uris_as_manager([], context, GLib.SpawnFlags.SEARCH_PATH, null, null); return; } if (this._attributeCanExecute && !this._isDirectory && !this._isValidDesktopFile && Gio.content_type_can_be_executable(this._attributeContentType)) { if (this._execLine) Util.spawnCommandLine(this._execLine); return; } Gio.AppInfo.launch_default_for_uri_async(this.file.get_uri(), null, null, (source, result) => { try { Gio.AppInfo.launch_default_for_uri_finish(result); } catch (e) { log('Error opening file ' + this.file.get_uri() + ': ' + e.message); } } ); } doOpen() { this._doOpenContext(null); } _doDiscreteGpu() { let gpus = Extension.desktopManager.switcherooProxyGPUs; if (!gpus) { log('Could not apply discrete GPU environment, no GPUs in list'); } for (let gpu in gpus) { if (!gpus[gpu]) continue; let default_variant = gpus[gpu].lookup_value('Default', null); if (!default_variant || default_variant.get_boolean()) continue; let env = gpus[gpu].lookup_value('Environment', null); if (!env) continue; let env_s = env.get_strv(); let context = new Gio.AppLaunchContext; for (let i = 0; i < env_s.length; i=i+2) { context.setenv(env_s[i], env_s[i+1]); } this._doOpenContext(context); return; } log('Could not find discrete GPU data in switcheroo-control'); } _onCopyClicked() { Extension.desktopManager.doCopy(); } _onCutClicked() { Extension.desktopManager.doCut(); } _onShowInFilesClicked() { DBusUtils.FreeDesktopFileManagerProxy.ShowItemsRemote([this.file.get_uri()], '', (result, error) => { if (error) log('Error showing file on desktop: ' + error.message); } ); } _onPropertiesClicked() { DBusUtils.FreeDesktopFileManagerProxy.ShowItemPropertiesRemote([this.file.get_uri()], '', (result, error) => { if (error) log('Error showing properties: ' + error.message); } ); } _onMoveToTrashClicked() { Extension.desktopManager.doTrash(); } _onEmptyTrashClicked() { Extension.desktopManager.doEmptyTrash(); } _onEjectClicked() { DesktopIconsUtil.eject(this._mount); } get _allowLaunchingText() { if (this.trustedDesktopFile) return _("Donāt Allow Launching"); return _("Allow Launching"); } get metadataTrusted() { return this._trusted; } set metadataTrusted(value) { this._trusted = value; let info = new Gio.FileInfo(); info.set_attribute_string('metadata::trusted', value ? 'true' : 'false'); this._file.set_attributes_async(info, Gio.FileQueryInfoFlags.NONE, GLib.PRIORITY_LOW, null, (source, result) => { try { source.set_attributes_finish(result); this._refreshMetadataAsync(true); } catch(e) { log(`Failed to set metadata::trusted: ${e.message}`); } }); } _onAllowDisallowLaunchingClicked() { this.metadataTrusted = !this.trustedDesktopFile; /* * we're marking as trusted, make the file executable too. note that we * do not ever remove the executable bit, since we don't know who set * it. */ if (this.metadataTrusted && !this._attributeCanExecute) { let info = new Gio.FileInfo(); let newUnixMode = this._unixmode | S_IXUSR; info.set_attribute_uint32(Gio.FILE_ATTRIBUTE_UNIX_MODE, newUnixMode); this._file.set_attributes_async(info, Gio.FileQueryInfoFlags.NONE, GLib.PRIORITY_LOW, null, (source, result) => { try { source.set_attributes_finish (result); } catch(e) { log(`Failed to set unix mode: ${e.message}`); } }); } } canRename() { return !this.trustedDesktopFile && this._fileExtra == Prefs.FileType.NONE; } _doOpenWith() { DBusUtils.openFileWithOtherApplication(this.file.get_path()); } get menu() { return this._menu; } _removeMenu() { if (this._menu != null) { if (this._menuManager != null) this._menuManager.removeMenu(this._menu); Main.layoutManager.uiGroup.remove_child(this._menu.actor); this._menu.destroy(); this._menu = null; } this._menuManager = null; } _recreateMenu() { this._removeMenu(); this._menuManager = new PopupMenu.PopupMenuManager(this); let side = St.Side.LEFT; if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) side = St.Side.RIGHT; this._menu = new PopupMenu.PopupMenu(this, 0.5, side); this._menu.addAction(_('Open'), () => this.doOpen()); switch (this._fileExtra) { case Prefs.FileType.NONE: if (!this._isDirectory) { this._actionOpenWith = this._menu.addAction(_('Open With Other Application'), () => this._doOpenWith()); if (Extension.desktopManager.discreteGpuAvailable && this.trustedDesktopFile) this._menu.addAction(_('Launch using Dedicated Graphics Card'), () => this._doDiscreteGpu()); } else { this._actionOpenWith = null; } this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this._actionCut = this._menu.addAction(_('Cut'), () => this._onCutClicked()); this._actionCopy = this._menu.addAction(_('Copy'), () => this._onCopyClicked()); if (this.canRename()) this._menu.addAction(_('Renameā¦'), () => this.doRename()); this._actionTrash = this._menu.addAction(_('Move to Trash'), () => this._onMoveToTrashClicked()); if (this._isValidDesktopFile && !Extension.desktopManager.writableByOthers && !this._writableByOthers) { this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this._allowLaunchingMenuItem = this._menu.addAction(this._allowLaunchingText, () => this._onAllowDisallowLaunchingClicked()); } break; case Prefs.FileType.USER_DIRECTORY_TRASH: this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this._menu.addAction(_('Empty Trash'), () => this._onEmptyTrashClicked()); break; case Prefs.FileType.MOUNT_DISK: this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this._menu.addAction(_('Eject'), () => this._onEjectClicked()); break; default: break; } this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this._menu.addAction(_('Properties'), () => this._onPropertiesClicked()); this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this._menu.addAction(_('Show in Files'), () => this._onShowInFilesClicked()); if (this._isDirectory && this.file.get_path() != null) this._actionOpenInTerminal = this._menu.addAction(_('Open in Terminal'), () => this._onOpenTerminalClicked()); this._menuManager.addMenu(this._menu); Main.layoutManager.uiGroup.add_child(this._menu.actor); this._menu.actor.hide(); } _ensureMenu() { if (this._menu == null) this._recreateMenu(); return this._menu; } _onOpenTerminalClicked () { DesktopIconsUtil.launchTerminal(this.file.get_path()); } _updateClickState(event) { const eventType = event.type(); const isButton = eventType === Clutter.EventType.BUTTON_PRESS || eventType === Clutter.EventType.BUTTON_RELEASE; const button = isButton ? event.get_button() : 0; const time = event.get_time(); let settings = Clutter.Settings.get_default(); if (button === this._lastClickButton && (time - this._lastClickTime) < settings.double_click_time) this._clickCount++; else this._clickCount = 1; this._lastClickTime = time; this._lastClickButton = button; } _getClickCount() { return this._clickCount; } _handlePressEvent(event) { const pressSequence = event.get_event_sequence(); if (this._pressSequence && pressSequence?.get_slot() !== this._pressSequence.get_slot()) return Clutter.EVENT_PROPAGATE; this._primaryButtonPressed = true; this._pressSequence = pressSequence; this._pressDevice = event.get_device(); if (this._getClickCount() !== 1) return Clutter.EVENT_STOP; const [x, y] = event.get_coords(); this._buttonPressInitialX = x; this._buttonPressInitialY = y; const shiftPressed = !!(event.get_state() & Clutter.ModifierType.SHIFT_MASK); const controlPressed = !!(event.get_state() & Clutter.ModifierType.CONTROL_MASK); if (controlPressed || shiftPressed) this.emit('selected', true, false, !this._isSelected); else if (!this._isSelected) this.emit('selected', false, false, true); return Clutter.EVENT_STOP; } _handleSecondaryPress() { if (!this.isSelected) this.emit('selected', false, false, true); this._ensureMenu().toggle(); if (this._actionOpenWith) { let allowOpenWith = Extension.desktopManager.getNumberOfSelectedItems() === 1; this._actionOpenWith.setSensitive(allowOpenWith); } const specialFilesSelected = Extension.desktopManager.checkIfSpecialFilesAreSelected(); if (this._actionCut) this._actionCut.setSensitive(!specialFilesSelected); if (this._actionCopy) this._actionCopy.setSensitive(!specialFilesSelected); if (this._actionTrash) this._actionTrash.setSensitive(!specialFilesSelected); return Clutter.EVENT_STOP; } _handleReleaseEvent(event) { if (this._longPressTimeoutId) GLib.source_remove(this._longPressTimeoutId); delete this._longPressTimeoutId; if (!this._primaryButtonPressed || this._pressDevice !== event.get_device()) return Clutter.EVENT_PROPAGATE; const pressSequence = event.get_event_sequence(); if (this._pressSequence && pressSequence?.get_slot() !== this._pressSequence.get_slot()) return Clutter.EVENT_PROPAGATE; // primaryButtonPressed is TRUE only if the user has pressed the button // over an icon, and if (s)he has not started a drag&drop operation this._primaryButtonPressed = false; delete this._pressDevice; delete this._pressSequence; let shiftPressed = !!(event.get_state() & Clutter.ModifierType.SHIFT_MASK); let controlPressed = !!(event.get_state() & Clutter.ModifierType.CONTROL_MASK); if (!controlPressed && !shiftPressed) this.emit('selected', false, false, true); if (this._getClickCount() === 1 && Prefs.CLICK_POLICY_SINGLE && !shiftPressed && !controlPressed) this.doOpen(); if (this._getClickCount() === 2 && !Prefs.CLICK_POLICY_SINGLE) this.doOpen(); return Clutter.EVENT_STOP; } _onTouchEvent(actor, event) { // on X11, let pointer emulation deal with touch if (!Meta.is_wayland_compositor()) return Clutter.EVENT_PROPAGATE; const type = event.type(); if (type === Clutter.EventType.TOUCH_BEGIN) { Extension.desktopManager.endRubberBand(); this._updateClickState(event); if (!this._handlePressEvent(event)) return Clutter.EVENT_PROPAGATE; const { longPressDuration } = Clutter.Settings.get_default(); this._longPressTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, longPressDuration, () => { this._handleSecondaryPress(); delete this._longPressTimeoutId; return GLib.SOURCE_REMOVE; }); return Clutter.EVENT_STOP; } else if (type === Clutter.EventType.TOUCH_END) { return this._handleReleaseEvent(event); } return Clutter.EVENT_PROPAGATE; } _onPressButton(actor, event) { Extension.desktopManager.endRubberBand(); this._updateClickState(event); let button = event.get_button(); if (button == 3) return this._handleSecondaryPress(); if (button == 1) return this._handlePressEvent(event); return Clutter.EVENT_PROPAGATE; } _onEnter(actor, event) { if (Prefs.CLICK_POLICY_SINGLE) global.display.set_cursor(Meta.Cursor.POINTING_HAND); else global.display.set_cursor(Meta.Cursor.DEFAULT); } _onLeave(actor, event) { this._primaryButtonPressed = false; if (Prefs.CLICK_POLICY_SINGLE) global.display.set_cursor(Meta.Cursor.DEFAULT); } _onMotion(actor, event) { let [x, y] = event.get_coords(); if (this._primaryButtonPressed) { let xDiff = x - this._buttonPressInitialX; let yDiff = y - this._buttonPressInitialY; let distance = Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2)); if (distance > DRAG_TRESHOLD) { // Don't need to track anymore this if we start drag, and also // avoids reentrance here this._primaryButtonPressed = false; let event = Clutter.get_current_event(); let [x, y] = event.get_coords(); Extension.desktopManager.dragStart(); } } return Clutter.EVENT_PROPAGATE; } _onReleaseButton(actor, event) { let button = event.get_button(); if (button == 1) return this._handleReleaseEvent(event); return Clutter.EVENT_PROPAGATE; } get savedCoordinates() { return this._savedCoordinates; } _onSetMetadataFileFinished(source, result) { try { let [success, info] = source.set_attributes_finish(result); } catch (error) { if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) log(`Error setting metadata to desktop files ${error}`); } } set savedCoordinates(pos) { if (this._setMetadataCancellable) this._setMetadataCancellable.cancel(); this._setMetadataCancellable = new Gio.Cancellable(); this._savedCoordinates = [pos[0], pos[1]]; let info = new Gio.FileInfo(); info.set_attribute_string('metadata::nautilus-icon-position', `${pos[0]},${pos[1]}`); this.file.set_attributes_async(info, Gio.FileQueryInfoFlags.NONE, GLib.PRIORITY_DEFAULT, this._setMetadataCancellable, (source, result) => { this._setMetadataCancellable = null; this._onSetMetadataFileFinished(source, result); } ); } intersectsWith(argX, argY, argWidth, argHeight) { let rect = new Meta.Rectangle({ x: argX, y: argY, width: argWidth, height: argHeight }); let [containerX, containerY] = this._container.get_transformed_position(); let boundingBox = new Meta.Rectangle({ x: containerX, y: containerY, width: this._container.allocation.x2 - this._container.allocation.x1, height: this._container.allocation.y2 - this._container.allocation.y1 }); let [intersects, _] = rect.intersect(boundingBox); return intersects; } set isSelected(isSelected) { isSelected = !!isSelected; if (isSelected == this._isSelected) return; if (isSelected) this._container.add_style_pseudo_class('selected'); else this._container.remove_style_pseudo_class('selected'); this._isSelected = isSelected; } get isSelected() { return this._isSelected; } get isSpecial() { return this._isSpecial; } get state() { return this._state; } set state(state) { if (state == this._state) return; this._state = state; } get isDirectory() { return this._isDirectory; } get trustedDesktopFile() { return this._isValidDesktopFile && this._attributeCanExecute && this.metadataTrusted && !Extension.desktopManager.writableByOthers && !this._writableByOthers; } get fileName() { return this._fileInfo.get_name(); } get displayName() { if (this._fileExtra == Prefs.FileType.USER_DIRECTORY_HOME) return _("Home"); if (this.trustedDesktopFile) return this._desktopFile.get_name(); return this._displayName || null; } acceptDrop() { return Extension.desktopManager.selectionDropOnFileItem(this); } });
Save
Cancel