| Server IP : 93.86.61.54 / Your IP : 216.73.216.60 Web Server : Apache/2.4.62 (Ubuntu) System : Linux rasin.ddns.net 6.8.0-124-generic #124~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 21:05:19 UTC x86_64 User : www-data ( 33) PHP Version : 8.4.22 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /usr/share/gnome-shell/extensions/ubuntu-dock@ubuntu.com/ |
Upload File : |
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Signals = imports.signals;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Utils = Me.imports.utils;
const FileManager1Iface = '<node><interface name="org.freedesktop.FileManager1">\
<property name="OpenWindowsWithLocations" type="a{sas}" access="read"/>\
</interface></node>';
const FileManager1Proxy = Gio.DBusProxy.makeProxyWrapper(FileManager1Iface);
/**
* This class implements a client for the org.freedesktop.FileManager1 dbus
* interface, and specifically for the OpenWindowsWithLocations property
* which is published by Nautilus, but is not an official part of the interface.
*
* The property is a map from window identifiers to a list of locations open in
* the window.
*/
var FileManager1Client = class DashToDock_FileManager1Client {
constructor() {
this._signalsHandler = new Utils.GlobalSignalsHandler();
this._cancellable = new Gio.Cancellable();
this._windowsByPath = new Map();
this._windowsByLocation = new Map();
this._proxy = new FileManager1Proxy(Gio.DBus.session,
"org.freedesktop.FileManager1",
"/org/freedesktop/FileManager1",
(initable, error) => {
// Use async construction to avoid blocking on errors.
if (error) {
if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
global.log(error);
return;
} else {
this._updateWindows();
this._updateLocationMap();
}
}, this._cancellable);
this._signalsHandler.add([
this._proxy,
'g-properties-changed',
this._onPropertyChanged.bind(this)
], [
// We must additionally listen for Screen events to know when to
// rebuild our location map when the set of available windows changes.
global.workspaceManager,
'workspace-added',
() => this._onWindowsChanged(),
], [
global.workspaceManager,
'workspace-removed',
() => this._onWindowsChanged(),
], [
global.display,
'window-entered-monitor',
() => this._onWindowsChanged(),
], [
global.display,
'window-left-monitor',
() => this._onWindowsChanged(),
]);
}
destroy() {
if (this._windowsUpdateIdle) {
GLib.source_remove(this._windowsUpdateIdle);
delete this._windowsUpdateIdle;
}
this._cancellable.cancel();
this._signalsHandler.destroy();
this._windowsByLocation.clear();
this._windowsByPath.clear()
this._proxy = null;
}
/**
* Return an array of windows that are showing a location or
* sub-directories of that location.
*/
getWindows(location) {
if (!location)
return [];
location += location.endsWith('/') ? '' : '/';
const windows = [];
this._windowsByLocation.forEach((wins, l) => {
if (l.startsWith(location))
windows.push(...wins);
});
return [...new Set(windows)];
}
_onPropertyChanged(proxy, changed, invalidated) {
let property = changed.unpack();
if (property &&
('OpenWindowsWithLocations' in property)) {
this._updateLocationMap();
}
}
_updateWindows() {
const oldSize = this._windowsByPath.size;
const oldPaths = this._windowsByPath.keys();
this._windowsByPath = Utils.getWindowsByObjectPath();
if (oldSize != this._windowsByPath.size)
return true;
return [...oldPaths].some(path => !this._windowsByPath.has(path));
}
_onWindowsChanged() {
if (this._windowsUpdateIdle)
return;
this._windowsUpdateIdle = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
if (this._updateWindows())
this._updateLocationMap();
delete this._windowsUpdateIdle;
return GLib.SOURCE_REMOVE;
});
}
_updateLocationMap() {
let properties = this._proxy.get_cached_property_names();
if (properties == null) {
// Nothing to check yet.
return;
}
if (properties.includes('OpenWindowsWithLocations')) {
this._updateFromPaths();
}
}
_locationMapsEquals(mapA, mapB) {
if (mapA.size !== mapB.size)
return false;
const setsEquals = (a, b) => a.size === b.size &&
[...a].every(value => b.has(value));
for (const [key, val] of mapA) {
const windowsSet = mapB.get(key);
if (!windowsSet || !setsEquals(windowsSet, val))
return false;
}
return true;
}
_updateFromPaths() {
const locationsByWindowsPath = this._proxy.OpenWindowsWithLocations;
const windowsByLocation = new Map();
this._signalsHandler.removeWithLabel('windows');
Object.entries(locationsByWindowsPath).forEach(([windowPath, locations]) => {
locations.forEach(location => {
const win = this._windowsByPath.get(windowPath);
const windowGroup = win ? [win] : [];
win?.foreach_transient(w => (windowGroup.push(w) || true));
windowGroup.forEach(window => {
location += location.endsWith('/') ? '' : '/';
// Use a set to deduplicate when a window has a
// location open in multiple tabs.
const windows = windowsByLocation.get(location) || new Set();
windows.add(window);
if (windows.size === 1)
windowsByLocation.set(location, windows);
this._signalsHandler.addWithLabel('windows', window,
'unmanaged', () => {
const wins = this._windowsByLocation.get(location);
wins.delete(window);
if (!wins.size)
this._windowsByLocation.delete(location);
this.emit('windows-changed');
});
});
});
});
if (!this._locationMapsEquals(this._windowsByLocation, windowsByLocation)) {
this._windowsByLocation = windowsByLocation;
this.emit('windows-changed');
}
}
}
Signals.addSignalMethods(FileManager1Client.prototype);