gconf-settings/skel/.local/share/gnome-shell/extensions/appfolders-managermaestrosc.../extension.js

446 lines
14 KiB
JavaScript

// extension.js
// GPLv3
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const St = imports.gi.St;
const Main = imports.ui.main;
const AppDisplay = imports.ui.appDisplay;
const PopupMenu = imports.ui.popupMenu;
const Meta = imports.gi.Meta;
const Mainloop = imports.mainloop;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;
const AppfolderDialog = Me.imports.appfolderDialog;
const DragAndDrop = Me.imports.dragAndDrop;
const Gettext = imports.gettext.domain('appfolders-manager');
const _ = Gettext.gettext;
let FOLDER_SCHEMA;
let FOLDER_LIST;
let INIT_TIME;
function init () {
Convenience.initTranslations();
INIT_TIME = getTimeStamp();
}
function getTimeStamp () {
let today = new Date();
let str = today.getDate() + '' + today.getHours() + '' + today.getMinutes()
+ '' + today.getSeconds();
return parseInt(str);
}
//------------------------------------------------------------------------------
/* do not edit this section */
function injectToFunction(parent, name, func) {
let origin = parent[name];
parent[name] = function() {
let ret;
ret = origin.apply(this, arguments);
if (ret === undefined)
ret = func.apply(this, arguments);
return ret;
}
return origin;
}
function removeInjection(object, injection, name) {
if (injection[name] === undefined)
delete object[name];
else
object[name] = injection[name];
}
var injections=[];
//------------------------------------------------------------------------------
/* this function injects items (1 or 2 submenus) in AppIconMenu's _redisplay method. */
function injectionInAppsMenus() {
injections['_redisplay'] = injectToFunction(AppDisplay.AppIconMenu.prototype, '_redisplay', function() {
if (Main.overview.viewSelector.getActivePage() == 2
|| Main.overview.viewSelector.getActivePage() == 3) {
//ok
} else {
return;
}
this._appendSeparator(); //TODO injecter ailleurs dans le menu?
let mainAppView = Main.overview.viewSelector.appDisplay._views[1].view;
FOLDER_LIST = FOLDER_SCHEMA.get_strv('folder-children');
//------------------------------------------------------------------
let addto = new PopupMenu.PopupSubMenuMenuItem(_("Add to"));
let newAppFolder = new PopupMenu.PopupMenuItem('+ ' + _("New AppFolder"));
newAppFolder.connect('activate', () => {
this._source._menuManager._grabHelper.ungrab({ actor: this.actor });
// XXX broken scrolling ??
// We can't popdown the folder immediately because the
// AppDisplay.AppFolderPopup.popdown() method tries to ungrab
// the global focus from the folder's popup actor, which isn't
// having the focus since the menu is still open. Menus' animation
// last ~0.25s so we will wait 0.30s before doing anything.
let a = Mainloop.timeout_add(300, () => {
if (mainAppView._currentPopup) {
mainAppView._currentPopup.popdown();
}
createNewFolder(this._source);
mainAppView._redisplay();
Mainloop.source_remove(a);
});
});
addto.menu.addMenuItem(newAppFolder);
for (var i = 0 ; i < FOLDER_LIST.length ; i++) {
let _folder = FOLDER_LIST[i];
let shouldShow = !isInFolder( this._source.app.get_id(), _folder );
let iFolderSchema = folderSchema(_folder);
let item = new PopupMenu.PopupMenuItem( AppDisplay._getFolderName(iFolderSchema) );
if ( Convenience.getSettings('org.gnome.shell.extensions.appfolders-manager').get_boolean('debug') ) {
shouldShow = true; //TODO ??? et l'exclusion ?
}
if(shouldShow) {
item.connect('activate', () => {
this._source._menuManager._grabHelper.ungrab({ actor: this.actor });
// XXX broken scrolling ??
// We can't popdown the folder immediatly because the
// AppDisplay.AppFolderPopup.popdown() method tries to
// ungrab the global focus from the folder's popup actor,
// which isn't having the focus since the menu is still
// open. Menus' animation last ~0.25s so we will wait 0.30s
// before doing anything.
let a = Mainloop.timeout_add(300, () => {
if (mainAppView._currentPopup) {
mainAppView._currentPopup.popdown();
}
addToFolder(this._source, _folder);
mainAppView._redisplay();
Mainloop.source_remove(a);
});
});
addto.menu.addMenuItem(item);
}
}
this.addMenuItem(addto);
//----------------------------------------------------------------------
let removeFrom = new PopupMenu.PopupSubMenuMenuItem(_("Remove from"));
let shouldShow2 = false;
for (var i = 0 ; i < FOLDER_LIST.length ; i++) {
let _folder = FOLDER_LIST[i];
let appId = this._source.app.get_id();
let shouldShow = isInFolder(appId, _folder);
let iFolderSchema = folderSchema(_folder);
let item = new PopupMenu.PopupMenuItem( AppDisplay._getFolderName(iFolderSchema) );
if ( Convenience.getSettings('org.gnome.shell.extensions.appfolders-manager').get_boolean('debug') ) {
shouldShow = true; //FIXME ??? et l'exclusion ?
}
if(shouldShow) {
item.connect('activate', () => {
this._source._menuManager._grabHelper.ungrab({ actor: this.actor });
// XXX broken scrolling ??
// We can't popdown the folder immediatly because the
// AppDisplay.AppFolderPopup.popdown() method tries to
// ungrab the global focus from the folder's popup actor,
// which isn't having the focus since the menu is still
// open. Menus' animation last ~0.25s so we will wait 0.30s
// before doing anything.
let a = Mainloop.timeout_add(300, () => {
if (mainAppView._currentPopup) {
mainAppView._currentPopup.popdown();
}
removeFromFolder(appId, _folder);
mainAppView._redisplay();
Mainloop.source_remove(a);
});
});
removeFrom.menu.addMenuItem(item);
shouldShow2 = true;
}
}
if (shouldShow2) {
this.addMenuItem(removeFrom);
}
});
}
//------------------------------------------------
function injectionInIcons() {
// Right-click on a FolderIcon launches a new AppfolderDialog
AppDisplay.FolderIcon = class extends AppDisplay.FolderIcon {
constructor (id, path, parentView) {
super(id, path, parentView);
if (!this.isCustom) {
this.actor.connect('button-press-event', this._onButtonPress.bind(this));
}
this.isCustom = true;
}
_onButtonPress (actor, event) {
let button = event.get_button();
if (button == 3) {
let tmp = new Gio.Settings({
schema_id: 'org.gnome.desktop.app-folders.folder',
path: '/org/gnome/desktop/app-folders/folders/' + this.id + '/'
});
let dialog = new AppfolderDialog.AppfolderDialog(tmp, null, this.id);
dialog.open();
}
return Clutter.EVENT_PROPAGATE;
}
};
// Dragging an AppIcon triggers the DND mode
AppDisplay.AppIcon = class extends AppDisplay.AppIcon {
constructor (app, params) {
super(app, params);
if (!this.isCustom) {
this._draggable.connect('drag-begin', this.onDragBeginExt.bind(this));
this._draggable.connect('drag-cancelled', this.onDragCancelledExt.bind(this));
this._draggable.connect('drag-end', this.onDragEndExt.bind(this));
}
this.isCustom = true;
}
onDragBeginExt () {
if (Main.overview.viewSelector.getActivePage() != 2) {
return;
}
this._removeMenuTimeout(); // why ?
Main.overview.beginItemDrag(this);
DragAndDrop.OVERLAY_MANAGER.on_drag_begin();
}
onDragEndExt () {
Main.overview.endItemDrag(this);
DragAndDrop.OVERLAY_MANAGER.on_drag_end();
}
onDragCancelledExt () {
Main.overview.cancelledItemDrag(this);
DragAndDrop.OVERLAY_MANAGER.on_drag_cancelled();
}
};
}
//------------------------------------------------------------------------------
//---------------------------------- Generic -----------------------------------
//--------------------------------- functions ----------------------------------
//------------------------------------------------------------------------------
/* These functions perform the requested actions but do not care about popdowning
* open menu/open folder, nor about hiding/showing/activating dropping areas, nor
* about redisplaying the view.
*/
function removeFromFolder (app_id, folder_id) {
let folder_schema = folderSchema(folder_id);
if ( isInFolder(app_id, folder_id) ) {
let pastContent = folder_schema.get_strv('apps');
let presentContent = [];
for(var i=0; i<pastContent.length; i++){
if(pastContent[i] != app_id) {
presentContent.push(pastContent[i]);
}
}
folder_schema.set_strv('apps', presentContent);
} else {
let content = folder_schema.get_strv('excluded-apps');
content.push(app_id);
folder_schema.set_strv('excluded-apps', content);
}
return true;
}
//------------------------------------------------------------------------------
function deleteFolder (folder_id) {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
let tmp = [];
FOLDER_LIST = FOLDER_SCHEMA.get_strv('folder-children');
for(var j=0;j < FOLDER_LIST.length;j++){
if(FOLDER_LIST[j] != folder_id) {
tmp.push(FOLDER_LIST[j]);
}
}
FOLDER_LIST = tmp;
FOLDER_SCHEMA.set_strv('folder-children', FOLDER_LIST);
// ?? XXX (ne fonctionne pas mieux hors du meta.later_add)
if ( Convenience.getSettings('org.gnome.shell.extensions.appfolders-manager').get_boolean('total-deletion') ) {
let folder_schema = folderSchema (folder_id);
folder_schema.reset('apps'); // génère un bug volumineux ?
folder_schema.reset('categories'); // génère un bug volumineux ?
folder_schema.reset('excluded-apps'); // génère un bug volumineux ?
folder_schema.reset('name'); // génère un bug volumineux ?
}
});
return true;
}
//------------------------------------------------------------------------------
function mergeFolders (folder_staying_id, folder_dying_id) { //unused XXX
let folder_dying_schema = folderSchema (folder_dying_id);
let folder_staying_schema = folderSchema (folder_staying_id);
let newerContent = folder_dying_schema.get_strv('categories');
let presentContent = folder_staying_schema.get_strv('categories');
for(var i=0;i<newerContent.length;i++){
if(presentContent.indexOf(newerContent[i]) == -1) {
presentContent.push(newerContent[i]);
}
}
folder_staying_schema.set_strv('categories', presentContent);
newerContent = folder_dying_schema.get_strv('excluded-apps');
presentContent = folder_staying_schema.get_strv('excluded-apps');
for(var i=0;i<newerContent.length;i++){
if(presentContent.indexOf(newerContent[i]) == -1) {
presentContent.push(newerContent[i]);
}
}
folder_staying_schema.set_strv('excluded-apps', presentContent);
newerContent = folder_dying_schema.get_strv('apps');
presentContent = folder_staying_schema.get_strv('apps');
for(var i=0;i<newerContent.length;i++){
if(presentContent.indexOf(newerContent[i]) == -1) {
// if(!isInFolder(newerContent[i], folder_staying_id)) {
presentContent.push(newerContent[i]);
//TODO utiliser addToFolder malgré ses paramètres chiants
}
}
folder_staying_schema.set_strv('apps', presentContent);
deleteFolder(folder_dying_id);
return true;
}
//------------------------------------------------------------------------------
function createNewFolder (app_source) {
let id = app_source.app.get_id();
let dialog = new AppfolderDialog.AppfolderDialog(null , id);
dialog.open();
return true;
}
//------------------------------------------------------------------------------
function addToFolder (app_source, folder_id) {
let id = app_source.app.get_id();
let folder_schema = folderSchema (folder_id);
//un-exclude the application if it was excluded TODO else don't do it at all
let pastExcluded = folder_schema.get_strv('excluded-apps');
let presentExcluded = [];
for(let i=0; i<pastExcluded.length; i++){
if(pastExcluded[i] != id) {
presentExcluded.push(pastExcluded[i]);
}
}
if (presentExcluded.length > 0) {
folder_schema.set_strv('excluded-apps', presentExcluded);
}
//actually add the app
let content = folder_schema.get_strv('apps');
content.push(id);
folder_schema.set_strv('apps', content); //XXX verbose errors
//update icons in the ugliest possible way
let icons = Main.overview.viewSelector.appDisplay._views[1].view.folderIcons;
for (let i=0; i<icons.length; i++) {
let size = icons[i].icon._iconBin.width;
icons[i].icon.icon = icons[i]._createIcon(size);
icons[i].icon._iconBin.child = icons[i].icon.icon;
}
return true;
}
//------------------------------------------------------------------------------
function isInFolder (app_id, folder_id) {
let folder_schema = folderSchema(folder_id);
let isIn = false;
let content_ = folder_schema.get_strv('apps');
for(var j=0; j<content_.length; j++) {
if(content_[j] == app_id) {
isIn = true;
}
}
return isIn;
}
//------------------------------------------------------------------------------
function folderSchema (folder_id) {
let a = new Gio.Settings({
schema_id: 'org.gnome.desktop.app-folders.folder',
path: '/org/gnome/desktop/app-folders/folders/' + folder_id + '/'
});
return a;
} // TODO et AppDisplay._getFolderName ??
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
function enable() {
FOLDER_SCHEMA = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders' });
FOLDER_LIST = FOLDER_SCHEMA.get_strv('folder-children');
injectionInIcons();
if( Convenience.getSettings('org.gnome.shell.extensions.appfolders-manager').get_boolean('extend-menus') ) {
injectionInAppsMenus();
}
DragAndDrop.initDND();
// Reload the view if the user load the extension at least a minute after
// opening the session. XXX works like shit
let delta = getTimeStamp() - INIT_TIME;
if (delta < 0 || delta > 105) {
Main.overview.viewSelector.appDisplay._views[1].view._redisplay();
}
}
function disable() {
AppDisplay.FolderIcon.prototype._onButtonPress = null;
AppDisplay.FolderIcon.prototype.popupMenu = null;
removeInjection(AppDisplay.AppIconMenu.prototype, injections, '_redisplay');
// Overwrite my shit for FolderIcon
AppDisplay.FolderIcon = class extends AppDisplay.FolderIcon {
_onButtonPress (actor, event) {
return Clutter.EVENT_PROPAGATE;
}
};
// Overwrite my shit for AppIcon
AppDisplay.AppIcon = class extends AppDisplay.AppIcon {
onDragBeginExt () {}
onDragEndExt () {}
onDragCancelledExt () {}
};
DragAndDrop.OVERLAY_MANAGER.destroy();
}
//------------------------------------------------------------------------------