2011-09-28 09:16:26 -04:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2019-01-31 09:07:06 -05:00
|
|
|
/* exported init */
|
2009-09-18 15:51:15 -04:00
|
|
|
|
2016-11-27 23:54:38 -05:00
|
|
|
const Config = imports.misc.config;
|
|
|
|
|
Specify API versions for all public GIR APIs, except GLib
If one of these libraries breaks its GIR API in future, then upgrading
packages unrelated to gnome-shell might pull in the newer version,
causing gnome-shell to crash when it gets a newer GIR API that is
incompatible with its expectations. For example, this seems to be
happening in Debian testing at the moment, when GNOME Shell 41.4
imports GWeather and can get version 4.0 instead of the version 3.0 that
it expected.
Adding explicit API versions at the time the newer version is released
is too late, because that will still let the newer version of the GIR API
break pre-existing GNOME Shell packages. Prevent similar crashes in
future by making the desired versions explicit.
This is done for all third-party libraries except GLib, similar to the
common practice in Python code; if GLib breaks API, then that will be
a disruptive change to the whole GLib/GObject ecosystem, regardless.
Gvc, Meta, Shell, Shew, St are not included because they're private
(only exist in a non-default search path entry).
Clutter and Cogl *are* included, because we need to import the fork of
them that comes with Meta, as opposed to their deprecated standalone
versions.
Signed-off-by: Simon McVittie <smcv@debian.org>
Bug-Debian: https://bugs.debian.org/1008926
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2261>
2022-04-04 06:26:43 -04:00
|
|
|
imports.gi.versions.AccountsService = '1.0';
|
|
|
|
imports.gi.versions.Atk = '1.0';
|
|
|
|
imports.gi.versions.Atspi = '2.0';
|
2016-11-27 23:54:38 -05:00
|
|
|
imports.gi.versions.Clutter = Config.LIBMUTTER_API_VERSION;
|
Specify API versions for all public GIR APIs, except GLib
If one of these libraries breaks its GIR API in future, then upgrading
packages unrelated to gnome-shell might pull in the newer version,
causing gnome-shell to crash when it gets a newer GIR API that is
incompatible with its expectations. For example, this seems to be
happening in Debian testing at the moment, when GNOME Shell 41.4
imports GWeather and can get version 4.0 instead of the version 3.0 that
it expected.
Adding explicit API versions at the time the newer version is released
is too late, because that will still let the newer version of the GIR API
break pre-existing GNOME Shell packages. Prevent similar crashes in
future by making the desired versions explicit.
This is done for all third-party libraries except GLib, similar to the
common practice in Python code; if GLib breaks API, then that will be
a disruptive change to the whole GLib/GObject ecosystem, regardless.
Gvc, Meta, Shell, Shew, St are not included because they're private
(only exist in a non-default search path entry).
Clutter and Cogl *are* included, because we need to import the fork of
them that comes with Meta, as opposed to their deprecated standalone
versions.
Signed-off-by: Simon McVittie <smcv@debian.org>
Bug-Debian: https://bugs.debian.org/1008926
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2261>
2022-04-04 06:26:43 -04:00
|
|
|
imports.gi.versions.Cogl = Config.LIBMUTTER_API_VERSION;
|
|
|
|
imports.gi.versions.Gcr = '3';
|
|
|
|
imports.gi.versions.Gdk = '3.0';
|
|
|
|
imports.gi.versions.Gdm = '1.0';
|
|
|
|
imports.gi.versions.Geoclue = '2.0';
|
2011-04-30 10:27:36 -04:00
|
|
|
imports.gi.versions.Gio = '2.0';
|
Specify API versions for all public GIR APIs, except GLib
If one of these libraries breaks its GIR API in future, then upgrading
packages unrelated to gnome-shell might pull in the newer version,
causing gnome-shell to crash when it gets a newer GIR API that is
incompatible with its expectations. For example, this seems to be
happening in Debian testing at the moment, when GNOME Shell 41.4
imports GWeather and can get version 4.0 instead of the version 3.0 that
it expected.
Adding explicit API versions at the time the newer version is released
is too late, because that will still let the newer version of the GIR API
break pre-existing GNOME Shell packages. Prevent similar crashes in
future by making the desired versions explicit.
This is done for all third-party libraries except GLib, similar to the
common practice in Python code; if GLib breaks API, then that will be
a disruptive change to the whole GLib/GObject ecosystem, regardless.
Gvc, Meta, Shell, Shew, St are not included because they're private
(only exist in a non-default search path entry).
Clutter and Cogl *are* included, because we need to import the fork of
them that comes with Meta, as opposed to their deprecated standalone
versions.
Signed-off-by: Simon McVittie <smcv@debian.org>
Bug-Debian: https://bugs.debian.org/1008926
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2261>
2022-04-04 06:26:43 -04:00
|
|
|
imports.gi.versions.GDesktopEnums = '3.0';
|
2011-04-30 10:27:36 -04:00
|
|
|
imports.gi.versions.GdkPixbuf = '2.0';
|
2021-12-02 05:44:47 -05:00
|
|
|
imports.gi.versions.GnomeBluetooth = '3.0';
|
2021-11-11 14:20:39 -05:00
|
|
|
imports.gi.versions.GnomeDesktop = '3.0';
|
Specify API versions for all public GIR APIs, except GLib
If one of these libraries breaks its GIR API in future, then upgrading
packages unrelated to gnome-shell might pull in the newer version,
causing gnome-shell to crash when it gets a newer GIR API that is
incompatible with its expectations. For example, this seems to be
happening in Debian testing at the moment, when GNOME Shell 41.4
imports GWeather and can get version 4.0 instead of the version 3.0 that
it expected.
Adding explicit API versions at the time the newer version is released
is too late, because that will still let the newer version of the GIR API
break pre-existing GNOME Shell packages. Prevent similar crashes in
future by making the desired versions explicit.
This is done for all third-party libraries except GLib, similar to the
common practice in Python code; if GLib breaks API, then that will be
a disruptive change to the whole GLib/GObject ecosystem, regardless.
Gvc, Meta, Shell, Shew, St are not included because they're private
(only exist in a non-default search path entry).
Clutter and Cogl *are* included, because we need to import the fork of
them that comes with Meta, as opposed to their deprecated standalone
versions.
Signed-off-by: Simon McVittie <smcv@debian.org>
Bug-Debian: https://bugs.debian.org/1008926
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2261>
2022-04-04 06:26:43 -04:00
|
|
|
imports.gi.versions.Graphene = '1.0';
|
2011-04-30 10:27:36 -04:00
|
|
|
imports.gi.versions.Gtk = '3.0';
|
2022-01-04 21:18:08 -05:00
|
|
|
imports.gi.versions.GWeather = '4.0';
|
Specify API versions for all public GIR APIs, except GLib
If one of these libraries breaks its GIR API in future, then upgrading
packages unrelated to gnome-shell might pull in the newer version,
causing gnome-shell to crash when it gets a newer GIR API that is
incompatible with its expectations. For example, this seems to be
happening in Debian testing at the moment, when GNOME Shell 41.4
imports GWeather and can get version 4.0 instead of the version 3.0 that
it expected.
Adding explicit API versions at the time the newer version is released
is too late, because that will still let the newer version of the GIR API
break pre-existing GNOME Shell packages. Prevent similar crashes in
future by making the desired versions explicit.
This is done for all third-party libraries except GLib, similar to the
common practice in Python code; if GLib breaks API, then that will be
a disruptive change to the whole GLib/GObject ecosystem, regardless.
Gvc, Meta, Shell, Shew, St are not included because they're private
(only exist in a non-default search path entry).
Clutter and Cogl *are* included, because we need to import the fork of
them that comes with Meta, as opposed to their deprecated standalone
versions.
Signed-off-by: Simon McVittie <smcv@debian.org>
Bug-Debian: https://bugs.debian.org/1008926
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2261>
2022-04-04 06:26:43 -04:00
|
|
|
imports.gi.versions.IBus = '1.0';
|
|
|
|
imports.gi.versions.Malcontent = '0';
|
|
|
|
imports.gi.versions.NM = '1.0';
|
|
|
|
imports.gi.versions.NMA = '1.0';
|
|
|
|
imports.gi.versions.Pango = '1.0';
|
|
|
|
imports.gi.versions.Polkit = '1.0';
|
|
|
|
imports.gi.versions.PolkitAgent = '1.0';
|
|
|
|
imports.gi.versions.Rsvg = '2.0';
|
2021-08-03 19:35:08 -04:00
|
|
|
imports.gi.versions.Soup = '3.0';
|
2014-03-25 13:02:02 -04:00
|
|
|
imports.gi.versions.TelepathyGLib = '0.12';
|
|
|
|
imports.gi.versions.TelepathyLogger = '0.2';
|
Specify API versions for all public GIR APIs, except GLib
If one of these libraries breaks its GIR API in future, then upgrading
packages unrelated to gnome-shell might pull in the newer version,
causing gnome-shell to crash when it gets a newer GIR API that is
incompatible with its expectations. For example, this seems to be
happening in Debian testing at the moment, when GNOME Shell 41.4
imports GWeather and can get version 4.0 instead of the version 3.0 that
it expected.
Adding explicit API versions at the time the newer version is released
is too late, because that will still let the newer version of the GIR API
break pre-existing GNOME Shell packages. Prevent similar crashes in
future by making the desired versions explicit.
This is done for all third-party libraries except GLib, similar to the
common practice in Python code; if GLib breaks API, then that will be
a disruptive change to the whole GLib/GObject ecosystem, regardless.
Gvc, Meta, Shell, Shew, St are not included because they're private
(only exist in a non-default search path entry).
Clutter and Cogl *are* included, because we need to import the fork of
them that comes with Meta, as opposed to their deprecated standalone
versions.
Signed-off-by: Simon McVittie <smcv@debian.org>
Bug-Debian: https://bugs.debian.org/1008926
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2261>
2022-04-04 06:26:43 -04:00
|
|
|
imports.gi.versions.UPowerGlib = '1.0';
|
2011-04-30 10:27:36 -04:00
|
|
|
|
2021-08-04 13:37:15 -04:00
|
|
|
try {
|
2021-08-29 08:24:42 -04:00
|
|
|
if (Config.HAVE_SOUP2)
|
|
|
|
throw new Error('Soup3 support not enabled');
|
2021-08-04 13:37:15 -04:00
|
|
|
const Soup_ = imports.gi.Soup;
|
|
|
|
} catch (e) {
|
|
|
|
imports.gi.versions.Soup = '2.4';
|
|
|
|
const { Soup } = imports.gi;
|
|
|
|
_injectSoup3Compat(Soup);
|
|
|
|
}
|
|
|
|
|
2019-12-19 14:50:37 -05:00
|
|
|
const { Clutter, Gio, GLib, GObject, Meta, Polkit, Shell, St } = imports.gi;
|
2011-04-30 10:34:51 -04:00
|
|
|
const Gettext = imports.gettext;
|
signalTracker: Provide monkey-patching for (dis)connectObject()
The module exports a `addObjectSignalMethods()` method that extends
the provided prototype with `connectObject()` and `disconnectObject()`
methods.
In its simplest form, `connectObject()` looks like the regular
`connect()` method, except for an additional parameter:
```js
this._button.connectObject('clicked',
() => this._onButtonClicked(), this);
```
The additional object can be used to disconnect all handlers on the
instance that were connected with that object, similar to
`g_signal_handlers_disconnect_by_data()` (which cannot be used
from introspection).
For objects that are subclasses of Clutter.Actor, that will happen
automatically when the actor is destroyed, similar to
`g_signal_connect_object()`.
Finally, `connectObject()` allows to conveniently connect multiple
signals at once, similar to `g_object_connect()`:
```js
this._toggleButton.connect(
'clicked', () => this._onClicked(),
'notify::checked', () => this._onChecked(), this);
```
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1953>
2021-08-15 18:01:40 -04:00
|
|
|
const Signals = imports.signals;
|
2020-02-27 16:46:44 -05:00
|
|
|
const System = imports.system;
|
signalTracker: Provide monkey-patching for (dis)connectObject()
The module exports a `addObjectSignalMethods()` method that extends
the provided prototype with `connectObject()` and `disconnectObject()`
methods.
In its simplest form, `connectObject()` looks like the regular
`connect()` method, except for an additional parameter:
```js
this._button.connectObject('clicked',
() => this._onButtonClicked(), this);
```
The additional object can be used to disconnect all handlers on the
instance that were connected with that object, similar to
`g_signal_handlers_disconnect_by_data()` (which cannot be used
from introspection).
For objects that are subclasses of Clutter.Actor, that will happen
automatically when the actor is destroyed, similar to
`g_signal_connect_object()`.
Finally, `connectObject()` allows to conveniently connect multiple
signals at once, similar to `g_object_connect()`:
```js
this._toggleButton.connect(
'clicked', () => this._onClicked(),
'notify::checked', () => this._onChecked(), this);
```
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1953>
2021-08-15 18:01:40 -04:00
|
|
|
const SignalTracker = imports.misc.signalTracker;
|
2020-02-27 16:46:44 -05:00
|
|
|
|
2022-02-10 18:09:54 -05:00
|
|
|
Gio._promisify(Gio.DataInputStream.prototype, 'fill_async');
|
|
|
|
Gio._promisify(Gio.DataInputStream.prototype, 'read_line_async');
|
|
|
|
Gio._promisify(Gio.DBus, 'get');
|
|
|
|
Gio._promisify(Gio.DBusConnection.prototype, 'call');
|
|
|
|
Gio._promisify(Gio.DBusProxy, 'new');
|
|
|
|
Gio._promisify(Gio.DBusProxy.prototype, 'init_async');
|
|
|
|
Gio._promisify(Gio.DBusProxy.prototype, 'call_with_unix_fd_list');
|
|
|
|
Gio._promisify(Polkit.Permission, 'new');
|
2019-12-19 14:50:37 -05:00
|
|
|
|
2020-02-27 16:46:44 -05:00
|
|
|
let _localTimeZone = null;
|
2009-09-18 15:51:15 -04:00
|
|
|
|
2011-04-30 10:27:36 -04:00
|
|
|
// We can't import shell JS modules yet, because they may have
|
|
|
|
// variable initializations, etc, that depend on init() already having
|
|
|
|
// been run.
|
2009-09-18 15:51:15 -04:00
|
|
|
|
2009-10-04 17:30:18 -04:00
|
|
|
|
2009-09-18 15:51:15 -04:00
|
|
|
// "monkey patch" in some varargs ClutterContainer methods; we need
|
|
|
|
// to do this per-container class since there is no representation
|
|
|
|
// of interfaces in Javascript
|
|
|
|
function _patchContainerClass(containerClass) {
|
|
|
|
// This one is a straightforward mapping of the C method
|
2019-08-19 13:55:49 -04:00
|
|
|
containerClass.prototype.child_set = function (actor, props) {
|
2009-09-18 15:51:15 -04:00
|
|
|
let meta = this.get_child_meta(actor);
|
2011-02-24 12:17:05 -05:00
|
|
|
for (let prop in props)
|
2009-09-18 15:51:15 -04:00
|
|
|
meta[prop] = props[prop];
|
|
|
|
};
|
|
|
|
|
|
|
|
// clutter_container_add() actually is a an add-many-actors
|
|
|
|
// method. We conveniently, but somewhat dubiously, take the
|
|
|
|
// this opportunity to make it do something more useful.
|
2019-08-19 13:55:49 -04:00
|
|
|
containerClass.prototype.add = function (actor, props) {
|
2009-09-18 15:51:15 -04:00
|
|
|
this.add_actor(actor);
|
|
|
|
if (props)
|
|
|
|
this.child_set(actor, props);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2013-07-09 17:04:45 -04:00
|
|
|
function _patchLayoutClass(layoutClass, styleProps) {
|
2019-08-19 20:51:42 -04:00
|
|
|
if (styleProps) {
|
2019-08-19 13:55:49 -04:00
|
|
|
layoutClass.prototype.hookup_style = function (container) {
|
2017-10-30 20:38:18 -04:00
|
|
|
container.connect('style-changed', () => {
|
2013-07-09 17:04:45 -04:00
|
|
|
let node = container.get_theme_node();
|
2014-04-24 10:20:01 -04:00
|
|
|
for (let prop in styleProps) {
|
|
|
|
let [found, length] = node.lookup_length(styleProps[prop], false);
|
|
|
|
if (found)
|
|
|
|
this[prop] = length;
|
|
|
|
}
|
2017-10-30 20:38:18 -04:00
|
|
|
});
|
2013-07-09 17:04:45 -04:00
|
|
|
};
|
2019-08-19 20:51:42 -04:00
|
|
|
}
|
2013-07-09 17:04:45 -04:00
|
|
|
}
|
|
|
|
|
2021-08-04 13:37:15 -04:00
|
|
|
/**
|
|
|
|
* Mimick the Soup 3 APIs we use when falling back to Soup 2.4
|
|
|
|
*
|
|
|
|
* @param {object} Soup 2.4 namespace
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
function _injectSoup3Compat(Soup) {
|
|
|
|
Soup.StatusCode = Soup.KnownStatusCode;
|
|
|
|
|
|
|
|
Soup.Message.new_from_encoded_form =
|
|
|
|
function (method, uri, form) {
|
|
|
|
const soupUri = new Soup.URI(uri);
|
|
|
|
soupUri.set_query(form);
|
|
|
|
return Soup.Message.new_from_uri(method, soupUri);
|
|
|
|
};
|
|
|
|
Soup.Message.prototype.set_request_body_from_bytes =
|
|
|
|
function (contentType, bytes) {
|
|
|
|
this.set_request(
|
|
|
|
contentType,
|
|
|
|
Soup.MemoryUse.COPY,
|
2021-08-12 10:38:57 -04:00
|
|
|
new TextDecoder().decode(bytes.get_data()));
|
2021-08-04 13:37:15 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
Soup.Session.prototype.send_and_read_async =
|
|
|
|
function (message, prio, cancellable, callback) {
|
|
|
|
this.queue_message(message, () => callback(this, message));
|
|
|
|
};
|
|
|
|
Soup.Session.prototype.send_and_read_finish =
|
|
|
|
function (message) {
|
|
|
|
if (message.status_code !== Soup.KnownStatusCode.OK)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
return message.response_body.flatten().get_as_bytes();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-09-13 05:51:41 -04:00
|
|
|
function _makeEaseCallback(params, cleanup) {
|
2017-06-09 20:52:12 -04:00
|
|
|
let onComplete = params.onComplete;
|
|
|
|
delete params.onComplete;
|
|
|
|
|
|
|
|
let onStopped = params.onStopped;
|
|
|
|
delete params.onStopped;
|
|
|
|
|
|
|
|
return isFinished => {
|
2019-09-13 05:51:41 -04:00
|
|
|
cleanup();
|
|
|
|
|
2017-06-09 20:52:12 -04:00
|
|
|
if (onStopped)
|
|
|
|
onStopped(isFinished);
|
|
|
|
if (onComplete && isFinished)
|
|
|
|
onComplete();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-06-09 22:14:12 -04:00
|
|
|
function _getPropertyTarget(actor, propName) {
|
|
|
|
if (!propName.startsWith('@'))
|
|
|
|
return [actor, propName];
|
|
|
|
|
|
|
|
let [type, name, prop] = propName.split('.');
|
|
|
|
switch (type) {
|
|
|
|
case '@layout':
|
|
|
|
return [actor.layout_manager, name];
|
|
|
|
case '@actions':
|
|
|
|
return [actor.get_action(name), prop];
|
|
|
|
case '@constraints':
|
|
|
|
return [actor.get_constraint(name), prop];
|
2020-10-07 19:21:04 -04:00
|
|
|
case '@content':
|
|
|
|
return [actor.content, name];
|
2017-06-09 22:14:12 -04:00
|
|
|
case '@effects':
|
|
|
|
return [actor.get_effect(name), prop];
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new Error(`Invalid property name ${propName}`);
|
|
|
|
}
|
|
|
|
|
2017-06-09 20:52:12 -04:00
|
|
|
function _easeActor(actor, params) {
|
|
|
|
actor.save_easing_state();
|
|
|
|
|
|
|
|
if (params.duration != undefined)
|
|
|
|
actor.set_easing_duration(params.duration);
|
|
|
|
delete params.duration;
|
|
|
|
|
|
|
|
if (params.delay != undefined)
|
|
|
|
actor.set_easing_delay(params.delay);
|
|
|
|
delete params.delay;
|
|
|
|
|
2019-10-15 15:32:21 -04:00
|
|
|
let repeatCount = 0;
|
|
|
|
if (params.repeatCount != undefined)
|
|
|
|
repeatCount = params.repeatCount;
|
|
|
|
delete params.repeatCount;
|
|
|
|
|
|
|
|
let autoReverse = false;
|
|
|
|
if (params.autoReverse != undefined)
|
|
|
|
autoReverse = params.autoReverse;
|
|
|
|
delete params.autoReverse;
|
|
|
|
|
2020-02-22 10:35:32 -05:00
|
|
|
// repeatCount doesn't include the initial iteration
|
|
|
|
const numIterations = repeatCount + 1;
|
|
|
|
// whether the transition should finish where it started
|
|
|
|
const isReversed = autoReverse && numIterations % 2 === 0;
|
|
|
|
|
2017-06-09 20:52:12 -04:00
|
|
|
if (params.mode != undefined)
|
|
|
|
actor.set_easing_mode(params.mode);
|
|
|
|
delete params.mode;
|
|
|
|
|
2020-08-03 12:33:57 -04:00
|
|
|
const prepare = () => {
|
|
|
|
Meta.disable_unredirect_for_display(global.display);
|
|
|
|
global.begin_work();
|
|
|
|
};
|
|
|
|
const cleanup = () => {
|
|
|
|
Meta.enable_unredirect_for_display(global.display);
|
|
|
|
global.end_work();
|
|
|
|
};
|
2019-09-13 05:51:41 -04:00
|
|
|
let callback = _makeEaseCallback(params, cleanup);
|
2017-06-09 20:52:12 -04:00
|
|
|
|
|
|
|
// cancel overwritten transitions
|
|
|
|
let animatedProps = Object.keys(params).map(p => p.replace('_', '-', 'g'));
|
|
|
|
animatedProps.forEach(p => actor.remove_transition(p));
|
|
|
|
|
2020-02-22 10:35:32 -05:00
|
|
|
if (actor.get_easing_duration() > 0 || !isReversed)
|
|
|
|
actor.set(params);
|
2019-08-08 20:58:28 -04:00
|
|
|
actor.restore_easing_state();
|
2017-06-09 20:52:12 -04:00
|
|
|
|
2021-10-21 13:50:18 -04:00
|
|
|
const transitions = animatedProps
|
|
|
|
.map(p => actor.get_transition(p))
|
|
|
|
.filter(t => t !== null);
|
|
|
|
|
|
|
|
transitions.forEach(t => t.set({ repeatCount, autoReverse }));
|
|
|
|
|
|
|
|
const [transition] = transitions;
|
2019-09-19 20:50:36 -04:00
|
|
|
|
2019-10-14 03:47:38 -04:00
|
|
|
if (transition && transition.delay)
|
2020-08-03 12:33:57 -04:00
|
|
|
transition.connect('started', () => prepare());
|
2019-10-14 03:47:38 -04:00
|
|
|
else
|
2020-08-03 12:33:57 -04:00
|
|
|
prepare();
|
2019-10-14 03:47:38 -04:00
|
|
|
|
2021-10-21 13:50:18 -04:00
|
|
|
if (transition)
|
2019-09-13 05:51:41 -04:00
|
|
|
transition.connect('stopped', (t, finished) => callback(finished));
|
2021-10-21 13:50:18 -04:00
|
|
|
else
|
2019-09-13 05:51:41 -04:00
|
|
|
callback(true);
|
2017-06-09 20:52:12 -04:00
|
|
|
}
|
|
|
|
|
2017-06-09 22:14:12 -04:00
|
|
|
function _easeActorProperty(actor, propName, target, params) {
|
|
|
|
// Avoid pointless difference with ease()
|
|
|
|
if (params.mode)
|
|
|
|
params.progress_mode = params.mode;
|
|
|
|
delete params.mode;
|
|
|
|
|
|
|
|
if (params.duration)
|
|
|
|
params.duration = adjustAnimationTime(params.duration);
|
|
|
|
let duration = Math.floor(params.duration || 0);
|
|
|
|
|
2019-10-15 15:32:21 -04:00
|
|
|
let repeatCount = 0;
|
|
|
|
if (params.repeatCount != undefined)
|
|
|
|
repeatCount = params.repeatCount;
|
|
|
|
delete params.repeatCount;
|
|
|
|
|
|
|
|
let autoReverse = false;
|
|
|
|
if (params.autoReverse != undefined)
|
|
|
|
autoReverse = params.autoReverse;
|
|
|
|
delete params.autoReverse;
|
|
|
|
|
2020-02-22 10:35:32 -05:00
|
|
|
// repeatCount doesn't include the initial iteration
|
|
|
|
const numIterations = repeatCount + 1;
|
|
|
|
// whether the transition should finish where it started
|
|
|
|
const isReversed = autoReverse && numIterations % 2 === 0;
|
|
|
|
|
2019-09-10 09:28:42 -04:00
|
|
|
// Copy Clutter's behavior for implicit animations, see
|
|
|
|
// should_skip_implicit_transition()
|
|
|
|
if (actor instanceof Clutter.Actor && !actor.mapped)
|
|
|
|
duration = 0;
|
|
|
|
|
2020-08-03 12:33:57 -04:00
|
|
|
const prepare = () => {
|
|
|
|
Meta.disable_unredirect_for_display(global.display);
|
|
|
|
global.begin_work();
|
|
|
|
};
|
|
|
|
const cleanup = () => {
|
|
|
|
Meta.enable_unredirect_for_display(global.display);
|
|
|
|
global.end_work();
|
|
|
|
};
|
2019-09-13 05:51:41 -04:00
|
|
|
let callback = _makeEaseCallback(params, cleanup);
|
2017-06-09 22:14:12 -04:00
|
|
|
|
|
|
|
// cancel overwritten transition
|
|
|
|
actor.remove_transition(propName);
|
|
|
|
|
|
|
|
if (duration == 0) {
|
|
|
|
let [obj, prop] = _getPropertyTarget(actor, propName);
|
2020-02-22 10:35:32 -05:00
|
|
|
|
|
|
|
if (!isReversed)
|
|
|
|
obj[prop] = target;
|
2017-06-09 22:14:12 -04:00
|
|
|
|
2020-08-03 12:33:57 -04:00
|
|
|
prepare();
|
2019-09-13 05:51:41 -04:00
|
|
|
callback(true);
|
2017-06-09 22:14:12 -04:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let pspec = actor.find_property(propName);
|
|
|
|
let transition = new Clutter.PropertyTransition(Object.assign({
|
|
|
|
property_name: propName,
|
|
|
|
interval: new Clutter.Interval({ value_type: pspec.value_type }),
|
2019-10-15 15:32:21 -04:00
|
|
|
remove_on_complete: true,
|
|
|
|
repeat_count: repeatCount,
|
|
|
|
auto_reverse: autoReverse,
|
2017-06-09 22:14:12 -04:00
|
|
|
}, params));
|
|
|
|
actor.add_transition(propName, transition);
|
|
|
|
|
|
|
|
transition.set_to(target);
|
|
|
|
|
2019-10-14 03:47:38 -04:00
|
|
|
if (transition.delay)
|
2020-08-03 12:33:57 -04:00
|
|
|
transition.connect('started', () => prepare());
|
2019-10-14 03:47:38 -04:00
|
|
|
else
|
2020-08-03 12:33:57 -04:00
|
|
|
prepare();
|
2019-10-14 03:47:38 -04:00
|
|
|
|
2019-09-13 05:51:41 -04:00
|
|
|
transition.connect('stopped', (t, finished) => callback(finished));
|
2017-06-09 22:14:12 -04:00
|
|
|
}
|
|
|
|
|
2019-02-12 06:24:30 -05:00
|
|
|
function _loggingFunc(...args) {
|
2019-01-28 20:27:05 -05:00
|
|
|
let fields = { 'MESSAGE': args.join(', ') };
|
2016-10-03 19:09:39 -04:00
|
|
|
let domain = "GNOME Shell";
|
|
|
|
|
|
|
|
// If the caller is an extension, add it as metadata
|
|
|
|
let extension = imports.misc.extensionUtils.getCurrentExtension();
|
|
|
|
if (extension != null) {
|
|
|
|
domain = extension.metadata.name;
|
|
|
|
fields['GNOME_SHELL_EXTENSION_UUID'] = extension.uuid;
|
|
|
|
fields['GNOME_SHELL_EXTENSION_NAME'] = extension.metadata.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLib.log_structured(domain, GLib.LogLevelFlags.LEVEL_MESSAGE, fields);
|
2012-04-29 16:41:08 -04:00
|
|
|
}
|
|
|
|
|
2009-09-18 15:51:15 -04:00
|
|
|
function init() {
|
2020-04-23 19:06:36 -04:00
|
|
|
// Add some bindings to the global JS namespace
|
|
|
|
globalThis.global = Shell.Global.get();
|
2011-03-12 19:41:23 -05:00
|
|
|
|
2020-04-23 19:06:36 -04:00
|
|
|
globalThis.log = _loggingFunc;
|
2012-04-29 16:41:08 -04:00
|
|
|
|
2020-04-23 19:06:36 -04:00
|
|
|
globalThis._ = Gettext.gettext;
|
|
|
|
globalThis.C_ = Gettext.pgettext;
|
|
|
|
globalThis.ngettext = Gettext.ngettext;
|
|
|
|
globalThis.N_ = s => s;
|
2011-04-30 09:16:13 -04:00
|
|
|
|
2019-10-28 13:44:24 -04:00
|
|
|
GObject.gtypeNameBasedOnJSPath = true;
|
|
|
|
|
signalTracker: Provide monkey-patching for (dis)connectObject()
The module exports a `addObjectSignalMethods()` method that extends
the provided prototype with `connectObject()` and `disconnectObject()`
methods.
In its simplest form, `connectObject()` looks like the regular
`connect()` method, except for an additional parameter:
```js
this._button.connectObject('clicked',
() => this._onButtonClicked(), this);
```
The additional object can be used to disconnect all handlers on the
instance that were connected with that object, similar to
`g_signal_handlers_disconnect_by_data()` (which cannot be used
from introspection).
For objects that are subclasses of Clutter.Actor, that will happen
automatically when the actor is destroyed, similar to
`g_signal_connect_object()`.
Finally, `connectObject()` allows to conveniently connect multiple
signals at once, similar to `g_object_connect()`:
```js
this._toggleButton.connect(
'clicked', () => this._onClicked(),
'notify::checked', () => this._onChecked(), this);
```
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1953>
2021-08-15 18:01:40 -04:00
|
|
|
GObject.Object.prototype.connectObject = function (...args) {
|
|
|
|
SignalTracker.connectObject(this, ...args);
|
|
|
|
};
|
|
|
|
GObject.Object.prototype.connect_object = function (...args) {
|
|
|
|
SignalTracker.connectObject(this, ...args);
|
|
|
|
};
|
|
|
|
GObject.Object.prototype.disconnectObject = function (...args) {
|
|
|
|
SignalTracker.disconnectObject(this, ...args);
|
|
|
|
};
|
|
|
|
GObject.Object.prototype.disconnect_object = function (...args) {
|
|
|
|
SignalTracker.disconnectObject(this, ...args);
|
|
|
|
};
|
|
|
|
|
|
|
|
const _addSignalMethods = Signals.addSignalMethods;
|
|
|
|
Signals.addSignalMethods = function (prototype) {
|
|
|
|
_addSignalMethods(prototype);
|
|
|
|
SignalTracker.addObjectSignalMethods(prototype);
|
|
|
|
};
|
|
|
|
|
2022-03-05 18:30:16 -05:00
|
|
|
SignalTracker.registerDestroyableType(Clutter.Actor);
|
|
|
|
|
2011-04-30 10:27:36 -04:00
|
|
|
// Miscellaneous monkeypatching
|
2010-03-26 16:38:03 -04:00
|
|
|
_patchContainerClass(St.BoxLayout);
|
|
|
|
|
2020-03-29 17:51:13 -04:00
|
|
|
_patchLayoutClass(Clutter.GridLayout, {
|
|
|
|
row_spacing: 'spacing-rows',
|
|
|
|
column_spacing: 'spacing-columns',
|
|
|
|
});
|
2013-07-09 17:04:45 -04:00
|
|
|
_patchLayoutClass(Clutter.BoxLayout, { spacing: 'spacing' });
|
|
|
|
|
2014-06-04 18:13:14 -04:00
|
|
|
let origSetEasingDuration = Clutter.Actor.prototype.set_easing_duration;
|
2019-08-19 13:55:49 -04:00
|
|
|
Clutter.Actor.prototype.set_easing_duration = function (msecs) {
|
2014-06-04 18:13:14 -04:00
|
|
|
origSetEasingDuration.call(this, adjustAnimationTime(msecs));
|
|
|
|
};
|
|
|
|
let origSetEasingDelay = Clutter.Actor.prototype.set_easing_delay;
|
2019-08-19 13:55:49 -04:00
|
|
|
Clutter.Actor.prototype.set_easing_delay = function (msecs) {
|
2014-06-04 18:13:14 -04:00
|
|
|
origSetEasingDelay.call(this, adjustAnimationTime(msecs));
|
|
|
|
};
|
|
|
|
|
2019-12-19 17:08:44 -05:00
|
|
|
Clutter.Actor.prototype.ease = function (props) {
|
|
|
|
_easeActor(this, props);
|
2017-06-09 20:52:12 -04:00
|
|
|
};
|
2019-08-19 13:55:49 -04:00
|
|
|
Clutter.Actor.prototype.ease_property = function (propName, target, params) {
|
2017-06-09 22:14:12 -04:00
|
|
|
_easeActorProperty(this, propName, target, params);
|
|
|
|
};
|
2019-08-19 13:55:49 -04:00
|
|
|
St.Adjustment.prototype.ease = function (target, params) {
|
2019-07-25 10:21:46 -04:00
|
|
|
// we're not an actor of course, but we implement the same
|
|
|
|
// transition API as Clutter.Actor, so this works anyway
|
|
|
|
_easeActorProperty(this, 'value', target, params);
|
|
|
|
};
|
2017-06-09 20:52:12 -04:00
|
|
|
|
2020-05-19 15:29:49 -04:00
|
|
|
Clutter.Actor.prototype[Symbol.iterator] = function* () {
|
2020-05-19 14:59:36 -04:00
|
|
|
for (let c = this.get_first_child(); c; c = c.get_next_sibling())
|
|
|
|
yield c;
|
|
|
|
};
|
|
|
|
|
2019-08-19 13:55:49 -04:00
|
|
|
Clutter.Actor.prototype.toString = function () {
|
2010-06-17 13:19:07 -04:00
|
|
|
return St.describe_actor(this);
|
|
|
|
};
|
2019-04-13 14:34:29 -04:00
|
|
|
// Deprecation warning for former JS classes turned into an actor subclass
|
|
|
|
Object.defineProperty(Clutter.Actor.prototype, 'actor', {
|
|
|
|
get() {
|
|
|
|
let klass = this.constructor.name;
|
|
|
|
let { stack } = new Error();
|
|
|
|
log(`Usage of object.actor is deprecated for ${klass}\n${stack}`);
|
|
|
|
return this;
|
2019-08-20 17:43:54 -04:00
|
|
|
},
|
2019-04-13 14:34:29 -04:00
|
|
|
});
|
2010-06-10 08:15:02 -04:00
|
|
|
|
2022-02-10 18:15:27 -05:00
|
|
|
Gio.File.prototype.touch_async = function (callback) {
|
2020-03-23 13:00:27 -04:00
|
|
|
Shell.util_touch_file_async(this, callback);
|
|
|
|
};
|
2022-02-10 18:15:27 -05:00
|
|
|
Gio.File.prototype.touch_finish = function (result) {
|
2020-03-23 13:00:27 -04:00
|
|
|
return Shell.util_touch_file_finish(this, result);
|
|
|
|
};
|
|
|
|
|
2019-08-19 13:55:49 -04:00
|
|
|
St.set_slow_down_factor = function (factor) {
|
2019-07-25 06:50:26 -04:00
|
|
|
let { stack } = new Error();
|
|
|
|
log(`St.set_slow_down_factor() is deprecated, use St.Settings.slow_down_factor\n${stack}`);
|
|
|
|
St.Settings.get().slow_down_factor = factor;
|
|
|
|
};
|
|
|
|
|
2011-04-06 10:40:01 -04:00
|
|
|
let origToString = Object.prototype.toString;
|
2019-08-19 13:55:49 -04:00
|
|
|
Object.prototype.toString = function () {
|
2011-04-06 10:40:01 -04:00
|
|
|
let base = origToString.call(this);
|
2012-03-05 15:15:45 -05:00
|
|
|
try {
|
|
|
|
if ('actor' in this && this.actor instanceof Clutter.Actor)
|
2019-01-29 19:18:24 -05:00
|
|
|
return base.replace(/\]$/, ` delegate for ${this.actor.toString().substring(1)}`);
|
2012-03-05 15:15:45 -05:00
|
|
|
else
|
|
|
|
return base;
|
2019-01-28 20:26:39 -05:00
|
|
|
} catch (e) {
|
2011-04-06 10:40:01 -04:00
|
|
|
return base;
|
2012-03-05 15:15:45 -05:00
|
|
|
}
|
2011-04-06 10:40:01 -04:00
|
|
|
};
|
|
|
|
|
2020-02-27 16:46:44 -05:00
|
|
|
// Override to clear our own timezone cache as well
|
|
|
|
const origClearDateCaches = System.clearDateCaches;
|
|
|
|
System.clearDateCaches = function () {
|
|
|
|
_localTimeZone = null;
|
|
|
|
origClearDateCaches();
|
|
|
|
};
|
|
|
|
|
2011-04-30 10:27:36 -04:00
|
|
|
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
|
2019-08-19 13:55:49 -04:00
|
|
|
Date.prototype.toLocaleFormat = function (format) {
|
2020-02-27 16:46:44 -05:00
|
|
|
if (_localTimeZone === null)
|
|
|
|
_localTimeZone = GLib.TimeZone.new_local();
|
|
|
|
|
|
|
|
let dt = GLib.DateTime.new(_localTimeZone,
|
2020-03-02 07:46:04 -05:00
|
|
|
this.getFullYear(),
|
2020-02-27 16:46:44 -05:00
|
|
|
this.getMonth() + 1,
|
|
|
|
this.getDate(),
|
|
|
|
this.getHours(),
|
|
|
|
this.getMinutes(),
|
|
|
|
this.getSeconds());
|
2020-08-12 14:59:01 -04:00
|
|
|
return dt?.format(format) ?? '';
|
2011-04-30 10:27:36 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
let slowdownEnv = GLib.getenv('GNOME_SHELL_SLOWDOWN_FACTOR');
|
|
|
|
if (slowdownEnv) {
|
|
|
|
let factor = parseFloat(slowdownEnv);
|
|
|
|
if (!isNaN(factor) && factor > 0.0)
|
2019-07-25 06:50:26 -04:00
|
|
|
St.Settings.get().slow_down_factor = factor;
|
2011-04-30 10:27:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// OK, now things are initialized enough that we can import shell JS
|
2012-05-04 17:23:08 -04:00
|
|
|
const Format = imports.format;
|
2011-04-30 10:27:36 -04:00
|
|
|
|
|
|
|
String.prototype.format = Format.format;
|
2020-06-01 23:41:43 -04:00
|
|
|
|
|
|
|
Math.clamp = function (x, lower, upper) {
|
|
|
|
return Math.min(Math.max(x, lower), upper);
|
|
|
|
};
|
2009-09-18 15:51:15 -04:00
|
|
|
}
|
2014-06-04 18:13:14 -04:00
|
|
|
|
|
|
|
// adjustAnimationTime:
|
|
|
|
// @msecs: time in milliseconds
|
|
|
|
//
|
|
|
|
// Adjust @msecs to account for St's enable-animations
|
|
|
|
// and slow-down-factor settings
|
|
|
|
function adjustAnimationTime(msecs) {
|
|
|
|
let settings = St.Settings.get();
|
|
|
|
|
|
|
|
if (!settings.enable_animations)
|
|
|
|
return 1;
|
|
|
|
return settings.slow_down_factor * msecs;
|
|
|
|
}
|
|
|
|
|