
We already include an .editorconfig that is supported by many editors, including emacs, so no need to repeat an emacs-specific modeline in every source file. Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3431>
223 lines
7.5 KiB
JavaScript
223 lines
7.5 KiB
JavaScript
import * as MessageTray from './messageTray.js';
|
||
import Shell from 'gi://Shell';
|
||
import * as ParentalControlsManager from '../misc/parentalControlsManager.js';
|
||
import * as Signals from '../misc/signals.js';
|
||
|
||
// In alphabetical order
|
||
const RENAMED_DESKTOP_IDS = {
|
||
'baobab.desktop': 'org.gnome.baobab.desktop',
|
||
'cheese.desktop': 'org.gnome.Cheese.desktop',
|
||
'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
|
||
'empathy.desktop': 'org.gnome.Empathy.desktop',
|
||
'eog.desktop': 'org.gnome.eog.desktop',
|
||
'epiphany.desktop': 'org.gnome.Epiphany.desktop',
|
||
'evolution.desktop': 'org.gnome.Evolution.desktop',
|
||
'file-roller.desktop': 'org.gnome.FileRoller.desktop',
|
||
'five-or-more.desktop': 'org.gnome.five-or-more.desktop',
|
||
'four-in-a-row.desktop': 'org.gnome.Four-in-a-row.desktop',
|
||
'gcalctool.desktop': 'org.gnome.Calculator.desktop',
|
||
'geary.desktop': 'org.gnome.Geary.desktop',
|
||
'gedit.desktop': 'org.gnome.gedit.desktop',
|
||
'glchess.desktop': 'org.gnome.Chess.desktop',
|
||
'glines.desktop': 'org.gnome.five-or-more.desktop',
|
||
'gnect.desktop': 'org.gnome.Four-in-a-row.desktop',
|
||
'gnibbles.desktop': 'org.gnome.Nibbles.desktop',
|
||
'gnobots2.desktop': 'org.gnome.Robots.desktop',
|
||
'gnome-boxes.desktop': 'org.gnome.Boxes.desktop',
|
||
'gnome-calculator.desktop': 'org.gnome.Calculator.desktop',
|
||
'gnome-chess.desktop': 'org.gnome.Chess.desktop',
|
||
'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
|
||
'gnome-contacts.desktop': 'org.gnome.Contacts.desktop',
|
||
'gnome-documents.desktop': 'org.gnome.Documents.desktop',
|
||
'gnome-font-viewer.desktop': 'org.gnome.font-viewer.desktop',
|
||
'gnome-klotski.desktop': 'org.gnome.Klotski.desktop',
|
||
'gnome-nibbles.desktop': 'org.gnome.Nibbles.desktop',
|
||
'gnome-mahjongg.desktop': 'org.gnome.Mahjongg.desktop',
|
||
'gnome-mines.desktop': 'org.gnome.Mines.desktop',
|
||
'gnome-music.desktop': 'org.gnome.Music.desktop',
|
||
'gnome-photos.desktop': 'org.gnome.Photos.desktop',
|
||
'gnome-robots.desktop': 'org.gnome.Robots.desktop',
|
||
'gnome-screenshot.desktop': 'org.gnome.Screenshot.desktop',
|
||
'gnome-software.desktop': 'org.gnome.Software.desktop',
|
||
'gnome-terminal.desktop': 'org.gnome.Terminal.desktop',
|
||
'gnome-tetravex.desktop': 'org.gnome.Tetravex.desktop',
|
||
'gnome-tweaks.desktop': 'org.gnome.tweaks.desktop',
|
||
'gnome-weather.desktop': 'org.gnome.Weather.desktop',
|
||
'gnomine.desktop': 'org.gnome.Mines.desktop',
|
||
'gnotravex.desktop': 'org.gnome.Tetravex.desktop',
|
||
'gnotski.desktop': 'org.gnome.Klotski.desktop',
|
||
'gtali.desktop': 'org.gnome.Tali.desktop',
|
||
'iagno.desktop': 'org.gnome.Reversi.desktop',
|
||
'nautilus.desktop': 'org.gnome.Nautilus.desktop',
|
||
'org.gnome.gnome-2048.desktop': 'org.gnome.TwentyFortyEight.desktop',
|
||
'org.gnome.taquin.desktop': 'org.gnome.Taquin.desktop',
|
||
'org.gnome.Weather.Application.desktop': 'org.gnome.Weather.desktop',
|
||
'polari.desktop': 'org.gnome.Polari.desktop',
|
||
'seahorse.desktop': 'org.gnome.seahorse.Application.desktop',
|
||
'shotwell.desktop': 'org.gnome.Shotwell.desktop',
|
||
'simple-scan.desktop': 'org.gnome.SimpleScan.desktop',
|
||
'tali.desktop': 'org.gnome.Tali.desktop',
|
||
'totem.desktop': 'org.gnome.Totem.desktop',
|
||
'evince.desktop': 'org.gnome.Evince.desktop',
|
||
};
|
||
|
||
class AppFavorites extends Signals.EventEmitter {
|
||
constructor() {
|
||
super();
|
||
|
||
// Filter the apps through the user’s parental controls.
|
||
this._parentalControlsManager = ParentalControlsManager.getDefault();
|
||
this._parentalControlsManager.connect('app-filter-changed', () => {
|
||
this.reload();
|
||
this.emit('changed');
|
||
});
|
||
|
||
this.FAVORITE_APPS_KEY = 'favorite-apps';
|
||
this._favorites = {};
|
||
global.settings.connect(`changed::${this.FAVORITE_APPS_KEY}`, this._onFavsChanged.bind(this));
|
||
this.reload();
|
||
}
|
||
|
||
_onFavsChanged() {
|
||
this.reload();
|
||
this.emit('changed');
|
||
}
|
||
|
||
reload() {
|
||
let ids = global.settings.get_strv(this.FAVORITE_APPS_KEY);
|
||
let appSys = Shell.AppSystem.get_default();
|
||
|
||
// Map old desktop file names to the current ones
|
||
let updated = false;
|
||
ids = ids.map(id => {
|
||
let newId = RENAMED_DESKTOP_IDS[id];
|
||
if (newId !== undefined &&
|
||
appSys.lookup_app(newId) != null) {
|
||
updated = true;
|
||
return newId;
|
||
}
|
||
return id;
|
||
});
|
||
// ... and write back the updated desktop file names
|
||
if (updated)
|
||
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
|
||
|
||
let apps = ids.map(id => appSys.lookup_app(id))
|
||
.filter(app => app !== null && this._parentalControlsManager.shouldShowApp(app.app_info));
|
||
this._favorites = {};
|
||
for (let i = 0; i < apps.length; i++) {
|
||
let app = apps[i];
|
||
this._favorites[app.get_id()] = app;
|
||
}
|
||
}
|
||
|
||
_getIds() {
|
||
let ret = [];
|
||
for (let id in this._favorites)
|
||
ret.push(id);
|
||
return ret;
|
||
}
|
||
|
||
getFavoriteMap() {
|
||
return this._favorites;
|
||
}
|
||
|
||
getFavorites() {
|
||
let ret = [];
|
||
for (let id in this._favorites)
|
||
ret.push(this._favorites[id]);
|
||
return ret;
|
||
}
|
||
|
||
isFavorite(appId) {
|
||
return appId in this._favorites;
|
||
}
|
||
|
||
_addFavorite(appId, pos) {
|
||
if (appId in this._favorites)
|
||
return false;
|
||
|
||
let app = Shell.AppSystem.get_default().lookup_app(appId);
|
||
|
||
if (!app)
|
||
return false;
|
||
|
||
if (!this._parentalControlsManager.shouldShowApp(app.app_info))
|
||
return false;
|
||
|
||
let ids = this._getIds();
|
||
if (pos === -1)
|
||
ids.push(appId);
|
||
else
|
||
ids.splice(pos, 0, appId);
|
||
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
|
||
return true;
|
||
}
|
||
|
||
addFavoriteAtPos(appId, pos) {
|
||
if (!this._addFavorite(appId, pos))
|
||
return;
|
||
|
||
const app = Shell.AppSystem.get_default().lookup_app(appId);
|
||
|
||
this._showNotification(_('%s has been pinned to the dash.').format(app.get_name()),
|
||
null,
|
||
() => this._removeFavorite(appId));
|
||
}
|
||
|
||
addFavorite(appId) {
|
||
this.addFavoriteAtPos(appId, -1);
|
||
}
|
||
|
||
moveFavoriteToPos(appId, pos) {
|
||
this._removeFavorite(appId);
|
||
this._addFavorite(appId, pos);
|
||
}
|
||
|
||
_removeFavorite(appId) {
|
||
if (!(appId in this._favorites))
|
||
return false;
|
||
|
||
let ids = this._getIds().filter(id => id !== appId);
|
||
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
|
||
return true;
|
||
}
|
||
|
||
removeFavorite(appId) {
|
||
let ids = this._getIds();
|
||
let pos = ids.indexOf(appId);
|
||
|
||
let app = this._favorites[appId];
|
||
if (!this._removeFavorite(appId))
|
||
return;
|
||
|
||
this._showNotification(_('%s has been unpinned from the dash.').format(app.get_name()),
|
||
null,
|
||
() => this._addFavorite(appId, pos));
|
||
}
|
||
|
||
_showNotification(title, body, undoCallback) {
|
||
const source = MessageTray.getSystemSource();
|
||
const notification = new MessageTray.Notification({
|
||
source,
|
||
title,
|
||
body,
|
||
isTransient: true,
|
||
forFeedback: true,
|
||
});
|
||
notification.addAction(_('Undo'), () => undoCallback());
|
||
source.addNotification(notification);
|
||
}
|
||
}
|
||
|
||
var appFavoritesInstance = null;
|
||
|
||
/**
|
||
* @returns {AppFavorites}
|
||
*/
|
||
export function getAppFavorites() {
|
||
if (appFavoritesInstance == null)
|
||
appFavoritesInstance = new AppFavorites();
|
||
return appFavoritesInstance;
|
||
}
|