/* DING: Desktop Icons New Generation for GNOME Shell * * Adw-DING Copyright (C) 2022, 2025 Sundeep Mediratta (smedius@gmail.com) * Based on code original (C) Carlos Soriano and (c) Sergio Costas * * 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, version 3 of the License. * * 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 . */ import {Gdk, Gio, GLib, DesktopAppInfo} from '../dependencies/gi.js'; import {FileItemIcon} from '../dependencies/localFiles.js'; import {_} from '../dependencies/gettext.js'; export {DesktopFileIcon}; const DesktopFileIcon = class extends FileItemIcon { _updateMetadataFromFileInfo(fileInfo) { super._updateMetadataFromFileInfo(fileInfo); this._isDesktopFile = this._attributeContentType === 'application/x-desktop'; if (this._isDesktopFile && this._writableByOthers) { console.log( `desktop-icons: File ${this._displayName} is writable` + 'by others - will not allow launching' ); } if (this._isDesktopFile) { try { this._desktopFile = DesktopAppInfo.new_from_filename( this._file.get_path() ); if (!this._desktopFile) { console.log( `Couldn’t parse ${this._displayName} as a desktop` + ' file, will treat it as a regular file.' ); this._isValidDesktopFile = false; } else { this._isValidDesktopFile = true; } } catch (e) { console.log(`Error reading Desktop file ${this.uri}: ${e}`); } } else { this._isValidDesktopFile = false; } if (this._isValidDesktopFile) this._execLine = null; this._trusted = fileInfo.get_attribute_as_string('metadata::trusted') === 'true'; this._getActions(); } _getActions() { if (!this.trustedDesktopFile) return; this.desktopAppInfo = DesktopAppInfo.new_from_filename(this.path); this.actionMap = new Map(); const actions = this.desktopAppInfo.list_actions(); actions.forEach(action => { const actionName = this.desktopAppInfo.get_action_name(action); this.actionMap.set(actionName, action); }); } _makeActionMenu() { this._actionmenu = Gio.Menu.new(); for (const [actionName, action] of this.actionMap) { const variant = new GLib.Variant('as', [this.path, actionName, action]); const menuItem = Gio.MenuItem.new(actionName, null); menuItem.set_action_and_target_value('app.desktopAction', variant); this._actionmenu.append_item(menuItem); } } getMenu() { if (!this.hasActions) return null; this._makeActionMenu(); return this._actionmenu; } async _doOpenContext(context, fileList = []) { if (this._isDesktopFile) { try { this._launchDesktopFile(context, fileList); } catch (e) {} return; } await super._doOpenContext(context, fileList); } _launchDesktopFile(context, fileList) { if (this._desktopManager.writableByOthers) { const title = _('The Displayed Desktop is writable by others'); const error = _( '.deskop files cannot be launched from this Desktop' + ' as the Desktop Folder is writable by other users.\n\n' + 'Please check the permissions of this Desktop Folder,' + ' and make sure it is not writable by others.' ); this._showerrorpopup(title, error); return; } if (!this._isValidDesktopFile) { const title = _('Broken Desktop File'); const error = _( 'This .desktop file has errors or points to a program' + ' without permissions. It can not be executed.\n\n' + 'Edit the file to set the correct executable Program.' ); this._showerrorpopup(title, error); return; } if (this._writableByOthers || !this._attributeCanExecute) { const title = _('Invalid Permissions on Desktop File'); const a = _('This Desktop File has incorrect Permissions.'); const aa = _('Right Click to edit Properties, then:'); let error = `${a} ${aa}\n`; const b = _('Set Permissions, in'); const c = _('Others Access'); const d = _('Read Only'); const e = _('or'); const f = _('None'); const g = _('Enable option'); const h = _('Allow Executing File as a Program'); if (this._writableByOthers) error += `\n${b} "${c}", "${d}" ${e} "${f}"`; if (!this._attributeCanExecute) error += `\n${g}, "${h}"`; this._showerrorpopup(title, error); return; } if (!this.trustedDesktopFile) { const title = _('Untrusted Desktop File'); const a = _('This Desktop file is not trusted, it can not be launched.'); const b = _('To enable launching, right-click, then:'); const c = _('enable'); const d = _('Allow Launching'); const error = `${a} ${b}\n\n${c} "${d}"`; this._showerrorpopup(title, error); return; } let object = this.DesktopIconsUtil.checkAppOpensFileType( this._desktopFile, fileList[0], null ); if (this.trustedDesktopFile && (!fileList.length || object.canopenFile) ) { this._desktopFile.launch_uris_as_manager( fileList, context, GLib.SpawnFlags.SEARCH_PATH, null, null ); } else if (this.trustedDesktopFile && !object.canopenFile) { const Appname = object.Appname; const title = _('Could not open File'); const error = _('{appName} can not open files of this Type!') .replace('{appName}', Appname); this._showerrorpopup(title, error); } } _updateName() { if (this._isValidDesktopFile && !this._desktopManager.writableByOthers && !this._writableByOthers && this.trustedDesktopFile ) this._setFileName(this._desktopFile.get_locale_string('Name')); else this._setFileName(this._getVisibleName()); this._setAccesibilityName(); } _handleDroppedUris( X, Y, x, y, fileList, _gdkDropAction, _localDrop, _event ) { if (this._isValidDesktopFile) { // open the desktop file with these dropped files as the arguments this.doOpen(fileList); return Gdk.DragAction.COPY; } else { return false; } } _dropCapable() { if (this._isValidDesktopFile) return true; else return false; } _addEmblemsToIconIfNeeded(iconPaintable, position = 0) { let emblem = null; let newIconPaintable = iconPaintable; if (this._isDesktopFile && (!this._isValidDesktopFile || !this.trustedDesktopFile) ) { emblem = Gio.ThemedIcon.new('icon-emblem-unreadable'); newIconPaintable = this._addEmblem(newIconPaintable, emblem, position); position += 1; } return super._addEmblemsToIconIfNeeded(newIconPaintable, position); } async onAllowDisallowLaunchingClicked() { if (this._isDesktopFile) this.metadataTrusted = !this.trustedDesktopFile; await super.onAllowDisallowLaunchingClicked(); } get canRename() { return !this.trustedDesktopFile; } get displayName() { if (this.trustedDesktopFile) return this._desktopFile.get_name(); return super.displayName; } get isDesktopFile() { return this._isDesktopFile; } get trustedDesktopFile() { return this._isValidDesktopFile && this._attributeCanExecute && this.metadataTrusted && !this._desktopManager.writableByOthers && !this._writableByOthers; } get isValidDesktopFile() { return this._isValidDesktopFile; } get hasActions() { return this.trustedDesktopFile && this.actionMap.size > 0; } };