Blame js/ui/modalDialog.js

Packit Service ed5168
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
Packit Service ed5168
Packit Service ed5168
const { Atk, Clutter, Shell, St } = imports.gi;
Packit Service ed5168
const Signals = imports.signals;
Packit Service ed5168
Packit Service ed5168
const Dialog = imports.ui.dialog;
Packit Service ed5168
const Layout = imports.ui.layout;
Packit Service ed5168
const Lightbox = imports.ui.lightbox;
Packit Service ed5168
const Main = imports.ui.main;
Packit Service ed5168
const Params = imports.misc.params;
Packit Service ed5168
const Tweener = imports.ui.tweener;
Packit Service ed5168
Packit Service ed5168
var OPEN_AND_CLOSE_TIME = 0.1;
Packit Service ed5168
var FADE_OUT_DIALOG_TIME = 1.0;
Packit Service ed5168
Packit Service ed5168
var State = {
Packit Service ed5168
    OPENED: 0,
Packit Service ed5168
    CLOSED: 1,
Packit Service ed5168
    OPENING: 2,
Packit Service ed5168
    CLOSING: 3,
Packit Service ed5168
    FADED_OUT: 4
Packit Service ed5168
};
Packit Service ed5168
Packit Service ed5168
var ModalDialog = class {
Packit Service ed5168
    constructor(params) {
Packit Service ed5168
        params = Params.parse(params, { shellReactive: false,
Packit Service ed5168
                                        styleClass: null,
Packit Service ed5168
                                        actionMode: Shell.ActionMode.SYSTEM_MODAL,
Packit Service ed5168
                                        shouldFadeIn: true,
Packit Service ed5168
                                        shouldFadeOut: true,
Packit Service ed5168
                                        destroyOnClose: true });
Packit Service ed5168
Packit Service ed5168
        this.state = State.CLOSED;
Packit Service ed5168
        this._hasModal = false;
Packit Service ed5168
        this._actionMode = params.actionMode;
Packit Service ed5168
        this._shellReactive = params.shellReactive;
Packit Service ed5168
        this._shouldFadeIn = params.shouldFadeIn;
Packit Service ed5168
        this._shouldFadeOut = params.shouldFadeOut;
Packit Service ed5168
        this._destroyOnClose = params.destroyOnClose;
Packit Service ed5168
Packit Service ed5168
        this._group = new St.Widget({ visible: false,
Packit Service ed5168
                                      x: 0,
Packit Service ed5168
                                      y: 0,
Packit Service ed5168
                                      accessible_role: Atk.Role.DIALOG });
Packit Service ed5168
        Main.layoutManager.modalDialogGroup.add_actor(this._group);
Packit Service ed5168
Packit Service ed5168
        let constraint = new Clutter.BindConstraint({ source: global.stage,
Packit Service ed5168
                                                      coordinate: Clutter.BindCoordinate.ALL });
Packit Service ed5168
        this._group.add_constraint(constraint);
Packit Service ed5168
Packit Service ed5168
        this._group.connect('destroy', this._onGroupDestroy.bind(this));
Packit Service ed5168
Packit Service ed5168
        this.backgroundStack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
Packit Service ed5168
        this._backgroundBin = new St.Bin({ child: this.backgroundStack,
Packit Service ed5168
                                           x_fill: true, y_fill: true });
Packit Service ed5168
        this._monitorConstraint = new Layout.MonitorConstraint();
Packit Service ed5168
        this._backgroundBin.add_constraint(this._monitorConstraint);
Packit Service ed5168
        this._group.add_actor(this._backgroundBin);
Packit Service ed5168
Packit Service ed5168
        this.dialogLayout = new Dialog.Dialog(this.backgroundStack, params.styleClass);
Packit Service ed5168
        this.contentLayout = this.dialogLayout.contentLayout;
Packit Service ed5168
        this.buttonLayout = this.dialogLayout.buttonLayout;
Packit Service ed5168
Packit Service ed5168
        if (!this._shellReactive) {
Packit Service ed5168
            this._lightbox = new Lightbox.Lightbox(this._group,
Packit Service ed5168
                                                   { inhibitEvents: true,
Packit Service ed5168
                                                     radialEffect: true });
Packit Service ed5168
            this._lightbox.highlight(this._backgroundBin);
Packit Service ed5168
Packit Service ed5168
            this._eventBlocker = new Clutter.Actor({ reactive: true });
Packit Service ed5168
            this.backgroundStack.add_actor(this._eventBlocker);
Packit Service ed5168
        }
Packit Service ed5168
Packit Service ed5168
        global.focus_manager.add_group(this.dialogLayout);
Packit Service ed5168
        this._initialKeyFocus = null;
Packit Service ed5168
        this._initialKeyFocusDestroyId = 0;
Packit Service ed5168
        this._savedKeyFocus = null;
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    destroy() {
Packit Service ed5168
        this._group.destroy();
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    clearButtons() {
Packit Service ed5168
        this.dialogLayout.clearButtons();
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    setButtons(buttons) {
Packit Service ed5168
        this.clearButtons();
Packit Service ed5168
Packit Service ed5168
        for (let buttonInfo of buttons)
Packit Service ed5168
            this.addButton(buttonInfo);
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    addButton(buttonInfo) {
Packit Service ed5168
        return this.dialogLayout.addButton(buttonInfo);
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _onGroupDestroy() {
Packit Service ed5168
        this.emit('destroy');
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _fadeOpen(onPrimary) {
Packit Service ed5168
        if (onPrimary)
Packit Service ed5168
            this._monitorConstraint.primary = true;
Packit Service ed5168
        else
Packit Service ed5168
            this._monitorConstraint.index = global.display.get_current_monitor();
Packit Service ed5168
Packit Service ed5168
        this.state = State.OPENING;
Packit Service ed5168
Packit Service ed5168
        this.dialogLayout.opacity = 255;
Packit Service ed5168
        if (this._lightbox)
Packit Service ed5168
            this._lightbox.show();
Packit Service ed5168
        this._group.opacity = 0;
Packit Service ed5168
        this._group.show();
Packit Service ed5168
        Tweener.addTween(this._group,
Packit Service ed5168
                         { opacity: 255,
Packit Service ed5168
                           time: this._shouldFadeIn ? OPEN_AND_CLOSE_TIME : 0,
Packit Service ed5168
                           transition: 'easeOutQuad',
Packit Service ed5168
                           onComplete: () => {
Packit Service ed5168
                               this.state = State.OPENED;
Packit Service ed5168
                               this.emit('opened');
Packit Service ed5168
                           }
Packit Service ed5168
                         });
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    setInitialKeyFocus(actor) {
Packit Service ed5168
        if (this._initialKeyFocusDestroyId)
Packit Service ed5168
            this._initialKeyFocus.disconnect(this._initialKeyFocusDestroyId);
Packit Service ed5168
Packit Service ed5168
        this._initialKeyFocus = actor;
Packit Service ed5168
Packit Service ed5168
        this._initialKeyFocusDestroyId = actor.connect('destroy', () => {
Packit Service ed5168
            this._initialKeyFocus = null;
Packit Service ed5168
            this._initialKeyFocusDestroyId = 0;
Packit Service ed5168
        });
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    open(timestamp, onPrimary) {
Packit Service ed5168
        if (this.state == State.OPENED || this.state == State.OPENING)
Packit Service ed5168
            return true;
Packit Service ed5168
Packit Service ed5168
        if (!this.pushModal(timestamp))
Packit Service ed5168
            return false;
Packit Service ed5168
Packit Service ed5168
        this._fadeOpen(onPrimary);
Packit Service ed5168
        return true;
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _closeComplete() {
Packit Service ed5168
        this.state = State.CLOSED;
Packit Service ed5168
        this._group.hide();
Packit Service ed5168
        this.emit('closed');
Packit Service ed5168
Packit Service ed5168
        if (this._destroyOnClose)
Packit Service ed5168
            this.destroy();
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    close(timestamp) {
Packit Service ed5168
        if (this.state == State.CLOSED || this.state == State.CLOSING)
Packit Service ed5168
            return;
Packit Service ed5168
Packit Service ed5168
        this.state = State.CLOSING;
Packit Service ed5168
        this.popModal(timestamp);
Packit Service ed5168
        this._savedKeyFocus = null;
Packit Service ed5168
Packit Service ed5168
        if (this._shouldFadeOut)
Packit Service ed5168
            Tweener.addTween(this._group,
Packit Service ed5168
                             { opacity: 0,
Packit Service ed5168
                               time: OPEN_AND_CLOSE_TIME,
Packit Service ed5168
                               transition: 'easeOutQuad',
Packit Service ed5168
                               onComplete: this._closeComplete.bind(this)
Packit Service ed5168
                             })
Packit Service ed5168
        else
Packit Service ed5168
            this._closeComplete();
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    // Drop modal status without closing the dialog; this makes the
Packit Service ed5168
    // dialog insensitive as well, so it needs to be followed shortly
Packit Service ed5168
    // by either a close() or a pushModal()
Packit Service ed5168
    popModal(timestamp) {
Packit Service ed5168
        if (!this._hasModal)
Packit Service ed5168
            return;
Packit Service ed5168
Packit Service ed5168
        let focus = global.stage.key_focus;
Packit Service ed5168
        if (focus && this._group.contains(focus))
Packit Service ed5168
            this._savedKeyFocus = focus;
Packit Service ed5168
        else
Packit Service ed5168
            this._savedKeyFocus = null;
Packit Service ed5168
        Main.popModal(this._group, timestamp);
Packit Service ed5168
        this._hasModal = false;
Packit Service ed5168
Packit Service ed5168
        if (!this._shellReactive)
Packit Service ed5168
            this._eventBlocker.raise_top();
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    pushModal(timestamp) {
Packit Service ed5168
        if (this._hasModal)
Packit Service ed5168
            return true;
Packit Service ed5168
Packit Service ed5168
        let params = { actionMode: this._actionMode };
Packit Service ed5168
        if (timestamp)
Packit Service ed5168
            params['timestamp'] = timestamp;
Packit Service ed5168
        if (!Main.pushModal(this._group, params))
Packit Service ed5168
            return false;
Packit Service ed5168
Packit Service ed5168
        this._hasModal = true;
Packit Service ed5168
        if (this._savedKeyFocus) {
Packit Service ed5168
            this._savedKeyFocus.grab_key_focus();
Packit Service ed5168
            this._savedKeyFocus = null;
Packit Service ed5168
        } else {
Packit Service ed5168
            let focus = this._initialKeyFocus || this.dialogLayout.initialKeyFocus;
Packit Service ed5168
            focus.grab_key_focus();
Packit Service ed5168
        }
Packit Service ed5168
Packit Service ed5168
        if (!this._shellReactive)
Packit Service ed5168
            this._eventBlocker.lower_bottom();
Packit Service ed5168
        return true;
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    // This method is like close, but fades the dialog out much slower,
Packit Service ed5168
    // and leaves the lightbox in place. Once in the faded out state,
Packit Service ed5168
    // the dialog can be brought back by an open call, or the lightbox
Packit Service ed5168
    // can be dismissed by a close call.
Packit Service ed5168
    //
Packit Service ed5168
    // The main point of this method is to give some indication to the user
Packit Service ed5168
    // that the dialog reponse has been acknowledged but will take a few
Packit Service ed5168
    // moments before being processed.
Packit Service ed5168
    // e.g., if a user clicked "Log Out" then the dialog should go away
Packit Service ed5168
    // imediately, but the lightbox should remain until the logout is
Packit Service ed5168
    // complete.
Packit Service ed5168
    _fadeOutDialog(timestamp) {
Packit Service ed5168
        if (this.state == State.CLOSED || this.state == State.CLOSING)
Packit Service ed5168
            return;
Packit Service ed5168
Packit Service ed5168
        if (this.state == State.FADED_OUT)
Packit Service ed5168
            return;
Packit Service ed5168
Packit Service ed5168
        this.popModal(timestamp);
Packit Service ed5168
        Tweener.addTween(this.dialogLayout,
Packit Service ed5168
                         { opacity: 0,
Packit Service ed5168
                           time:    FADE_OUT_DIALOG_TIME,
Packit Service ed5168
                           transition: 'easeOutQuad',
Packit Service ed5168
                           onComplete: () => {
Packit Service ed5168
                               this.state = State.FADED_OUT;
Packit Service ed5168
                           }
Packit Service ed5168
                         });
Packit Service ed5168
    }
Packit Service ed5168
};
Packit Service ed5168
Signals.addSignalMethods(ModalDialog.prototype);