Blame js/ui/pointerWatcher.js

Packit Service ed5168
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
Packit Service ed5168
Packit Service ed5168
const { GLib, Meta } = imports.gi;
Packit Service ed5168
const Mainloop = imports.mainloop;
Packit Service ed5168
Packit Service ed5168
// We stop polling if the user is idle for more than this amount of time
Packit Service ed5168
var IDLE_TIME = 1000;
Packit Service ed5168
Packit Service ed5168
// This file implements a reasonably efficient system for tracking the position
Packit Service ed5168
// of the mouse pointer. We simply query the pointer from the X server in a loop,
Packit Service ed5168
// but we turn off the polling when the user is idle.
Packit Service ed5168
Packit Service ed5168
let _pointerWatcher = null;
Packit Service ed5168
function getPointerWatcher() {
Packit Service ed5168
    if (_pointerWatcher == null)
Packit Service ed5168
        _pointerWatcher = new PointerWatcher();
Packit Service ed5168
Packit Service ed5168
    return _pointerWatcher;
Packit Service ed5168
}
Packit Service ed5168
Packit Service ed5168
var PointerWatch = class {
Packit Service ed5168
    constructor(watcher, interval, callback) {
Packit Service ed5168
        this.watcher = watcher;
Packit Service ed5168
        this.interval = interval;
Packit Service ed5168
        this.callback = callback;
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    // remove:
Packit Service ed5168
    // remove this watch. This function may safely be called
Packit Service ed5168
    // while the callback is executing.
Packit Service ed5168
    remove() {
Packit Service ed5168
        this.watcher._removeWatch(this);
Packit Service ed5168
    }
Packit Service ed5168
};
Packit Service ed5168
Packit Service ed5168
var PointerWatcher = class {
Packit Service ed5168
    constructor() {
Packit Service ed5168
        this._idleMonitor = Meta.IdleMonitor.get_core();
Packit Service ed5168
        this._idleMonitor.add_idle_watch(IDLE_TIME, this._onIdleMonitorBecameIdle.bind(this));
Packit Service ed5168
        this._idle = this._idleMonitor.get_idletime() > IDLE_TIME;
Packit Service ed5168
        this._watches = [];
Packit Service ed5168
        this.pointerX = null;
Packit Service ed5168
        this.pointerY = null;
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    // addWatch:
Packit Service ed5168
    // @interval: hint as to the time resolution needed. When the user is
Packit Service ed5168
    //   not idle, the position of the pointer will be queried at least
Packit Service ed5168
    //   once every this many milliseconds.
Packit Service ed5168
    // @callback to call when the pointer position changes - takes
Packit Service ed5168
    //   two arguments, X and Y.
Packit Service ed5168
    //
Packit Service ed5168
    // Set up a watch on the position of the mouse pointer. Returns a
Packit Service ed5168
    // PointerWatch object which has a remove() method to remove the watch.
Packit Service ed5168
    addWatch(interval, callback) {
Packit Service ed5168
        // Avoid unreliably calling the watch for the current position
Packit Service ed5168
        this._updatePointer();
Packit Service ed5168
Packit Service ed5168
        let watch = new PointerWatch(this, interval, callback);
Packit Service ed5168
        this._watches.push(watch);
Packit Service ed5168
        this._updateTimeout();
Packit Service ed5168
        return watch;
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _removeWatch(watch) {
Packit Service ed5168
        for (let i = 0; i < this._watches.length; i++) {
Packit Service ed5168
            if (this._watches[i] == watch) {
Packit Service ed5168
                this._watches.splice(i, 1);
Packit Service ed5168
                this._updateTimeout();
Packit Service ed5168
                return;
Packit Service ed5168
            }
Packit Service ed5168
        }
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _onIdleMonitorBecameActive(monitor) {
Packit Service ed5168
        this._idle = false;
Packit Service ed5168
        this._updatePointer();
Packit Service ed5168
        this._updateTimeout();
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _onIdleMonitorBecameIdle(monitor) {
Packit Service ed5168
        this._idle = true;
Packit Service ed5168
        this._idleMonitor.add_user_active_watch(this._onIdleMonitorBecameActive.bind(this));
Packit Service ed5168
        this._updateTimeout();
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _updateTimeout() {
Packit Service ed5168
        if (this._timeoutId) {
Packit Service ed5168
            Mainloop.source_remove(this._timeoutId);
Packit Service ed5168
            this._timeoutId = 0;
Packit Service ed5168
        }
Packit Service ed5168
Packit Service ed5168
        if (this._idle || this._watches.length == 0)
Packit Service ed5168
            return;
Packit Service ed5168
Packit Service ed5168
        let minInterval = this._watches[0].interval;
Packit Service ed5168
        for (let i = 1; i < this._watches.length; i++)
Packit Service ed5168
            minInterval = Math.min(this._watches[i].interval, minInterval);
Packit Service ed5168
Packit Service ed5168
        this._timeoutId = Mainloop.timeout_add(minInterval,
Packit Service ed5168
                                               this._onTimeout.bind(this));
Packit Service ed5168
        GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._onTimeout');
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _onTimeout() {
Packit Service ed5168
        this._updatePointer();
Packit Service ed5168
        return GLib.SOURCE_CONTINUE;
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _updatePointer() {
Packit Service ed5168
        let [x, y, mods] = global.get_pointer();
Packit Service ed5168
        if (this.pointerX == x && this.pointerY == y)
Packit Service ed5168
            return;
Packit Service ed5168
Packit Service ed5168
        this.pointerX = x;
Packit Service ed5168
        this.pointerY = y;
Packit Service ed5168
Packit Service ed5168
        for (let i = 0; i < this._watches.length;) {
Packit Service ed5168
            let watch = this._watches[i];
Packit Service ed5168
            watch.callback(x, y);
Packit Service ed5168
            if (watch == this._watches[i]) // guard against self-removal
Packit Service ed5168
                i++;
Packit Service ed5168
        }
Packit Service ed5168
    }
Packit Service ed5168
};