Codebase list gnome-shell-extensions / 7f6e631 extensions / windowsNavigator / extension.js
7f6e631

Tree @7f6e631 (Download .tar.gz)

extension.js @7f6e631raw · history · blame

/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
/* exported init */
const { Clutter, Graphene, GObject, St } = imports.gi;

const Main = imports.ui.main;
const Workspace = imports.ui.workspace;
const WorkspacesView = imports.ui.workspacesView;

const WINDOW_SLOT = 4;

var MyWorkspace = GObject.registerClass(
class MyWorkspace extends Workspace.Workspace {
    _init(metaWorkspace, monitorIndex) {
        super._init(metaWorkspace, monitorIndex);

        if (metaWorkspace && metaWorkspace.index() < 9) {
            this._tip = new St.Label({
                style_class: 'extension-windowsNavigator-window-tooltip',
                visible: false,
            });
            this.add_actor(this._tip);

            this.connect('notify::scale-x', () => {
                this._tip.set_scale(1 / this.scale_x, 1 / this.scale_x);
            });
        } else {
            this._tip = null;
        }
    }

    vfunc_allocate(box) {
        super.vfunc_allocate(box);

        if (this._tip)
            this._tip.allocate_preferred_size(0, 0);
    }

    showTooltip() {
        if (!this._tip)
            return;
        this._tip.text = (this.metaWorkspace.index() + 1).toString();
        this._tip.show();
        this.set_child_below_sibling(this._tip, null);
    }

    hideTooltip() {
        if (this._tip)
            this._tip.hide();
    }

    getWindowWithTooltip(id) {
        const slot = this.layout_manager._windowSlots[id - 1];
        return slot ? slot[WINDOW_SLOT].metaWindow : null;
    }

    showWindowsTooltips() {
        for (let i = 0; i < this.layout_manager._windowSlots.length; i++) {
            if (this.layout_manager._windowSlots[i])
                this.layout_manager._windowSlots[i][WINDOW_SLOT].showTooltip(`${i + 1}`);
        }
    }

    hideWindowsTooltips() {
        for (let i in this.layout_manager._windowSlots) {
            if (this.layout_manager._windowSlots[i])
                this.layout_manager._windowSlots[i][WINDOW_SLOT].hideTooltip();
        }
    }

    // overriding _addWindowClone to apply the tooltip patch on the cloned
    // windowPreview
    _addWindowClone(metaWindow) {
        const clone = super._addWindowClone(metaWindow);

        // appling the tooltip patch
        (function patchPreview() {
            this._text = new St.Label({
                style_class: 'extension-windowsNavigator-window-tooltip',
                visible: false,
            });

            this._text.add_constraint(new Clutter.BindConstraint({
                source: this._borderCenter,
                coordinate: Clutter.BindCoordinate.POSITION,
            }));
            this._text.add_constraint(new Clutter.AlignConstraint({
                source: this._borderCenter,
                align_axis: Clutter.AlignAxis.X_AXIS,
                pivot_point: new Graphene.Point({ x: 0.5, y: -1 }),
                factor: this._closeButtonSide === St.Side.LEFT ? 1 : 0,
            }));
            this._text.add_constraint(new Clutter.AlignConstraint({
                source: this._borderCenter,
                align_axis: Clutter.AlignAxis.Y_AXIS,
                pivot_point: new Graphene.Point({ x: -1, y: 0.5 }),
                factor: 0,
            }));

            this.add_child(this._text);
        }).call(clone);

        clone.showTooltip = function (text) {
            this._text.set({ text });
            this._text.show();
        };

        clone.hideTooltip = function () {
            if (this._text && this._text.visible)
                this._text.hide();
        };

        return clone;
    }
});

var MyWorkspacesView = GObject.registerClass(
class MyWorkspacesView extends WorkspacesView.WorkspacesView {
    _init(width, height, x, y, workspaces) {
        super._init(width, height, x, y, workspaces);

        this._pickWorkspace = false;
        this._pickWindow = false;
        this._keyPressEventId =
            global.stage.connect('key-press-event', this._onKeyPress.bind(this));
        this._keyReleaseEventId =
            global.stage.connect('key-release-event', this._onKeyRelease.bind(this));
    }

    _onDestroy() {
        super._onDestroy();

        global.stage.disconnect(this._keyPressEventId);
        global.stage.disconnect(this._keyReleaseEventId);
    }

    _hideTooltips() {
        if (global.stage.get_key_focus() === global.stage)
            global.stage.set_key_focus(this._prevFocusActor);
        this._pickWindow = false;
        for (let i = 0; i < this._workspaces.length; i++)
            this._workspaces[i].hideWindowsTooltips();
    }

    _hideWorkspacesTooltips() {
        global.stage.set_key_focus(this._prevFocusActor);
        this._pickWorkspace = false;
        for (let i = 0; i < this._workspaces.length; i++)
            this._workspaces[i].hideTooltip();
    }

    _onKeyRelease(s, o) {
        if (this._pickWindow &&
            (o.get_key_symbol() === Clutter.KEY_Alt_L ||
             o.get_key_symbol() === Clutter.KEY_Alt_R))
            this._hideTooltips();
        if (this._pickWorkspace &&
            (o.get_key_symbol() === Clutter.KEY_Control_L ||
             o.get_key_symbol() === Clutter.KEY_Control_R))
            this._hideWorkspacesTooltips();
    }

    _onKeyPress(s, o) {
        let { viewSelector } = Main.overview;
        if (viewSelector._activePage !== viewSelector._workspacesPage)
            return false;

        let workspaceManager = global.workspace_manager;

        if ((o.get_key_symbol() === Clutter.KEY_Alt_L ||
             o.get_key_symbol() === Clutter.KEY_Alt_R) &&
            !this._pickWorkspace) {
            this._prevFocusActor = global.stage.get_key_focus();
            global.stage.set_key_focus(null);
            this._active = workspaceManager.get_active_workspace_index();
            this._pickWindow = true;
            this._workspaces[workspaceManager.get_active_workspace_index()].showWindowsTooltips();
            return true;
        }
        if ((o.get_key_symbol() === Clutter.KEY_Control_L ||
             o.get_key_symbol() === Clutter.KEY_Control_R) &&
            !this._pickWindow) {
            this._prevFocusActor = global.stage.get_key_focus();
            global.stage.set_key_focus(null);
            this._pickWorkspace = true;
            for (let i = 0; i < this._workspaces.length; i++)
                this._workspaces[i].showTooltip();
            return true;
        }

        if (global.stage.get_key_focus() !== global.stage)
            return false;

        // ignore shift presses, they're required to get numerals in azerty keyboards
        if ((this._pickWindow || this._pickWorkspace) &&
            (o.get_key_symbol() === Clutter.KEY_Shift_L ||
             o.get_key_symbol() === Clutter.KEY_Shift_R))
            return true;

        if (this._pickWindow) {
            if (this._active !== workspaceManager.get_active_workspace_index()) {
                this._hideTooltips();
                return false;
            }

            let c = o.get_key_symbol() - Clutter.KEY_KP_0;
            if (c > 9 || c <= 0) {
                c = o.get_key_symbol() - Clutter.KEY_0;
                if (c > 9 || c <= 0) {
                    this._hideTooltips();
                    global.log(c);
                    return false;
                }
            }

            let win = this._workspaces[this._active].getWindowWithTooltip(c);
            this._hideTooltips();

            if (win)
                Main.activateWindow(win, global.get_current_time());

            return true;
        }
        if (this._pickWorkspace) {
            let c = o.get_key_symbol() - Clutter.KEY_KP_0;
            if (c > 9 || c <= 0) {
                c = o.get_key_symbol() - Clutter.KEY_0;
                if (c > 9 || c <= 0) {
                    this._hideWorkspacesTooltips();
                    return false;
                }
            }

            let workspace = this._workspaces[c - 1];
            if (workspace !== undefined)
                workspace.metaWorkspace.activate(global.get_current_time());

            this._hideWorkspacesTooltips();
            return true;
        }
        return false;
    }
});

class Extension {
    constructor() {
        this._origWorkspace = Workspace.Workspace;
        this._origWorkspacesView = WorkspacesView.WorkspacesView;
    }

    enable() {
        Workspace.Workspace = MyWorkspace;
        WorkspacesView.WorkspacesView = MyWorkspacesView;
    }

    disable() {
        Workspace.Workspace = this._origWorkspace;
        WorkspacesView.WorkspacesView = this._origWorkspacesView;
    }
}

function init() {
    return new Extension();
}