Compare commits
	
		
			23 Commits
		
	
	
		
			3.36.0
			...
			gbsneto/ne
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					6fd0aafada | ||
| 
						 | 
					e5091ff17c | ||
| 
						 | 
					22534c4c64 | ||
| 
						 | 
					cd1c45731d | ||
| 
						 | 
					5380b06eb5 | ||
| 
						 | 
					be714f7401 | ||
| 
						 | 
					e71c249ea5 | ||
| 
						 | 
					5b6deff977 | ||
| 
						 | 
					6cd0c3f965 | ||
| 
						 | 
					d529e222d7 | ||
| 
						 | 
					2e23a0e6b8 | ||
| 
						 | 
					64aaa46333 | ||
| 
						 | 
					d1f61e884d | ||
| 
						 | 
					fe3d55eb80 | ||
| 
						 | 
					7a90b2d908 | ||
| 
						 | 
					137df4bc26 | ||
| 
						 | 
					23abe4eb22 | ||
| 
						 | 
					b7feb71490 | ||
| 
						 | 
					9aa9431a32 | ||
| 
						 | 
					c9e2afcf65 | ||
| 
						 | 
					be5ab24e97 | ||
| 
						 | 
					caf0c8dd7d | ||
| 
						 | 
					10a194e6ed | 
@@ -1929,6 +1929,7 @@ StScrollBar {
 | 
			
		||||
 | 
			
		||||
  StEntry {
 | 
			
		||||
    @extend %search_entry;
 | 
			
		||||
    width: -1px;
 | 
			
		||||
    border-radius: $button_radius;
 | 
			
		||||
    @if $variant=='dark' {
 | 
			
		||||
      $_gdm_entry_bg: transparentize(lighten(desaturate(#241f31, 20%), 2%), 0.5);
 | 
			
		||||
@@ -1986,6 +1987,15 @@ StScrollBar {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .cancel-button {
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    border-radius: 16px;
 | 
			
		||||
    width: 32px;
 | 
			
		||||
    height: 32px;
 | 
			
		||||
 | 
			
		||||
	  StIcon { icon-size: 16px; }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  .login-dialog-logo-bin { padding: 24px 0px; }
 | 
			
		||||
@@ -2069,42 +2079,28 @@ StScrollBar {
 | 
			
		||||
 | 
			
		||||
$_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726);
 | 
			
		||||
 | 
			
		||||
.screen-shield-arrows {
 | 
			
		||||
    padding-bottom: 3em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.screen-shield-arrows Gjs_Arrow {
 | 
			
		||||
    color: white;
 | 
			
		||||
    width: 80px;
 | 
			
		||||
    height: 48px;
 | 
			
		||||
    -arrow-thickness: 12px;
 | 
			
		||||
    -arrow-shadow: $_screenshield_shadow;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.screen-shield-clock {
 | 
			
		||||
  color: white;
 | 
			
		||||
  text-shadow: $_screenshield_shadow;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  padding-bottom: 1.5em;
 | 
			
		||||
  padding-bottom: 2.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.screen-shield-clock-time {
 | 
			
		||||
  font-size: 72pt;
 | 
			
		||||
  text-shadow: $_screenshield_shadow;
 | 
			
		||||
  font-size: 64pt;
 | 
			
		||||
  font-weight: 200;
 | 
			
		||||
  padding-bottom: 24px;
 | 
			
		||||
  font-feature-settings: "tnum";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.screen-shield-clock-date { 
 | 
			
		||||
  font-size: 28pt;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  font-size: 16pt;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.screen-shield-notifications-container {
 | 
			
		||||
  spacing: 6px;
 | 
			
		||||
  width: 30em;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  max-height: 500px;
 | 
			
		||||
  padding: 24px 0;
 | 
			
		||||
  .summary-notification-stack-scrollview {
 | 
			
		||||
    padding-top: 0;
 | 
			
		||||
    padding-bottom: 0;
 | 
			
		||||
@@ -2112,7 +2108,7 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726);
 | 
			
		||||
 | 
			
		||||
  .notification,
 | 
			
		||||
  .screen-shield-notification-source {
 | 
			
		||||
    padding: 12px 6px;
 | 
			
		||||
    padding: 12px;
 | 
			
		||||
    border: 1px solid $osd_outer_borders_color;
 | 
			
		||||
    background-color: transparentize($osd_bg_color,0.5);
 | 
			
		||||
    color: $osd_fg_color;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,10 @@ var DEFAULT_BUTTON_WELL_ANIMATION_TIME = 300;
 | 
			
		||||
 | 
			
		||||
var MESSAGE_FADE_OUT_ANIMATION_TIME = 500;
 | 
			
		||||
 | 
			
		||||
const WIGGLE_OFFSET = 6;
 | 
			
		||||
const WIGGLE_DURATION = 65;
 | 
			
		||||
const N_WIGGLES = 3;
 | 
			
		||||
 | 
			
		||||
var AuthPromptMode = {
 | 
			
		||||
    UNLOCK_ONLY: 0,
 | 
			
		||||
    UNLOCK_OR_LOG_IN: 1
 | 
			
		||||
@@ -90,40 +94,14 @@ var AuthPrompt = class {
 | 
			
		||||
                         x_fill: false,
 | 
			
		||||
                         y_fill: true,
 | 
			
		||||
                         x_align: St.Align.START });
 | 
			
		||||
        this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
 | 
			
		||||
                                     can_focus: true });
 | 
			
		||||
        ShellEntry.addContextMenu(this._entry, { isPassword: true, actionMode: Shell.ActionMode.NONE });
 | 
			
		||||
 | 
			
		||||
        this.actor.add(this._entry,
 | 
			
		||||
                       { expand: true,
 | 
			
		||||
                         x_fill: true,
 | 
			
		||||
                         y_fill: false,
 | 
			
		||||
                         x_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        this._entry.grab_key_focus();
 | 
			
		||||
        this._initEntryRow();
 | 
			
		||||
 | 
			
		||||
        this._message = new St.Label({ opacity: 0,
 | 
			
		||||
                                       styleClass: 'login-dialog-message' });
 | 
			
		||||
        this._message.clutter_text.line_wrap = true;
 | 
			
		||||
        this._message.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 | 
			
		||||
        this.actor.add(this._message, { x_fill: false, x_align: St.Align.START, y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
 | 
			
		||||
                                             vertical: false });
 | 
			
		||||
        this.actor.add(this._buttonBox,
 | 
			
		||||
                       { expand: true,
 | 
			
		||||
                         x_align: St.Align.MIDDLE,
 | 
			
		||||
                         y_align: St.Align.END });
 | 
			
		||||
 | 
			
		||||
        this._defaultButtonWell = new St.Widget({ layout_manager: new Clutter.BinLayout() });
 | 
			
		||||
        this._defaultButtonWellActor = null;
 | 
			
		||||
 | 
			
		||||
        this._initButtons();
 | 
			
		||||
 | 
			
		||||
        this._spinner = new Animation.Spinner(DEFAULT_BUTTON_WELL_ICON_SIZE);
 | 
			
		||||
        this._spinner.actor.opacity = 0;
 | 
			
		||||
        this._spinner.actor.show();
 | 
			
		||||
        this._defaultButtonWell.add_child(this._spinner.actor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
@@ -131,52 +109,47 @@ var AuthPrompt = class {
 | 
			
		||||
        this._userVerifier = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _initButtons() {
 | 
			
		||||
        this.cancelButton = new St.Button({ style_class: 'modal-dialog-button button',
 | 
			
		||||
                                            button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
 | 
			
		||||
                                            reactive: true,
 | 
			
		||||
                                            can_focus: true,
 | 
			
		||||
                                            label: _("Cancel") });
 | 
			
		||||
    _initEntryRow() {
 | 
			
		||||
        let mainBox = new St.BoxLayout({
 | 
			
		||||
            style_class: 'login-dialog-button-box',
 | 
			
		||||
            vertical: false,
 | 
			
		||||
        });
 | 
			
		||||
        this.actor.add_child(mainBox);
 | 
			
		||||
 | 
			
		||||
        this.cancelButton = new St.Button({
 | 
			
		||||
            style_class: 'modal-dialog-button button cancel-button',
 | 
			
		||||
            button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
 | 
			
		||||
            reactive: true,
 | 
			
		||||
            can_focus: true,
 | 
			
		||||
            child: new St.Icon({ icon_name: 'go-previous-symbolic' }),
 | 
			
		||||
        });
 | 
			
		||||
        this.cancelButton.connect('clicked', () => this.cancel());
 | 
			
		||||
        this._buttonBox.add(this.cancelButton,
 | 
			
		||||
                            { expand: false,
 | 
			
		||||
                              x_fill: false,
 | 
			
		||||
                              y_fill: false,
 | 
			
		||||
                              x_align: St.Align.START,
 | 
			
		||||
                              y_align: St.Align.END });
 | 
			
		||||
        mainBox.add_child(this.cancelButton);
 | 
			
		||||
 | 
			
		||||
        this._buttonBox.add(this._defaultButtonWell,
 | 
			
		||||
                            { expand: true,
 | 
			
		||||
                              x_fill: false,
 | 
			
		||||
                              y_fill: false,
 | 
			
		||||
                              x_align: St.Align.END,
 | 
			
		||||
                              y_align: St.Align.MIDDLE });
 | 
			
		||||
        this.nextButton = new St.Button({ style_class: 'modal-dialog-button button',
 | 
			
		||||
                                          button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
 | 
			
		||||
                                          reactive: true,
 | 
			
		||||
                                          can_focus: true,
 | 
			
		||||
                                          label: _("Next") });
 | 
			
		||||
        this.nextButton.connect('clicked', () => this.emit('next'));
 | 
			
		||||
        this.nextButton.add_style_pseudo_class('default');
 | 
			
		||||
        this._buttonBox.add(this.nextButton,
 | 
			
		||||
                            { expand: false,
 | 
			
		||||
                              x_fill: false,
 | 
			
		||||
                              y_fill: false,
 | 
			
		||||
                              x_align: St.Align.END,
 | 
			
		||||
                              y_align: St.Align.END });
 | 
			
		||||
        this._entry = new St.Entry({
 | 
			
		||||
            style_class: 'login-dialog-prompt-entry',
 | 
			
		||||
            can_focus: true,
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
        });
 | 
			
		||||
        ShellEntry.addContextMenu(this._entry, { isPassword: true, actionMode: Shell.ActionMode.NONE });
 | 
			
		||||
 | 
			
		||||
        this._updateNextButtonSensitivity(this._entry.text.length > 0);
 | 
			
		||||
        mainBox.add_child(this._entry);
 | 
			
		||||
 | 
			
		||||
        this._entry.grab_key_focus();
 | 
			
		||||
        this._entry.clutter_text.connect('activate', () => this.emit('next'));
 | 
			
		||||
        this._entry.clutter_text.connect('text-changed', () => {
 | 
			
		||||
            if (!this._userVerifier.hasPendingMessages)
 | 
			
		||||
                this._fadeOutMessage();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
            this._updateNextButtonSensitivity(this._entry.text.length > 0 || this.verificationStatus == AuthPromptStatus.VERIFYING);
 | 
			
		||||
        });
 | 
			
		||||
        this._entry.clutter_text.connect('activate', () => {
 | 
			
		||||
            if (this.nextButton.reactive)
 | 
			
		||||
                this.emit('next');
 | 
			
		||||
        });
 | 
			
		||||
        this._defaultButtonWell = new St.Widget({ layout_manager: new Clutter.BinLayout() });
 | 
			
		||||
        this._defaultButtonWellActor = null;
 | 
			
		||||
        mainBox.add_child(this._defaultButtonWell);
 | 
			
		||||
 | 
			
		||||
        this._spinner = new Animation.Spinner(DEFAULT_BUTTON_WELL_ICON_SIZE);
 | 
			
		||||
        this._spinner.actor.opacity = 0;
 | 
			
		||||
        this._spinner.actor.show();
 | 
			
		||||
        this._defaultButtonWell.add_child(this._spinner.actor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onAskQuestion(verifier, serviceName, question, passwordChar) {
 | 
			
		||||
@@ -191,16 +164,6 @@ var AuthPrompt = class {
 | 
			
		||||
        }
 | 
			
		||||
        this.setPasswordChar(passwordChar);
 | 
			
		||||
        this.setQuestion(question);
 | 
			
		||||
 | 
			
		||||
        if (passwordChar) {
 | 
			
		||||
            if (this._userVerifier.reauthenticating)
 | 
			
		||||
                this.nextButton.label = _("Unlock");
 | 
			
		||||
            else
 | 
			
		||||
                this.nextButton.label = C_("button", "Sign In");
 | 
			
		||||
        } else {
 | 
			
		||||
            this.nextButton.label = _("Next");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.updateSensitivity(true);
 | 
			
		||||
        this.emit('prompted');
 | 
			
		||||
    }
 | 
			
		||||
@@ -241,6 +204,35 @@ var AuthPrompt = class {
 | 
			
		||||
        this.updateSensitivity(canRetry);
 | 
			
		||||
        this.setActorInDefaultButtonWell(null);
 | 
			
		||||
        this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
 | 
			
		||||
 | 
			
		||||
        this._wiggle();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _wiggle() {
 | 
			
		||||
        // Accelerate before wiggling
 | 
			
		||||
        this._entry.ease({
 | 
			
		||||
            translation_x: -WIGGLE_OFFSET,
 | 
			
		||||
            duration: WIGGLE_DURATION,
 | 
			
		||||
            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
            onComplete: () => {
 | 
			
		||||
                // Wiggle
 | 
			
		||||
                this._entry.ease({
 | 
			
		||||
                    translation_x: WIGGLE_OFFSET,
 | 
			
		||||
                    duration: WIGGLE_DURATION,
 | 
			
		||||
                    mode: Clutter.AnimationMode.LINEAR,
 | 
			
		||||
                    repeat_count: N_WIGGLES,
 | 
			
		||||
                    auto_reverse: true,
 | 
			
		||||
                    onComplete: () => {
 | 
			
		||||
                        // Decelerate and return to the original position
 | 
			
		||||
                        this._entry.ease({
 | 
			
		||||
                            translation_x: 0,
 | 
			
		||||
                            duration: WIGGLE_DURATION,
 | 
			
		||||
                            mode: Clutter.AnimationMode.EASE_IN_QUAD,
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onVerificationComplete() {
 | 
			
		||||
@@ -393,13 +385,7 @@ var AuthPrompt = class {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateNextButtonSensitivity(sensitive) {
 | 
			
		||||
        this.nextButton.reactive = sensitive;
 | 
			
		||||
        this.nextButton.can_focus = sensitive;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateSensitivity(sensitive) {
 | 
			
		||||
        this._updateNextButtonSensitivity(sensitive && (this._entry.text.length > 0 || this.verificationStatus == AuthPromptStatus.VERIFYING));
 | 
			
		||||
        this._entry.reactive = sensitive;
 | 
			
		||||
        this._entry.clutter_text.editable = sensitive;
 | 
			
		||||
    }
 | 
			
		||||
@@ -430,7 +416,6 @@ var AuthPrompt = class {
 | 
			
		||||
        let oldStatus = this.verificationStatus;
 | 
			
		||||
        this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
 | 
			
		||||
        this.cancelButton.reactive = true;
 | 
			
		||||
        this.nextButton.label = _("Next");
 | 
			
		||||
        this._preemptiveAnswer = null;
 | 
			
		||||
 | 
			
		||||
        if (this._userVerifier)
 | 
			
		||||
 
 | 
			
		||||
@@ -105,6 +105,16 @@ function _easeActor(actor, params) {
 | 
			
		||||
        actor.set_easing_delay(params.delay);
 | 
			
		||||
    delete params.delay;
 | 
			
		||||
 | 
			
		||||
    let repeat_count = 0;
 | 
			
		||||
    if (params.repeat_count != undefined)
 | 
			
		||||
        repeat_count = params.repeat_count;
 | 
			
		||||
    delete params.repeat_count;
 | 
			
		||||
 | 
			
		||||
    let auto_reverse = false;
 | 
			
		||||
    if (params.auto_reverse != undefined)
 | 
			
		||||
        auto_reverse = params.auto_reverse;
 | 
			
		||||
    delete params.auto_reverse;
 | 
			
		||||
 | 
			
		||||
    if (params.mode != undefined)
 | 
			
		||||
        actor.set_easing_mode(params.mode);
 | 
			
		||||
    delete params.mode;
 | 
			
		||||
@@ -124,10 +134,14 @@ function _easeActor(actor, params) {
 | 
			
		||||
    let transition = animatedProps.map(p => actor.get_transition(p))
 | 
			
		||||
        .find(t => t !== null);
 | 
			
		||||
 | 
			
		||||
    if (transition)
 | 
			
		||||
    if (transition) {
 | 
			
		||||
        transition.repeat_count = repeat_count;
 | 
			
		||||
        transition.auto_reverse = auto_reverse;
 | 
			
		||||
 | 
			
		||||
        transition.connect('stopped', (t, finished) => callback(finished));
 | 
			
		||||
    else
 | 
			
		||||
    } else {
 | 
			
		||||
        callback(true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _easeActorProperty(actor, propName, target, params) {
 | 
			
		||||
@@ -140,6 +154,16 @@ function _easeActorProperty(actor, propName, target, params) {
 | 
			
		||||
        params.duration = adjustAnimationTime(params.duration);
 | 
			
		||||
    let duration = Math.floor(params.duration || 0);
 | 
			
		||||
 | 
			
		||||
    let repeat_count = 0;
 | 
			
		||||
    if (params.repeat_count != undefined)
 | 
			
		||||
        repeat_count = params.repeat_count;
 | 
			
		||||
    delete params.repeat_count;
 | 
			
		||||
 | 
			
		||||
    let auto_reverse = false;
 | 
			
		||||
    if (params.auto_reverse != undefined)
 | 
			
		||||
        auto_reverse = params.auto_reverse;
 | 
			
		||||
    delete params.auto_reverse;
 | 
			
		||||
 | 
			
		||||
    // Copy Clutter's behavior for implicit animations, see
 | 
			
		||||
    // should_skip_implicit_transition()
 | 
			
		||||
    if (actor instanceof Clutter.Actor && !actor.mapped)
 | 
			
		||||
@@ -166,7 +190,9 @@ function _easeActorProperty(actor, propName, target, params) {
 | 
			
		||||
    let transition = new Clutter.PropertyTransition(Object.assign({
 | 
			
		||||
        property_name: propName,
 | 
			
		||||
        interval: new Clutter.Interval({ value_type: pspec.value_type }),
 | 
			
		||||
        remove_on_complete: true
 | 
			
		||||
        remove_on_complete: true,
 | 
			
		||||
        repeat_count: repeat_count,
 | 
			
		||||
        auto_reverse: auto_reverse,
 | 
			
		||||
    }, params));
 | 
			
		||||
    actor.add_transition(propName, transition);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const { AccountsService, Clutter, Cogl, Gio, GLib,
 | 
			
		||||
        GnomeDesktop, GObject, Meta, Shell, St } = imports.gi;
 | 
			
		||||
        GObject, Meta, Shell, St } = imports.gi;
 | 
			
		||||
const Cairo = imports.cairo;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
@@ -16,6 +16,7 @@ const Overview = imports.ui.overview;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const ShellDBus = imports.ui.shellDBus;
 | 
			
		||||
const SmartcardManager = imports.misc.smartcardManager;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
 | 
			
		||||
const LOCK_ENABLED_KEY = 'lock-enabled';
 | 
			
		||||
@@ -25,16 +26,14 @@ const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
 | 
			
		||||
const DISABLE_LOCK_KEY = 'disable-lock-screen';
 | 
			
		||||
 | 
			
		||||
const LOCKED_STATE_STR = 'screenShield.locked';
 | 
			
		||||
 | 
			
		||||
const BLUR_BRIGHTNESS = 0.55;
 | 
			
		||||
const BLUR_RADIUS = 200;
 | 
			
		||||
 | 
			
		||||
// fraction of screen height the arrow must reach before completing
 | 
			
		||||
// the slide up automatically
 | 
			
		||||
var ARROW_DRAG_THRESHOLD = 0.1;
 | 
			
		||||
 | 
			
		||||
// Parameters for the arrow animation
 | 
			
		||||
var N_ARROWS = 3;
 | 
			
		||||
var ARROW_ANIMATION_TIME = 600;
 | 
			
		||||
var ARROW_ANIMATION_PEAK_OPACITY = 0.4;
 | 
			
		||||
var ARROW_IDLE_TIME = 30000; // ms
 | 
			
		||||
 | 
			
		||||
var SUMMARY_ICON_SIZE = 48;
 | 
			
		||||
 | 
			
		||||
// ScreenShield animation time
 | 
			
		||||
@@ -46,373 +45,6 @@ var STANDARD_FADE_TIME = 10000;
 | 
			
		||||
var MANUAL_FADE_TIME = 300;
 | 
			
		||||
var CURTAIN_SLIDE_TIME = 300;
 | 
			
		||||
 | 
			
		||||
var Clock = class {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'screen-shield-clock',
 | 
			
		||||
                                        vertical: true });
 | 
			
		||||
 | 
			
		||||
        this._time = new St.Label({ style_class: 'screen-shield-clock-time' });
 | 
			
		||||
        this._date = new St.Label({ style_class: 'screen-shield-clock-date' });
 | 
			
		||||
 | 
			
		||||
        this.actor.add(this._time, { x_align: St.Align.MIDDLE });
 | 
			
		||||
        this.actor.add(this._date, { x_align: St.Align.MIDDLE });
 | 
			
		||||
 | 
			
		||||
        this._wallClock = new GnomeDesktop.WallClock({ time_only: true });
 | 
			
		||||
        this._wallClock.connect('notify::clock', this._updateClock.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._updateClock();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateClock() {
 | 
			
		||||
        this._time.text = this._wallClock.clock;
 | 
			
		||||
 | 
			
		||||
        let date = new Date();
 | 
			
		||||
        /* Translators: This is a time format for a date in
 | 
			
		||||
           long format */
 | 
			
		||||
        let dateFormat = Shell.util_translate_time_string(N_("%A, %B %d"));
 | 
			
		||||
        this._date.text = date.toLocaleFormat(dateFormat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    destroy() {
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
        this._wallClock.run_dispose();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var NotificationsBox = class {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.actor = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                        name: 'screenShieldNotifications',
 | 
			
		||||
                                        style_class: 'screen-shield-notifications-container' });
 | 
			
		||||
 | 
			
		||||
        this._scrollView = new St.ScrollView({ x_fill: false, x_align: St.Align.START,
 | 
			
		||||
                                               hscrollbar_policy: St.PolicyType.NEVER });
 | 
			
		||||
        this._notificationBox = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                                   style_class: 'screen-shield-notifications-container' });
 | 
			
		||||
        this._scrollView.add_actor(this._notificationBox);
 | 
			
		||||
 | 
			
		||||
        this.actor.add(this._scrollView, { x_fill: true, x_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        this._sources = new Map();
 | 
			
		||||
        Main.messageTray.getSources().forEach(source => {
 | 
			
		||||
            this._sourceAdded(Main.messageTray, source, true);
 | 
			
		||||
        });
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
 | 
			
		||||
        this._sourceAddedId = Main.messageTray.connect('source-added', this._sourceAdded.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    destroy() {
 | 
			
		||||
        if (this._sourceAddedId) {
 | 
			
		||||
            Main.messageTray.disconnect(this._sourceAddedId);
 | 
			
		||||
            this._sourceAddedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let items = this._sources.entries();
 | 
			
		||||
        for (let [source, obj] of items) {
 | 
			
		||||
            this._removeSource(source, obj);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateVisibility() {
 | 
			
		||||
        this._notificationBox.visible =
 | 
			
		||||
            this._notificationBox.get_children().some(a => a.visible);
 | 
			
		||||
 | 
			
		||||
        this.actor.visible = this._notificationBox.visible;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _makeNotificationCountText(count, isChat) {
 | 
			
		||||
        if (isChat)
 | 
			
		||||
            return ngettext("%d new message", "%d new messages", count).format(count);
 | 
			
		||||
        else
 | 
			
		||||
            return ngettext("%d new notification", "%d new notifications", count).format(count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _makeNotificationSource(source, box) {
 | 
			
		||||
        let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
 | 
			
		||||
        box.add(sourceActor, { y_fill: true });
 | 
			
		||||
 | 
			
		||||
        let textBox = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        box.add(textBox, { y_fill: false, y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        let title = new St.Label({ text: source.title,
 | 
			
		||||
                                   style_class: 'screen-shield-notification-label' });
 | 
			
		||||
        textBox.add(title);
 | 
			
		||||
 | 
			
		||||
        let count = source.unseenCount;
 | 
			
		||||
        let countLabel = new St.Label({ text: this._makeNotificationCountText(count, source.isChat),
 | 
			
		||||
                                        style_class: 'screen-shield-notification-count-text' });
 | 
			
		||||
        textBox.add(countLabel);
 | 
			
		||||
 | 
			
		||||
        box.visible = count != 0;
 | 
			
		||||
        return [title, countLabel];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _makeNotificationDetailedSource(source, box) {
 | 
			
		||||
        let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
 | 
			
		||||
        let sourceBin = new St.Bin({ y_align: St.Align.START,
 | 
			
		||||
                                     x_align: St.Align.START,
 | 
			
		||||
                                     child: sourceActor });
 | 
			
		||||
        box.add(sourceBin);
 | 
			
		||||
 | 
			
		||||
        let textBox = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        box.add(textBox, { y_fill: false, y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        let title = new St.Label({ text: source.title,
 | 
			
		||||
                                   style_class: 'screen-shield-notification-label' });
 | 
			
		||||
        textBox.add(title);
 | 
			
		||||
 | 
			
		||||
        let visible = false;
 | 
			
		||||
        for (let i = 0; i < source.notifications.length; i++) {
 | 
			
		||||
            let n = source.notifications[i];
 | 
			
		||||
 | 
			
		||||
            if (n.acknowledged)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            let body = '';
 | 
			
		||||
            if (n.bannerBodyText) {
 | 
			
		||||
                body = n.bannerBodyMarkup
 | 
			
		||||
                    ? n.bannerBodyText
 | 
			
		||||
                    : GLib.markup_escape_text(n.bannerBodyText, -1);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let label = new St.Label({ style_class: 'screen-shield-notification-count-text' });
 | 
			
		||||
            label.clutter_text.set_markup('<b>' + n.title + '</b> ' + body);
 | 
			
		||||
            textBox.add(label);
 | 
			
		||||
 | 
			
		||||
            visible = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        box.visible = visible;
 | 
			
		||||
        return [title, null];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _shouldShowDetails(source) {
 | 
			
		||||
        return source.policy.detailsInLockScreen ||
 | 
			
		||||
               source.narrowestPrivacyScope == MessageTray.PrivacyScope.SYSTEM;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _showSource(source, obj, box) {
 | 
			
		||||
        if (obj.detailed) {
 | 
			
		||||
            [obj.titleLabel, obj.countLabel] = this._makeNotificationDetailedSource(source, box);
 | 
			
		||||
        } else {
 | 
			
		||||
            [obj.titleLabel, obj.countLabel] = this._makeNotificationSource(source, box);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        box.visible = obj.visible && (source.unseenCount > 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sourceAdded(tray, source, initial) {
 | 
			
		||||
        let obj = {
 | 
			
		||||
            visible: source.policy.showInLockScreen,
 | 
			
		||||
            detailed: this._shouldShowDetails(source),
 | 
			
		||||
            sourceDestroyId: 0,
 | 
			
		||||
            sourceCountChangedId: 0,
 | 
			
		||||
            sourceTitleChangedId: 0,
 | 
			
		||||
            sourceUpdatedId: 0,
 | 
			
		||||
            sourceBox: null,
 | 
			
		||||
            titleLabel: null,
 | 
			
		||||
            countLabel: null,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        obj.sourceBox = new St.BoxLayout({ style_class: 'screen-shield-notification-source',
 | 
			
		||||
                                           x_expand: true });
 | 
			
		||||
        this._showSource(source, obj, obj.sourceBox);
 | 
			
		||||
        this._notificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        obj.sourceCountChangedId = source.connect('count-updated', source => {
 | 
			
		||||
            this._countChanged(source, obj);
 | 
			
		||||
        });
 | 
			
		||||
        obj.sourceTitleChangedId = source.connect('title-changed', source => {
 | 
			
		||||
            this._titleChanged(source, obj);
 | 
			
		||||
        });
 | 
			
		||||
        obj.policyChangedId = source.policy.connect('policy-changed', (policy, key) => {
 | 
			
		||||
            if (key == 'show-in-lock-screen')
 | 
			
		||||
                this._visibleChanged(source, obj);
 | 
			
		||||
            else
 | 
			
		||||
                this._detailedChanged(source, obj);
 | 
			
		||||
        });
 | 
			
		||||
        obj.sourceDestroyId = source.connect('destroy', source => {
 | 
			
		||||
            this._onSourceDestroy(source, obj);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._sources.set(source, obj);
 | 
			
		||||
 | 
			
		||||
        if (!initial) {
 | 
			
		||||
            // block scrollbars while animating, if they're not needed now
 | 
			
		||||
            let boxHeight = this._notificationBox.height;
 | 
			
		||||
            if (this._scrollView.height >= boxHeight)
 | 
			
		||||
                this._scrollView.vscrollbar_policy = St.PolicyType.NEVER;
 | 
			
		||||
 | 
			
		||||
            let widget = obj.sourceBox;
 | 
			
		||||
            let [, natHeight] = widget.get_preferred_height(-1);
 | 
			
		||||
            widget.height = 0;
 | 
			
		||||
            widget.ease({
 | 
			
		||||
                height: natHeight,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
                duration: 250,
 | 
			
		||||
                onComplete: () => {
 | 
			
		||||
                    this._scrollView.vscrollbar_policy = St.PolicyType.AUTOMATIC;
 | 
			
		||||
                    widget.set_height(-1);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this._updateVisibility();
 | 
			
		||||
            if (obj.sourceBox.visible)
 | 
			
		||||
                this.emit('wake-up-screen');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _titleChanged(source, obj) {
 | 
			
		||||
        obj.titleLabel.text = source.title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _countChanged(source, obj) {
 | 
			
		||||
        // A change in the number of notifications may change whether we show
 | 
			
		||||
        // details.
 | 
			
		||||
        let newDetailed = this._shouldShowDetails(source);
 | 
			
		||||
        let oldDetailed = obj.detailed;
 | 
			
		||||
 | 
			
		||||
        obj.detailed = newDetailed;
 | 
			
		||||
 | 
			
		||||
        if (obj.detailed || oldDetailed != newDetailed) {
 | 
			
		||||
            // A new notification was pushed, or a previous notification was destroyed.
 | 
			
		||||
            // Give up, and build the list again.
 | 
			
		||||
 | 
			
		||||
            obj.sourceBox.destroy_all_children();
 | 
			
		||||
            obj.titleLabel = obj.countLabel = null;
 | 
			
		||||
            this._showSource(source, obj, obj.sourceBox);
 | 
			
		||||
        } else {
 | 
			
		||||
            let count = source.unseenCount;
 | 
			
		||||
            obj.countLabel.text = this._makeNotificationCountText(count, source.isChat);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        obj.sourceBox.visible = obj.visible && (source.unseenCount > 0);
 | 
			
		||||
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        if (obj.sourceBox.visible)
 | 
			
		||||
            this.emit('wake-up-screen');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _visibleChanged(source, obj) {
 | 
			
		||||
        if (obj.visible == source.policy.showInLockScreen)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        obj.visible = source.policy.showInLockScreen;
 | 
			
		||||
        obj.sourceBox.visible = obj.visible && source.unseenCount > 0;
 | 
			
		||||
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        if (obj.sourceBox.visible)
 | 
			
		||||
            this.emit('wake-up-screen');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _detailedChanged(source, obj) {
 | 
			
		||||
        let newDetailed = this._shouldShowDetails(source);
 | 
			
		||||
        if (obj.detailed == newDetailed)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        obj.detailed = newDetailed;
 | 
			
		||||
 | 
			
		||||
        obj.sourceBox.destroy_all_children();
 | 
			
		||||
        obj.titleLabel = obj.countLabel = null;
 | 
			
		||||
        this._showSource(source, obj, obj.sourceBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onSourceDestroy(source, obj) {
 | 
			
		||||
        this._removeSource(source, obj);
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _removeSource(source, obj) {
 | 
			
		||||
        obj.sourceBox.destroy();
 | 
			
		||||
        obj.sourceBox = obj.titleLabel = obj.countLabel = null;
 | 
			
		||||
 | 
			
		||||
        source.disconnect(obj.sourceDestroyId);
 | 
			
		||||
        source.disconnect(obj.sourceCountChangedId);
 | 
			
		||||
        source.disconnect(obj.sourceTitleChangedId);
 | 
			
		||||
        source.policy.disconnect(obj.policyChangedId);
 | 
			
		||||
 | 
			
		||||
        this._sources.delete(source);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
Signals.addSignalMethods(NotificationsBox.prototype);
 | 
			
		||||
 | 
			
		||||
var Arrow = GObject.registerClass(
 | 
			
		||||
class ScreenShieldArrow extends St.Bin {
 | 
			
		||||
    _init(params) {
 | 
			
		||||
        super._init(params);
 | 
			
		||||
        this.x_fill = this.y_fill = true;
 | 
			
		||||
 | 
			
		||||
        this._drawingArea = new St.DrawingArea();
 | 
			
		||||
        this._drawingArea.connect('repaint', this._drawArrow.bind(this));
 | 
			
		||||
        this.child = this._drawingArea;
 | 
			
		||||
 | 
			
		||||
        this._shadowHelper = null;
 | 
			
		||||
        this._shadowWidth = this._shadowHeight = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _drawArrow(arrow) {
 | 
			
		||||
        let cr = arrow.get_context();
 | 
			
		||||
        let [w, h] = arrow.get_surface_size();
 | 
			
		||||
        let node = this.get_theme_node();
 | 
			
		||||
        let thickness = node.get_length('-arrow-thickness');
 | 
			
		||||
 | 
			
		||||
        Clutter.cairo_set_source_color(cr, node.get_foreground_color());
 | 
			
		||||
 | 
			
		||||
        cr.setLineCap(Cairo.LineCap.ROUND);
 | 
			
		||||
        cr.setLineWidth(thickness);
 | 
			
		||||
 | 
			
		||||
        cr.moveTo(thickness / 2, h - thickness / 2);
 | 
			
		||||
        cr.lineTo(w / 2, thickness);
 | 
			
		||||
        cr.lineTo(w - thickness / 2, h - thickness / 2);
 | 
			
		||||
        cr.stroke();
 | 
			
		||||
        cr.$dispose();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_paint_volume(volume) {
 | 
			
		||||
        if (!super.vfunc_get_paint_volume(volume))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (!this._shadow)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        let shadowBox = new Clutter.ActorBox();
 | 
			
		||||
        this._shadow.get_box(this._drawingArea.get_allocation_box(), shadowBox);
 | 
			
		||||
 | 
			
		||||
        volume.set_width(Math.max(shadowBox.x2 - shadowBox.x1, volume.get_width()));
 | 
			
		||||
        volume.set_height(Math.max(shadowBox.y2 - shadowBox.y1, volume.get_height()));
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_style_changed() {
 | 
			
		||||
        let node = this.get_theme_node();
 | 
			
		||||
        this._shadow = node.get_shadow('-arrow-shadow');
 | 
			
		||||
        if (this._shadow)
 | 
			
		||||
            this._shadowHelper = St.ShadowHelper.new(this._shadow);
 | 
			
		||||
        else
 | 
			
		||||
            this._shadowHelper = null;
 | 
			
		||||
 | 
			
		||||
        super.vfunc_style_changed();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_paint() {
 | 
			
		||||
        if (this._shadowHelper) {
 | 
			
		||||
            this._shadowHelper.update(this._drawingArea);
 | 
			
		||||
 | 
			
		||||
            let allocation = this._drawingArea.get_allocation_box();
 | 
			
		||||
            let paintOpacity = this._drawingArea.get_paint_opacity();
 | 
			
		||||
            let framebuffer = Cogl.get_draw_framebuffer();
 | 
			
		||||
 | 
			
		||||
            this._shadowHelper.paint(framebuffer, allocation, paintOpacity);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._drawingArea.paint();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function clamp(value, min, max) {
 | 
			
		||||
    return Math.max(min, Math.min(max, value));
 | 
			
		||||
}
 | 
			
		||||
@@ -430,67 +62,24 @@ var ScreenShield = class {
 | 
			
		||||
        this.actor = Main.layoutManager.screenShieldGroup;
 | 
			
		||||
 | 
			
		||||
        this._lockScreenState = MessageTray.State.HIDDEN;
 | 
			
		||||
        this._lockScreenGroup = new St.Widget({
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
            y_expand: true,
 | 
			
		||||
            reactive: true,
 | 
			
		||||
            can_focus: true,
 | 
			
		||||
            name: 'lockScreenGroup',
 | 
			
		||||
            visible: false,
 | 
			
		||||
        });
 | 
			
		||||
        this._lockScreenGroup.connect('key-press-event',
 | 
			
		||||
                                      this._onLockScreenKeyPress.bind(this));
 | 
			
		||||
        this._lockScreenGroup.connect('scroll-event',
 | 
			
		||||
                                      this._onLockScreenScroll.bind(this));
 | 
			
		||||
        Main.ctrlAltTabManager.addGroup(this._lockScreenGroup, _("Lock"), 'changes-prevent-symbolic');
 | 
			
		||||
 | 
			
		||||
        this._lockScreenContents = new St.Widget({ layout_manager: new Clutter.BinLayout(),
 | 
			
		||||
                                                   name: 'lockScreenContents' });
 | 
			
		||||
        this._lockScreenContents.add_constraint(new Layout.MonitorConstraint({ primary: true }));
 | 
			
		||||
 | 
			
		||||
        this._lockScreenGroup.add_actor(this._lockScreenContents);
 | 
			
		||||
 | 
			
		||||
        this._backgroundGroup = new Clutter.Actor();
 | 
			
		||||
 | 
			
		||||
        this._lockScreenGroup.add_actor(this._backgroundGroup);
 | 
			
		||||
        this._backgroundGroup.lower_bottom();
 | 
			
		||||
        this._bgManagers = [];
 | 
			
		||||
 | 
			
		||||
        this._updateBackgrounds();
 | 
			
		||||
        Main.layoutManager.connect('monitors-changed', this._updateBackgrounds.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._arrowAnimationId = 0;
 | 
			
		||||
        this._arrowWatchId = 0;
 | 
			
		||||
        this._arrowActiveWatchId = 0;
 | 
			
		||||
        this._arrowContainer = new St.BoxLayout({ style_class: 'screen-shield-arrows',
 | 
			
		||||
                                                  vertical: true,
 | 
			
		||||
                                                  x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
                                                  y_align: Clutter.ActorAlign.END,
 | 
			
		||||
                                                  // HACK: without these, ClutterBinLayout
 | 
			
		||||
                                                  // ignores alignment properties on the actor
 | 
			
		||||
                                                  x_expand: true,
 | 
			
		||||
                                                  y_expand: true });
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < N_ARROWS; i++) {
 | 
			
		||||
            let arrow = new Arrow({ opacity: 0 });
 | 
			
		||||
            this._arrowContainer.add_actor(arrow);
 | 
			
		||||
        }
 | 
			
		||||
        this._lockScreenContents.add_actor(this._arrowContainer);
 | 
			
		||||
 | 
			
		||||
        this._dragAction = new Clutter.GestureAction();
 | 
			
		||||
        this._dragAction.connect('gesture-begin', this._onDragBegin.bind(this));
 | 
			
		||||
        this._dragAction.connect('gesture-progress', this._onDragMotion.bind(this));
 | 
			
		||||
        this._dragAction.connect('gesture-end', this._onDragEnd.bind(this));
 | 
			
		||||
        this._lockScreenGroup.add_action(this._dragAction);
 | 
			
		||||
 | 
			
		||||
        this._lockDialogGroup = new St.Widget({ x_expand: true,
 | 
			
		||||
                                                y_expand: true,
 | 
			
		||||
                                                reactive: true,
 | 
			
		||||
                                                pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }),
 | 
			
		||||
                                                name: 'lockDialogGroup' });
 | 
			
		||||
        this._lockDialogGroup.connect('key-press-event',
 | 
			
		||||
                                      this._onLockScreenKeyPress.bind(this));
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._lockDialogGroup);
 | 
			
		||||
        this.actor.add_actor(this._lockScreenGroup);
 | 
			
		||||
 | 
			
		||||
        this._backgroundGroup = new Clutter.Actor();
 | 
			
		||||
        this._lockDialogGroup.add_actor(this._backgroundGroup);
 | 
			
		||||
        this._backgroundGroup.lower_bottom();
 | 
			
		||||
        this._bgManagers = [];
 | 
			
		||||
 | 
			
		||||
        this._updateBackgrounds();
 | 
			
		||||
        Main.layoutManager.connect('monitors-changed', this._updateBackgrounds.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._presence = new GnomeSession.Presence((proxy, error) => {
 | 
			
		||||
            if (error) {
 | 
			
		||||
@@ -510,14 +99,14 @@ var ScreenShield = class {
 | 
			
		||||
        this._smartcardManager.connect('smartcard-inserted',
 | 
			
		||||
                                       (manager, token) => {
 | 
			
		||||
                                           if (this._isLocked && token.UsedToLogin)
 | 
			
		||||
                                               this._liftShield(true, 0);
 | 
			
		||||
                                               this._liftShield();
 | 
			
		||||
                                       });
 | 
			
		||||
 | 
			
		||||
        this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
 | 
			
		||||
        this._oVirtCredentialsManager.connect('user-authenticated',
 | 
			
		||||
                                              () => {
 | 
			
		||||
                                                  if (this._isLocked)
 | 
			
		||||
                                                      this._liftShield(true, 0);
 | 
			
		||||
                                                      this._liftShield();
 | 
			
		||||
                                              });
 | 
			
		||||
 | 
			
		||||
        this._loginManager = LoginManager.getLoginManager();
 | 
			
		||||
@@ -542,7 +131,6 @@ var ScreenShield = class {
 | 
			
		||||
        this._lockSettings.connect(`changed::${DISABLE_LOCK_KEY}`, this._syncInhibitor.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._isModal = false;
 | 
			
		||||
        this._hasLockScreen = false;
 | 
			
		||||
        this._isGreeter = false;
 | 
			
		||||
        this._isActive = false;
 | 
			
		||||
        this._isLocked = false;
 | 
			
		||||
@@ -585,6 +173,7 @@ var ScreenShield = class {
 | 
			
		||||
    _createBackground(monitorIndex) {
 | 
			
		||||
        let monitor = Main.layoutManager.monitors[monitorIndex];
 | 
			
		||||
        let widget = new St.Widget({ style_class: 'screen-shield-background',
 | 
			
		||||
                                     clip_to_allocation: true,
 | 
			
		||||
                                     x: monitor.x,
 | 
			
		||||
                                     y: monitor.y,
 | 
			
		||||
                                     width: monitor.width,
 | 
			
		||||
@@ -598,12 +187,27 @@ var ScreenShield = class {
 | 
			
		||||
        this._bgManagers.push(bgManager);
 | 
			
		||||
 | 
			
		||||
        this._backgroundGroup.add_child(widget);
 | 
			
		||||
 | 
			
		||||
        widget.add_effect(new Shell.BlurEffect({
 | 
			
		||||
            blur_radius: BLUR_RADIUS,
 | 
			
		||||
            vertical: true,
 | 
			
		||||
        }));
 | 
			
		||||
        widget.add_effect(new Shell.BlurEffect({
 | 
			
		||||
            blur_radius: BLUR_RADIUS,
 | 
			
		||||
            brightness: BLUR_BRIGHTNESS,
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateBackgrounds() {
 | 
			
		||||
        let isGreeter = Main.sessionMode.isGreeter;
 | 
			
		||||
        this._backgroundGroup.visible = !isGreeter;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._bgManagers.length; i++)
 | 
			
		||||
            this._bgManagers[i].destroy();
 | 
			
		||||
 | 
			
		||||
        if (isGreeter)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._bgManagers = [];
 | 
			
		||||
        this._backgroundGroup.destroy_all_children();
 | 
			
		||||
 | 
			
		||||
@@ -611,28 +215,17 @@ var ScreenShield = class {
 | 
			
		||||
            this._createBackground(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _liftShield(onPrimary, velocity) {
 | 
			
		||||
    _liftShield() {
 | 
			
		||||
        if (this._isLocked) {
 | 
			
		||||
            if (this._ensureUnlockDialog(onPrimary, true /* allowCancel */))
 | 
			
		||||
                this._hideLockScreen(true /* animate */, velocity);
 | 
			
		||||
            if (this._ensureUnlockDialog(true /* allowCancel */))
 | 
			
		||||
                this._hideLockScreen();
 | 
			
		||||
        } else {
 | 
			
		||||
            this.deactivate(true /* animate */);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _maybeCancelDialog() {
 | 
			
		||||
        if (!this._dialog)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._dialog.cancel();
 | 
			
		||||
        if (this._isGreeter) {
 | 
			
		||||
            // LoginDialog.cancel() will grab the key focus
 | 
			
		||||
            // on its own, so ensure it stays on lock screen
 | 
			
		||||
            // instead
 | 
			
		||||
            this._lockScreenGroup.grab_key_focus();
 | 
			
		||||
        } else {
 | 
			
		||||
            this._dialog = null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _becomeModal() {
 | 
			
		||||
@@ -672,31 +265,10 @@ var ScreenShield = class {
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        if (this._isLocked &&
 | 
			
		||||
            this._ensureUnlockDialog(true, true) &&
 | 
			
		||||
            this._ensureUnlockDialog(true) &&
 | 
			
		||||
            GLib.unichar_isgraph(unichar))
 | 
			
		||||
            this._dialog.addCharacter(unichar);
 | 
			
		||||
 | 
			
		||||
        this._liftShield(true, 0);
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onLockScreenScroll(actor, event) {
 | 
			
		||||
        if (this._lockScreenState != MessageTray.State.SHOWN)
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        let delta = 0;
 | 
			
		||||
        if (event.get_scroll_direction() == Clutter.ScrollDirection.SMOOTH)
 | 
			
		||||
            delta = Math.abs(event.get_scroll_delta()[0]);
 | 
			
		||||
        else
 | 
			
		||||
            delta = 5;
 | 
			
		||||
 | 
			
		||||
        this._lockScreenScrollCounter += delta;
 | 
			
		||||
 | 
			
		||||
        // 7 standard scrolls to lift up
 | 
			
		||||
        if (this._lockScreenScrollCounter > 35) {
 | 
			
		||||
            this._liftShield(true, 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -728,79 +300,6 @@ var ScreenShield = class {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _animateArrows() {
 | 
			
		||||
        let arrows = this._arrowContainer.get_children();
 | 
			
		||||
        let unitaryDelay = ARROW_ANIMATION_TIME / (arrows.length + 1);
 | 
			
		||||
        let maxOpacity = 255 * ARROW_ANIMATION_PEAK_OPACITY;
 | 
			
		||||
        for (let i = 0; i < arrows.length; i++) {
 | 
			
		||||
            arrows[i].opacity = 0;
 | 
			
		||||
            arrows[i].ease({
 | 
			
		||||
                opacity: maxOpacity,
 | 
			
		||||
                delay: unitaryDelay * (N_ARROWS - (i + 1)),
 | 
			
		||||
                duration: ARROW_ANIMATION_TIME / 2,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
                onComplete: () => {
 | 
			
		||||
                    arrows[i].ease({
 | 
			
		||||
                        opacity: 0,
 | 
			
		||||
                        duration: ARROW_ANIMATION_TIME / 2,
 | 
			
		||||
                        mode: Clutter.AnimationMode.EASE_IN_QUAD
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return GLib.SOURCE_CONTINUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDragBegin() {
 | 
			
		||||
        this._lockScreenGroup.remove_all_transitions();
 | 
			
		||||
        this._lockScreenState = MessageTray.State.HIDING;
 | 
			
		||||
 | 
			
		||||
        if (this._isLocked)
 | 
			
		||||
            this._ensureUnlockDialog(false, false);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDragMotion() {
 | 
			
		||||
        let [, origY] = this._dragAction.get_press_coords(0);
 | 
			
		||||
        let [, currentY] = this._dragAction.get_motion_coords(0);
 | 
			
		||||
 | 
			
		||||
        let newY = currentY - origY;
 | 
			
		||||
        newY = clamp(newY, -global.stage.height, 0);
 | 
			
		||||
 | 
			
		||||
        this._lockScreenGroup.y = newY;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDragEnd(_action, _actor, _eventX, _eventY, _modifiers) {
 | 
			
		||||
        if (this._lockScreenState != MessageTray.State.HIDING)
 | 
			
		||||
            return;
 | 
			
		||||
        if (this._lockScreenGroup.y < -(ARROW_DRAG_THRESHOLD * global.stage.height)) {
 | 
			
		||||
            // Complete motion automatically
 | 
			
		||||
            let [velocity_, velocityX_, velocityY] = this._dragAction.get_velocity(0);
 | 
			
		||||
            this._liftShield(true, -velocityY);
 | 
			
		||||
        } else {
 | 
			
		||||
            // restore the lock screen to its original place
 | 
			
		||||
            // try to use the same speed as the normal animation
 | 
			
		||||
            let h = global.stage.height;
 | 
			
		||||
            let duration = MANUAL_FADE_TIME * (-this._lockScreenGroup.y) / h;
 | 
			
		||||
            this._lockScreenGroup.remove_all_transitions();
 | 
			
		||||
            this._lockScreenGroup.ease({
 | 
			
		||||
                y: 0,
 | 
			
		||||
                duration,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_IN_QUAD,
 | 
			
		||||
                onComplete: () => {
 | 
			
		||||
                    this._lockScreenGroup.fixed_position_set = false;
 | 
			
		||||
                    this._lockScreenState = MessageTray.State.SHOWN;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this._maybeCancelDialog();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onStatusChanged(status) {
 | 
			
		||||
        if (status != GnomeSession.PresenceStatus.IDLE)
 | 
			
		||||
            return;
 | 
			
		||||
@@ -904,57 +403,19 @@ var ScreenShield = class {
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
        this._isGreeter = Main.sessionMode.isGreeter;
 | 
			
		||||
        this._isLocked = true;
 | 
			
		||||
        if (this._ensureUnlockDialog(true, true))
 | 
			
		||||
            this._hideLockScreen(false, 0);
 | 
			
		||||
        if (this._ensureUnlockDialog(true))
 | 
			
		||||
            this._hideLockScreen();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _hideLockScreenComplete() {
 | 
			
		||||
        if (Main.sessionMode.currentMode == 'lock-screen')
 | 
			
		||||
            Main.sessionMode.popMode('lock-screen');
 | 
			
		||||
 | 
			
		||||
        this._lockScreenState = MessageTray.State.HIDDEN;
 | 
			
		||||
        this._lockScreenGroup.hide();
 | 
			
		||||
 | 
			
		||||
        if (this._dialog) {
 | 
			
		||||
            this._dialog.grab_key_focus();
 | 
			
		||||
            this._dialog.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _hideLockScreen(animate, velocity) {
 | 
			
		||||
    _hideLockScreen() {
 | 
			
		||||
        if (this._lockScreenState == MessageTray.State.HIDDEN)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._lockScreenState = MessageTray.State.HIDING;
 | 
			
		||||
 | 
			
		||||
        this._lockScreenGroup.remove_all_transitions();
 | 
			
		||||
 | 
			
		||||
        if (animate) {
 | 
			
		||||
            // Tween the lock screen out of screen
 | 
			
		||||
            // if velocity is not specified (i.e. we come here from pressing ESC),
 | 
			
		||||
            // use the same speed regardless of original position
 | 
			
		||||
            // if velocity is specified, it's in pixels per milliseconds
 | 
			
		||||
            let h = global.stage.height;
 | 
			
		||||
            let delta = (h + this._lockScreenGroup.y);
 | 
			
		||||
            let minVelocity = global.stage.height / CURTAIN_SLIDE_TIME;
 | 
			
		||||
 | 
			
		||||
            velocity = Math.max(minVelocity, velocity);
 | 
			
		||||
            let duration = delta / velocity;
 | 
			
		||||
 | 
			
		||||
            this._lockScreenGroup.ease({
 | 
			
		||||
                y: -h,
 | 
			
		||||
                duration,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_IN_QUAD,
 | 
			
		||||
                onComplete: () => this._hideLockScreenComplete()
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            this._hideLockScreenComplete();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._lockScreenState = MessageTray.State.HIDDEN;
 | 
			
		||||
        this._cursorTracker.set_pointer_visible(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _ensureUnlockDialog(onPrimary, allowCancel) {
 | 
			
		||||
    _ensureUnlockDialog(allowCancel) {
 | 
			
		||||
        if (!this._dialog) {
 | 
			
		||||
            let constructor = Main.sessionMode.unlockDialog;
 | 
			
		||||
            if (!constructor) {
 | 
			
		||||
@@ -967,7 +428,7 @@ var ScreenShield = class {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            let time = global.get_current_time();
 | 
			
		||||
            if (!this._dialog.open(time, onPrimary)) {
 | 
			
		||||
            if (!this._dialog.open(time)) {
 | 
			
		||||
                // This is kind of an impossible error: we're already modal
 | 
			
		||||
                // by the time we reach this...
 | 
			
		||||
                log('Could not open login dialog: failed to acquire grab');
 | 
			
		||||
@@ -995,20 +456,17 @@ var ScreenShield = class {
 | 
			
		||||
        if (this._lockScreenState != MessageTray.State.HIDDEN)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._ensureLockScreen();
 | 
			
		||||
        this._lockDialogGroup.scale_x = 1;
 | 
			
		||||
        this._lockDialogGroup.scale_y = 1;
 | 
			
		||||
        this._ensureUnlockDialog(false);
 | 
			
		||||
 | 
			
		||||
        this._lockScreenGroup.show();
 | 
			
		||||
        this._lockScreenState = MessageTray.State.SHOWING;
 | 
			
		||||
 | 
			
		||||
        let fadeToBlack = params.fadeToBlack;
 | 
			
		||||
 | 
			
		||||
        if (params.animateLockScreen) {
 | 
			
		||||
            this._lockScreenGroup.y = -global.screen_height;
 | 
			
		||||
            this._lockScreenGroup.remove_all_transitions();
 | 
			
		||||
            this._lockScreenGroup.ease({
 | 
			
		||||
                y: 0,
 | 
			
		||||
            this._lockDialogGroup.translation_y = -global.screen_height;
 | 
			
		||||
            this._lockDialogGroup.remove_all_transitions();
 | 
			
		||||
            this._lockDialogGroup.ease({
 | 
			
		||||
                translation_y: 0,
 | 
			
		||||
                duration: MANUAL_FADE_TIME,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
                onComplete: () => {
 | 
			
		||||
@@ -1016,73 +474,17 @@ var ScreenShield = class {
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            this._lockScreenGroup.fixed_position_set = false;
 | 
			
		||||
            this._lockScreenShown({ fadeToBlack: fadeToBlack,
 | 
			
		||||
                                    animateFade: false });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._lockScreenGroup.grab_key_focus();
 | 
			
		||||
        this._lockDialogGroup.grab_key_focus();
 | 
			
		||||
 | 
			
		||||
        if (Main.sessionMode.currentMode != 'lock-screen')
 | 
			
		||||
            Main.sessionMode.pushMode('lock-screen');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _startArrowAnimation() {
 | 
			
		||||
        this._arrowActiveWatchId = 0;
 | 
			
		||||
 | 
			
		||||
        if (!this._arrowAnimationId) {
 | 
			
		||||
            this._arrowAnimationId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 6000, this._animateArrows.bind(this));
 | 
			
		||||
            GLib.Source.set_name_by_id(this._arrowAnimationId, '[gnome-shell] this._animateArrows');
 | 
			
		||||
            this._animateArrows();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this._arrowWatchId)
 | 
			
		||||
            this._arrowWatchId = this.idleMonitor.add_idle_watch(ARROW_IDLE_TIME,
 | 
			
		||||
                                                                 this._pauseArrowAnimation.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _pauseArrowAnimation() {
 | 
			
		||||
        if (this._arrowAnimationId) {
 | 
			
		||||
            GLib.source_remove(this._arrowAnimationId);
 | 
			
		||||
            this._arrowAnimationId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this._arrowActiveWatchId)
 | 
			
		||||
            this._arrowActiveWatchId = this.idleMonitor.add_user_active_watch(this._startArrowAnimation.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _stopArrowAnimation() {
 | 
			
		||||
        if (this._arrowAnimationId) {
 | 
			
		||||
            GLib.source_remove(this._arrowAnimationId);
 | 
			
		||||
            this._arrowAnimationId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (this._arrowActiveWatchId) {
 | 
			
		||||
            this.idleMonitor.remove_watch(this._arrowActiveWatchId);
 | 
			
		||||
            this._arrowActiveWatchId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (this._arrowWatchId) {
 | 
			
		||||
            this.idleMonitor.remove_watch(this._arrowWatchId);
 | 
			
		||||
            this._arrowWatchId = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _checkArrowAnimation() {
 | 
			
		||||
        let idleTime = this.idleMonitor.get_idletime();
 | 
			
		||||
 | 
			
		||||
        if (idleTime < ARROW_IDLE_TIME)
 | 
			
		||||
            this._startArrowAnimation();
 | 
			
		||||
        else
 | 
			
		||||
            this._pauseArrowAnimation();
 | 
			
		||||
        if (Main.sessionMode.currentMode != 'unlock-dialog')
 | 
			
		||||
            Main.sessionMode.pushMode('unlock-dialog');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _lockScreenShown(params) {
 | 
			
		||||
        if (this._dialog && !this._isGreeter) {
 | 
			
		||||
            this._dialog.destroy();
 | 
			
		||||
            this._dialog = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._checkArrowAnimation();
 | 
			
		||||
 | 
			
		||||
        let motionId = global.stage.connect('captured-event', (stage, event) => {
 | 
			
		||||
            if (event.type() == Clutter.EventType.MOTION) {
 | 
			
		||||
                this._cursorTracker.set_pointer_visible(true);
 | 
			
		||||
@@ -1094,8 +496,6 @@ var ScreenShield = class {
 | 
			
		||||
        this._cursorTracker.set_pointer_visible(false);
 | 
			
		||||
 | 
			
		||||
        this._lockScreenState = MessageTray.State.SHOWN;
 | 
			
		||||
        this._lockScreenGroup.fixed_position_set = false;
 | 
			
		||||
        this._lockScreenScrollCounter = 0;
 | 
			
		||||
 | 
			
		||||
        if (params.fadeToBlack && params.animateFade) {
 | 
			
		||||
            // Take a beat
 | 
			
		||||
@@ -1118,54 +518,6 @@ var ScreenShield = class {
 | 
			
		||||
        this.emit('lock-screen-shown');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Some of the actors in the lock screen are heavy in
 | 
			
		||||
    // resources, so we only create them when needed
 | 
			
		||||
    _ensureLockScreen() {
 | 
			
		||||
        if (this._hasLockScreen)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._lockScreenContentsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
                                                         y_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
                                                         x_expand: true,
 | 
			
		||||
                                                         y_expand: true,
 | 
			
		||||
                                                         vertical: true,
 | 
			
		||||
                                                         style_class: 'screen-shield-contents-box' });
 | 
			
		||||
        this._clock = new Clock();
 | 
			
		||||
        this._lockScreenContentsBox.add(this._clock.actor, { x_fill: true,
 | 
			
		||||
                                                             y_fill: true });
 | 
			
		||||
 | 
			
		||||
        this._lockScreenContents.add_actor(this._lockScreenContentsBox);
 | 
			
		||||
 | 
			
		||||
        this._notificationsBox = new NotificationsBox();
 | 
			
		||||
        this._wakeUpScreenId = this._notificationsBox.connect('wake-up-screen', this._wakeUpScreen.bind(this));
 | 
			
		||||
        this._lockScreenContentsBox.add(this._notificationsBox.actor, { x_fill: true,
 | 
			
		||||
                                                                        y_fill: true,
 | 
			
		||||
                                                                        expand: true });
 | 
			
		||||
 | 
			
		||||
        this._hasLockScreen = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _wakeUpScreen() {
 | 
			
		||||
        this._onUserBecameActive();
 | 
			
		||||
        this.emit('wake-up-screen');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _clearLockScreen() {
 | 
			
		||||
        this._clock.destroy();
 | 
			
		||||
        this._clock = null;
 | 
			
		||||
 | 
			
		||||
        if (this._notificationsBox) {
 | 
			
		||||
            this._notificationsBox.disconnect(this._wakeUpScreenId);
 | 
			
		||||
            this._notificationsBox.destroy();
 | 
			
		||||
            this._notificationsBox = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._stopArrowAnimation();
 | 
			
		||||
 | 
			
		||||
        this._lockScreenContentsBox.destroy();
 | 
			
		||||
 | 
			
		||||
        this._hasLockScreen = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get locked() {
 | 
			
		||||
        return this._isLocked;
 | 
			
		||||
@@ -1180,20 +532,12 @@ var ScreenShield = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    deactivate(animate) {
 | 
			
		||||
        if (this._dialog)
 | 
			
		||||
            this._dialog.finish(() => this._continueDeactivate(animate));
 | 
			
		||||
        else
 | 
			
		||||
            this._continueDeactivate(animate);
 | 
			
		||||
        this._dialog.finish(() => this._continueDeactivate(animate));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _continueDeactivate(animate) {
 | 
			
		||||
        this._hideLockScreen(animate, 0);
 | 
			
		||||
        this._hideLockScreen();
 | 
			
		||||
 | 
			
		||||
        if (this._hasLockScreen)
 | 
			
		||||
            this._clearLockScreen();
 | 
			
		||||
 | 
			
		||||
        if (Main.sessionMode.currentMode == 'lock-screen')
 | 
			
		||||
            Main.sessionMode.popMode('lock-screen');
 | 
			
		||||
        if (Main.sessionMode.currentMode == 'unlock-dialog')
 | 
			
		||||
            Main.sessionMode.popMode('unlock-dialog');
 | 
			
		||||
 | 
			
		||||
@@ -1210,7 +554,7 @@ var ScreenShield = class {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._dialog && !this._isGreeter)
 | 
			
		||||
        if (!this._isGreeter)
 | 
			
		||||
            this._dialog.popModal();
 | 
			
		||||
 | 
			
		||||
        if (this._isModal) {
 | 
			
		||||
@@ -1219,9 +563,8 @@ var ScreenShield = class {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._lockDialogGroup.ease({
 | 
			
		||||
            scale_x: 0,
 | 
			
		||||
            scale_y: 0,
 | 
			
		||||
            duration: animate ? Overview.ANIMATION_TIME : 0,
 | 
			
		||||
            translation_y: -global.screen_height,
 | 
			
		||||
            duration: CURTAIN_SLIDE_TIME,
 | 
			
		||||
            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
            onComplete: () => this._completeDeactivate()
 | 
			
		||||
        });
 | 
			
		||||
@@ -1260,8 +603,7 @@ var ScreenShield = class {
 | 
			
		||||
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
 | 
			
		||||
        if (Main.sessionMode.currentMode != 'unlock-dialog' &&
 | 
			
		||||
            Main.sessionMode.currentMode != 'lock-screen') {
 | 
			
		||||
        if (Main.sessionMode.currentMode != 'unlock-dialog') {
 | 
			
		||||
            this._isGreeter = Main.sessionMode.isGreeter;
 | 
			
		||||
            if (!this._isGreeter)
 | 
			
		||||
                Main.sessionMode.pushMode('unlock-dialog');
 | 
			
		||||
 
 | 
			
		||||
@@ -53,19 +53,6 @@ const _modes = {
 | 
			
		||||
        panelStyle: 'login-screen'
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    'lock-screen': {
 | 
			
		||||
        isLocked: true,
 | 
			
		||||
        isGreeter: undefined,
 | 
			
		||||
        unlockDialog: undefined,
 | 
			
		||||
        components: ['polkitAgent', 'telepathyClient'],
 | 
			
		||||
        panel: {
 | 
			
		||||
            left: [],
 | 
			
		||||
            center: [],
 | 
			
		||||
            right: ['aggregateMenu']
 | 
			
		||||
        },
 | 
			
		||||
        panelStyle: 'lock-screen'
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    'unlock-dialog': {
 | 
			
		||||
        isLocked: true,
 | 
			
		||||
        unlockDialog: undefined,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,376 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/* exported UnlockDialog */
 | 
			
		||||
 | 
			
		||||
const { AccountsService, Atk, Clutter,
 | 
			
		||||
        Gdm, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
 | 
			
		||||
const { AccountsService, Atk, Clutter, Gdm, Gio, GLib,
 | 
			
		||||
        GnomeDesktop, GObject, Meta, Shell, St } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const Layout = imports.ui.layout;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const AuthPrompt = imports.gdm.authPrompt;
 | 
			
		||||
 | 
			
		||||
// The timeout before going back automatically to the lock screen (in seconds)
 | 
			
		||||
const IDLE_TIMEOUT = 2 * 60;
 | 
			
		||||
 | 
			
		||||
var SUMMARY_ICON_SIZE = 24;
 | 
			
		||||
 | 
			
		||||
var Clock = class {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.actor = new St.BoxLayout({
 | 
			
		||||
            style_class: 'screen-shield-clock',
 | 
			
		||||
            vertical: true,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._time = new St.Label({ style_class: 'screen-shield-clock-time' });
 | 
			
		||||
        this._date = new St.Label({ style_class: 'screen-shield-clock-date' });
 | 
			
		||||
 | 
			
		||||
        this.actor.add(this._time, { x_align: St.Align.MIDDLE });
 | 
			
		||||
        this.actor.add(this._date, { x_align: St.Align.MIDDLE });
 | 
			
		||||
 | 
			
		||||
        this._wallClock = new GnomeDesktop.WallClock({ time_only: true });
 | 
			
		||||
        this._wallClock.connect('notify::clock', this._updateClock.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._updateClock();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateClock() {
 | 
			
		||||
        this._time.text = this._wallClock.clock;
 | 
			
		||||
 | 
			
		||||
        let date = new Date();
 | 
			
		||||
        /* Translators: This is a time format for a date in
 | 
			
		||||
           long format */
 | 
			
		||||
        let dateFormat = Shell.util_translate_time_string(N_("%A, %B %d"));
 | 
			
		||||
        this._date.text = date.toLocaleFormat(dateFormat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    destroy() {
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
        this._wallClock.run_dispose();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var NotificationsBox = class {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.actor = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                        name: 'screenShieldNotifications',
 | 
			
		||||
                                        style_class: 'screen-shield-notifications-container' });
 | 
			
		||||
 | 
			
		||||
        this._scrollView = new St.ScrollView({ x_fill: false, x_align: St.Align.START,
 | 
			
		||||
                                               hscrollbar_policy: St.PolicyType.NEVER });
 | 
			
		||||
        this._notificationBox = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                                   style_class: 'screen-shield-notifications-container' });
 | 
			
		||||
        this._scrollView.add_actor(this._notificationBox);
 | 
			
		||||
 | 
			
		||||
        this.actor.add(this._scrollView, { x_fill: true, x_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        this._sources = new Map();
 | 
			
		||||
        Main.messageTray.getSources().forEach(source => {
 | 
			
		||||
            this._sourceAdded(Main.messageTray, source, true);
 | 
			
		||||
        });
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
 | 
			
		||||
        this._sourceAddedId = Main.messageTray.connect('source-added', this._sourceAdded.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    destroy() {
 | 
			
		||||
        if (this._sourceAddedId) {
 | 
			
		||||
            Main.messageTray.disconnect(this._sourceAddedId);
 | 
			
		||||
            this._sourceAddedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let items = this._sources.entries();
 | 
			
		||||
        for (let [source, obj] of items) {
 | 
			
		||||
            this._removeSource(source, obj);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateVisibility() {
 | 
			
		||||
        this._notificationBox.visible =
 | 
			
		||||
            this._notificationBox.get_children().some(a => a.visible);
 | 
			
		||||
 | 
			
		||||
        this.actor.visible = this._notificationBox.visible;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _makeNotificationSource(source, box) {
 | 
			
		||||
        let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
 | 
			
		||||
        box.add(sourceActor, { y_fill: true });
 | 
			
		||||
 | 
			
		||||
        let title = new St.Label({
 | 
			
		||||
            text: source.title,
 | 
			
		||||
            style_class: 'screen-shield-notification-label',
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
            y_align: Clutter.ActorAlign.START,
 | 
			
		||||
            y_expand: true,
 | 
			
		||||
            y_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
        });
 | 
			
		||||
        box.add_child(title);
 | 
			
		||||
 | 
			
		||||
        let count = source.unseenCount;
 | 
			
		||||
        let countLabel = new St.Label({
 | 
			
		||||
            text: '%d'.format(count),
 | 
			
		||||
            style_class: 'screen-shield-notification-count-text',
 | 
			
		||||
            y_expand: true,
 | 
			
		||||
            y_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
        });
 | 
			
		||||
        box.add_child(countLabel);
 | 
			
		||||
 | 
			
		||||
        box.visible = count != 0;
 | 
			
		||||
        return [title, countLabel];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _makeNotificationDetailedSource(source, box) {
 | 
			
		||||
        let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
 | 
			
		||||
        let sourceBin = new St.Bin({ y_align: St.Align.START,
 | 
			
		||||
                                     x_align: St.Align.START,
 | 
			
		||||
                                     child: sourceActor });
 | 
			
		||||
        box.add(sourceBin);
 | 
			
		||||
 | 
			
		||||
        let textBox = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        box.add(textBox, { y_fill: false, y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        let title = new St.Label({ text: source.title,
 | 
			
		||||
                                   style_class: 'screen-shield-notification-label' });
 | 
			
		||||
        textBox.add(title);
 | 
			
		||||
 | 
			
		||||
        let visible = false;
 | 
			
		||||
        for (let i = 0; i < source.notifications.length; i++) {
 | 
			
		||||
            let n = source.notifications[i];
 | 
			
		||||
 | 
			
		||||
            if (n.acknowledged)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            let body = '';
 | 
			
		||||
            if (n.bannerBodyText) {
 | 
			
		||||
                body = n.bannerBodyMarkup
 | 
			
		||||
                    ? n.bannerBodyText
 | 
			
		||||
                    : GLib.markup_escape_text(n.bannerBodyText, -1);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let label = new St.Label({ style_class: 'screen-shield-notification-count-text' });
 | 
			
		||||
            label.clutter_text.set_markup('<b>' + n.title + '</b> ' + body);
 | 
			
		||||
            textBox.add(label);
 | 
			
		||||
 | 
			
		||||
            visible = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        box.visible = visible;
 | 
			
		||||
        return [title, null];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _shouldShowDetails(source) {
 | 
			
		||||
        return source.policy.detailsInLockScreen ||
 | 
			
		||||
               source.narrowestPrivacyScope == MessageTray.PrivacyScope.SYSTEM;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _showSource(source, obj, box) {
 | 
			
		||||
        if (obj.detailed) {
 | 
			
		||||
            [obj.titleLabel, obj.countLabel] = this._makeNotificationDetailedSource(source, box);
 | 
			
		||||
        } else {
 | 
			
		||||
            [obj.titleLabel, obj.countLabel] = this._makeNotificationSource(source, box);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        box.visible = obj.visible && (source.unseenCount > 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sourceAdded(tray, source, initial) {
 | 
			
		||||
        let obj = {
 | 
			
		||||
            visible: source.policy.showInLockScreen,
 | 
			
		||||
            detailed: this._shouldShowDetails(source),
 | 
			
		||||
            sourceDestroyId: 0,
 | 
			
		||||
            sourceCountChangedId: 0,
 | 
			
		||||
            sourceTitleChangedId: 0,
 | 
			
		||||
            sourceUpdatedId: 0,
 | 
			
		||||
            sourceBox: null,
 | 
			
		||||
            titleLabel: null,
 | 
			
		||||
            countLabel: null,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        obj.sourceBox = new St.BoxLayout({ style_class: 'screen-shield-notification-source',
 | 
			
		||||
                                           x_expand: true });
 | 
			
		||||
        this._showSource(source, obj, obj.sourceBox);
 | 
			
		||||
        this._notificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        obj.sourceCountChangedId = source.connect('count-updated', source => {
 | 
			
		||||
            this._countChanged(source, obj);
 | 
			
		||||
        });
 | 
			
		||||
        obj.sourceTitleChangedId = source.connect('title-changed', source => {
 | 
			
		||||
            this._titleChanged(source, obj);
 | 
			
		||||
        });
 | 
			
		||||
        obj.policyChangedId = source.policy.connect('policy-changed', (policy, key) => {
 | 
			
		||||
            if (key == 'show-in-lock-screen')
 | 
			
		||||
                this._visibleChanged(source, obj);
 | 
			
		||||
            else
 | 
			
		||||
                this._detailedChanged(source, obj);
 | 
			
		||||
        });
 | 
			
		||||
        obj.sourceDestroyId = source.connect('destroy', source => {
 | 
			
		||||
            this._onSourceDestroy(source, obj);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._sources.set(source, obj);
 | 
			
		||||
 | 
			
		||||
        if (!initial) {
 | 
			
		||||
            // block scrollbars while animating, if they're not needed now
 | 
			
		||||
            let boxHeight = this._notificationBox.height;
 | 
			
		||||
            if (this._scrollView.height >= boxHeight)
 | 
			
		||||
                this._scrollView.vscrollbar_policy = St.PolicyType.NEVER;
 | 
			
		||||
 | 
			
		||||
            let widget = obj.sourceBox;
 | 
			
		||||
            let [, natHeight] = widget.get_preferred_height(-1);
 | 
			
		||||
            widget.height = 0;
 | 
			
		||||
            widget.ease({
 | 
			
		||||
                height: natHeight,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
                duration: 250,
 | 
			
		||||
                onComplete: () => {
 | 
			
		||||
                    this._scrollView.vscrollbar_policy = St.PolicyType.AUTOMATIC;
 | 
			
		||||
                    widget.set_height(-1);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this._updateVisibility();
 | 
			
		||||
            if (obj.sourceBox.visible)
 | 
			
		||||
                this.emit('wake-up-screen');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _titleChanged(source, obj) {
 | 
			
		||||
        obj.titleLabel.text = source.title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _countChanged(source, obj) {
 | 
			
		||||
        // A change in the number of notifications may change whether we show
 | 
			
		||||
        // details.
 | 
			
		||||
        let newDetailed = this._shouldShowDetails(source);
 | 
			
		||||
        let oldDetailed = obj.detailed;
 | 
			
		||||
 | 
			
		||||
        obj.detailed = newDetailed;
 | 
			
		||||
 | 
			
		||||
        if (obj.detailed || oldDetailed != newDetailed) {
 | 
			
		||||
            // A new notification was pushed, or a previous notification was destroyed.
 | 
			
		||||
            // Give up, and build the list again.
 | 
			
		||||
 | 
			
		||||
            obj.sourceBox.destroy_all_children();
 | 
			
		||||
            obj.titleLabel = obj.countLabel = null;
 | 
			
		||||
            this._showSource(source, obj, obj.sourceBox);
 | 
			
		||||
        } else {
 | 
			
		||||
            let count = source.unseenCount;
 | 
			
		||||
            obj.countLabel.text = '%d'.format(count);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        obj.sourceBox.visible = obj.visible && (source.unseenCount > 0);
 | 
			
		||||
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        if (obj.sourceBox.visible)
 | 
			
		||||
            this.emit('wake-up-screen');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _visibleChanged(source, obj) {
 | 
			
		||||
        if (obj.visible == source.policy.showInLockScreen)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        obj.visible = source.policy.showInLockScreen;
 | 
			
		||||
        obj.sourceBox.visible = obj.visible && source.unseenCount > 0;
 | 
			
		||||
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        if (obj.sourceBox.visible)
 | 
			
		||||
            this.emit('wake-up-screen');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _detailedChanged(source, obj) {
 | 
			
		||||
        let newDetailed = this._shouldShowDetails(source);
 | 
			
		||||
        if (obj.detailed == newDetailed)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        obj.detailed = newDetailed;
 | 
			
		||||
 | 
			
		||||
        obj.sourceBox.destroy_all_children();
 | 
			
		||||
        obj.titleLabel = obj.countLabel = null;
 | 
			
		||||
        this._showSource(source, obj, obj.sourceBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onSourceDestroy(source, obj) {
 | 
			
		||||
        this._removeSource(source, obj);
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _removeSource(source, obj) {
 | 
			
		||||
        obj.sourceBox.destroy();
 | 
			
		||||
        obj.sourceBox = obj.titleLabel = obj.countLabel = null;
 | 
			
		||||
 | 
			
		||||
        source.disconnect(obj.sourceDestroyId);
 | 
			
		||||
        source.disconnect(obj.sourceCountChangedId);
 | 
			
		||||
        source.disconnect(obj.sourceTitleChangedId);
 | 
			
		||||
        source.policy.disconnect(obj.policyChangedId);
 | 
			
		||||
 | 
			
		||||
        this._sources.delete(source);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
Signals.addSignalMethods(NotificationsBox.prototype);
 | 
			
		||||
 | 
			
		||||
var UnlockDialogLayout = GObject.registerClass(
 | 
			
		||||
class UnlockDialogLayout extends Clutter.LayoutManager {
 | 
			
		||||
    _init(clockStack, notifications) {
 | 
			
		||||
        super._init();
 | 
			
		||||
 | 
			
		||||
        this._clockStack = clockStack;
 | 
			
		||||
        this._notifications = notifications;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_width(container, forHeight) {
 | 
			
		||||
        return this._clockStack.get_preferred_width(forHeight);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_height(container, forWidth) {
 | 
			
		||||
        return this._clockStack.get_preferred_height(forWidth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(container, box, flags) {
 | 
			
		||||
        let [width, height] = box.get_size();
 | 
			
		||||
 | 
			
		||||
        let tenthOfHeight = height / 10.0;
 | 
			
		||||
        let thirdOfHeight = height / 3.0;
 | 
			
		||||
 | 
			
		||||
        let [clockStackWidth, clockStackHeight] =
 | 
			
		||||
            this._clockStack.get_preferred_size();
 | 
			
		||||
 | 
			
		||||
        let [, , notificationsWidth, notificationsHeight] =
 | 
			
		||||
            this._notifications.get_preferred_size();
 | 
			
		||||
 | 
			
		||||
        let columnWidth = Math.max(clockStackWidth, notificationsWidth);
 | 
			
		||||
 | 
			
		||||
        let columnX1 = Math.floor(width / 2.0 - columnWidth / 2.0);
 | 
			
		||||
        let actorBox = new Clutter.ActorBox();
 | 
			
		||||
 | 
			
		||||
        // Notifications
 | 
			
		||||
        let maxNotificationsHeight = Math.min(
 | 
			
		||||
            notificationsHeight,
 | 
			
		||||
            height - tenthOfHeight - clockStackHeight);
 | 
			
		||||
 | 
			
		||||
        actorBox.x1 = columnX1;
 | 
			
		||||
        actorBox.y1 = height - maxNotificationsHeight;
 | 
			
		||||
        actorBox.x2 = columnX1 + columnWidth;
 | 
			
		||||
        actorBox.y2 = actorBox.y1 + maxNotificationsHeight;
 | 
			
		||||
 | 
			
		||||
        this._notifications.allocate(actorBox, flags);
 | 
			
		||||
 | 
			
		||||
        // Clock Stack
 | 
			
		||||
        let clockStackY = Math.min(
 | 
			
		||||
            thirdOfHeight,
 | 
			
		||||
            height - clockStackHeight - maxNotificationsHeight);
 | 
			
		||||
 | 
			
		||||
        actorBox.x1 = columnX1;
 | 
			
		||||
        actorBox.y1 = clockStackY;
 | 
			
		||||
        actorBox.x2 = columnX1 + columnWidth;
 | 
			
		||||
        actorBox.y2 = clockStackY + clockStackHeight;
 | 
			
		||||
 | 
			
		||||
        this._clockStack.allocate(actorBox, flags);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var UnlockDialog = GObject.registerClass({
 | 
			
		||||
    Signals: { 'failed': {} },
 | 
			
		||||
}, class UnlockDialog extends St.Widget {
 | 
			
		||||
@@ -19,10 +378,16 @@ var UnlockDialog = GObject.registerClass({
 | 
			
		||||
        super._init({
 | 
			
		||||
            accessible_role: Atk.Role.WINDOW,
 | 
			
		||||
            style_class: 'login-dialog',
 | 
			
		||||
            layout_manager: new Clutter.BoxLayout(),
 | 
			
		||||
            reactive: true,
 | 
			
		||||
            visible: false,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let tapAction = new Clutter.TapAction();
 | 
			
		||||
        tapAction.connect('tap', () => {
 | 
			
		||||
            this._showAuth();
 | 
			
		||||
        })
 | 
			
		||||
        this.add_action(tapAction);
 | 
			
		||||
 | 
			
		||||
        this.add_constraint(new Layout.MonitorConstraint({ primary: true }));
 | 
			
		||||
        parentActor.add_child(this);
 | 
			
		||||
 | 
			
		||||
@@ -30,21 +395,31 @@ var UnlockDialog = GObject.registerClass({
 | 
			
		||||
        this._userName = GLib.get_user_name();
 | 
			
		||||
        this._user = this._userManager.get_user(this._userName);
 | 
			
		||||
 | 
			
		||||
        this._promptBox = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                             x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
                                             y_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
                                             x_expand: true,
 | 
			
		||||
                                             y_expand: true });
 | 
			
		||||
        this.add_child(this._promptBox);
 | 
			
		||||
        let clockStack = new Shell.Stack();
 | 
			
		||||
        this.add_child(clockStack);
 | 
			
		||||
 | 
			
		||||
        this._clock = new Clock();
 | 
			
		||||
        clockStack.add_child(this._clock.actor);
 | 
			
		||||
 | 
			
		||||
        this._activePage  = this._clock.actor;
 | 
			
		||||
 | 
			
		||||
        this._authBox = new St.BoxLayout({
 | 
			
		||||
            x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
            y_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
            y_expand: true,
 | 
			
		||||
            vertical: true,
 | 
			
		||||
            visible: false,
 | 
			
		||||
        });
 | 
			
		||||
        clockStack.add_child(this._authBox);
 | 
			
		||||
 | 
			
		||||
        this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY);
 | 
			
		||||
        this._authPrompt.connect('failed', this._fail.bind(this));
 | 
			
		||||
        this._authPrompt.connect('cancelled', this._fail.bind(this));
 | 
			
		||||
        this._authPrompt.connect('reset', this._onReset.bind(this));
 | 
			
		||||
        this._authPrompt.setPasswordChar('\u25cf');
 | 
			
		||||
        this._authPrompt.nextButton.label = _("Unlock");
 | 
			
		||||
 | 
			
		||||
        this._promptBox.add_child(this._authPrompt.actor);
 | 
			
		||||
        this._authBox.add_child(this._authPrompt.actor);
 | 
			
		||||
 | 
			
		||||
        this.allowCancel = false;
 | 
			
		||||
 | 
			
		||||
@@ -59,11 +434,15 @@ var UnlockDialog = GObject.registerClass({
 | 
			
		||||
                                                    x_align: St.Align.START,
 | 
			
		||||
                                                    x_fill: false });
 | 
			
		||||
            this._otherUserButton.connect('clicked', this._otherUserClicked.bind(this));
 | 
			
		||||
            this._promptBox.add_child(this._otherUserButton);
 | 
			
		||||
            this._authBox.add_child(this._otherUserButton);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._otherUserButton = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._notificationsBox = new NotificationsBox();
 | 
			
		||||
        this._wakeUpScreenId = this._notificationsBox.connect('wake-up-screen', this._wakeUpScreen.bind(this));
 | 
			
		||||
        this.add_child(this._notificationsBox.actor);
 | 
			
		||||
 | 
			
		||||
        this._authPrompt.reset();
 | 
			
		||||
        this._updateSensitivity(true);
 | 
			
		||||
 | 
			
		||||
@@ -72,9 +451,81 @@ var UnlockDialog = GObject.registerClass({
 | 
			
		||||
        this._idleMonitor = Meta.IdleMonitor.get_core();
 | 
			
		||||
        this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, this._escape.bind(this));
 | 
			
		||||
 | 
			
		||||
        this.layout_manager = new UnlockDialogLayout(
 | 
			
		||||
            clockStack,
 | 
			
		||||
            this._notificationsBox.actor);
 | 
			
		||||
 | 
			
		||||
        this.connect('destroy', this._onDestroy.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _showClock() {
 | 
			
		||||
        if (this._activePage == this._clock.actor)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._activePage = this._clock.actor;
 | 
			
		||||
        this._clock.actor.show();
 | 
			
		||||
 | 
			
		||||
        this._authBox.ease({
 | 
			
		||||
            opacity: 0,
 | 
			
		||||
            duration: 300,
 | 
			
		||||
            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
            onComplete: () => this._authBox.hide(),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._clock.actor.ease({
 | 
			
		||||
            opacity: 255,
 | 
			
		||||
            duration: 300,
 | 
			
		||||
            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _showAuth() {
 | 
			
		||||
        if (this._activePage == this._authBox)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._activePage = this._authBox;
 | 
			
		||||
        this._authBox.show();
 | 
			
		||||
 | 
			
		||||
        this._clock.actor.ease({
 | 
			
		||||
            opacity: 0,
 | 
			
		||||
            duration: 300,
 | 
			
		||||
            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
            onComplete: () => this._clock.actor.hide(),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._authBox.ease({
 | 
			
		||||
            opacity: 255,
 | 
			
		||||
            duration: 300,
 | 
			
		||||
            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_captured_event(event) {
 | 
			
		||||
        if (event.type() != Clutter.EventType.KEY_PRESS)
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        if (this._activePage == this._authBox)
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        let symbol = event.get_key_symbol();
 | 
			
		||||
        let unichar = event.get_key_unicode();
 | 
			
		||||
 | 
			
		||||
        let isEnter = (symbol == Clutter.KEY_Return ||
 | 
			
		||||
                       symbol == Clutter.KEY_KP_Enter ||
 | 
			
		||||
                       symbol == Clutter.KEY_ISO_Enter);
 | 
			
		||||
        let isEscape = (symbol == Clutter.KEY_Escape);
 | 
			
		||||
        let isLiftChar = (GLib.unichar_isprint(unichar) &&
 | 
			
		||||
                          (this._activePage == this._clock.actor ||
 | 
			
		||||
                          !GLib.unichar_isgraph(unichar)));
 | 
			
		||||
 | 
			
		||||
        if (!isEnter && !isEscape && !isLiftChar)
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        this._showAuth();
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateSensitivity(sensitive) {
 | 
			
		||||
        this._authPrompt.updateSensitivity(sensitive);
 | 
			
		||||
 | 
			
		||||
@@ -85,6 +536,7 @@ var UnlockDialog = GObject.registerClass({
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _fail() {
 | 
			
		||||
        this._showClock();
 | 
			
		||||
        this.emit('failed');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -111,9 +563,24 @@ var UnlockDialog = GObject.registerClass({
 | 
			
		||||
        this._authPrompt.cancel();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _wakeUpScreen() {
 | 
			
		||||
        // FIXME
 | 
			
		||||
        //this._onUserBecameActive();
 | 
			
		||||
        this.emit('wake-up-screen');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
        this.popModal();
 | 
			
		||||
 | 
			
		||||
        if (this._notificationsBox) {
 | 
			
		||||
            this._notificationsBox.disconnect(this._wakeUpScreenId);
 | 
			
		||||
            this._notificationsBox.destroy();
 | 
			
		||||
            this._notificationsBox = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._clock.destroy();
 | 
			
		||||
        this._clock = null;
 | 
			
		||||
 | 
			
		||||
        if (this._idleWatchId) {
 | 
			
		||||
            this._idleMonitor.remove_watch(this._idleWatchId);
 | 
			
		||||
            this._idleWatchId = 0;
 | 
			
		||||
@@ -122,11 +589,10 @@ var UnlockDialog = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
    cancel() {
 | 
			
		||||
        this._authPrompt.cancel();
 | 
			
		||||
 | 
			
		||||
        this.destroy();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addCharacter(unichar) {
 | 
			
		||||
        this._showAuth();
 | 
			
		||||
        this._authPrompt.addCharacter(unichar);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -95,6 +95,7 @@ libshell_public_headers = [
 | 
			
		||||
  'shell-app.h',
 | 
			
		||||
  'shell-app-system.h',
 | 
			
		||||
  'shell-app-usage.h',
 | 
			
		||||
  'shell-blur-effect.h',
 | 
			
		||||
  'shell-embedded-window.h',
 | 
			
		||||
  'shell-glsl-effect.h',
 | 
			
		||||
  'shell-gtk-embed.h',
 | 
			
		||||
@@ -129,6 +130,7 @@ libshell_sources = [
 | 
			
		||||
  'shell-app.c',
 | 
			
		||||
  'shell-app-system.c',
 | 
			
		||||
  'shell-app-usage.c',
 | 
			
		||||
  'shell-blur-effect.c',
 | 
			
		||||
  'shell-embedded-window.c',
 | 
			
		||||
  'shell-embedded-window-private.h',
 | 
			
		||||
  'shell-global.c',
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										506
									
								
								src/shell-blur-effect.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										506
									
								
								src/shell-blur-effect.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,506 @@
 | 
			
		||||
/* shell-blur-effect.c
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "shell-blur-effect.h"
 | 
			
		||||
 | 
			
		||||
static const gchar *gaussian_blur_glsl_declarations =
 | 
			
		||||
"uniform float blur_radius;                                        \n"
 | 
			
		||||
"uniform float brightness;                                         \n"
 | 
			
		||||
"uniform float pixel_step;                                         \n"
 | 
			
		||||
"uniform int vertical;                                             \n"
 | 
			
		||||
"                                                                  \n"
 | 
			
		||||
"float gaussian (float sigma, float x) {                           \n"
 | 
			
		||||
"  return exp ( - (x * x) / (2.0 * sigma * sigma));                \n"
 | 
			
		||||
"}                                                                 \n"
 | 
			
		||||
"                                                                  \n";
 | 
			
		||||
 | 
			
		||||
static const gchar *gaussian_blur_glsl =
 | 
			
		||||
"  float radius = blur_radius * 2.30348;                           \n"
 | 
			
		||||
"  float total = 0.0;                                              \n"
 | 
			
		||||
"  vec4 ret = vec4 (0);                                            \n"
 | 
			
		||||
"  vec2 uv = vec2(cogl_tex_coord.st);                              \n"
 | 
			
		||||
"                                                                  \n"
 | 
			
		||||
"  int half_radius = max(int(radius / 2.0), 1);                    \n"
 | 
			
		||||
"                                                                  \n"
 | 
			
		||||
"  if (vertical != 0) {                                            \n"
 | 
			
		||||
"    for (int y = -half_radius; y < half_radius; y++) {            \n"
 | 
			
		||||
"      float fy = gaussian (radius / 2.0, float(y));               \n"
 | 
			
		||||
"      float offset_y = float(y) * pixel_step;                     \n"
 | 
			
		||||
"                                                                  \n"
 | 
			
		||||
"      vec4 c = texture2D(cogl_sampler, uv + vec2(0.0, offset_y)); \n"
 | 
			
		||||
"      total += fy;                                                \n"
 | 
			
		||||
"      ret += c * fy;                                              \n"
 | 
			
		||||
"    }                                                             \n"
 | 
			
		||||
"  } else {                                                        \n"
 | 
			
		||||
"    for (int x = -half_radius; x < half_radius; x++) {            \n"
 | 
			
		||||
"      float fx = gaussian (radius / 2.0, float(x));               \n"
 | 
			
		||||
"      float offset_x = float(x) * pixel_step;                     \n"
 | 
			
		||||
"                                                                  \n"
 | 
			
		||||
"      vec4 c = texture2D(cogl_sampler, uv + vec2(offset_x, 0.0)); \n"
 | 
			
		||||
"      total += fx;                                                \n"
 | 
			
		||||
"      ret += c * fx;                                              \n"
 | 
			
		||||
"    }                                                             \n"
 | 
			
		||||
"  }                                                               \n"
 | 
			
		||||
"                                                                  \n"
 | 
			
		||||
"  cogl_texel = vec4 (ret / total);                                \n"
 | 
			
		||||
"  cogl_texel.rgb *= brightness;                                   \n";
 | 
			
		||||
 | 
			
		||||
#define DOWNSCALE_FACTOR 4.0
 | 
			
		||||
 | 
			
		||||
struct _ShellBlurEffect
 | 
			
		||||
{
 | 
			
		||||
  ClutterOffscreenEffect parent_instance;
 | 
			
		||||
 | 
			
		||||
  CoglPipeline *pipeline;
 | 
			
		||||
  int blur_radius_uniform;
 | 
			
		||||
  int brightness_uniform;
 | 
			
		||||
  int pixel_step_uniform;
 | 
			
		||||
  int vertical_uniform;
 | 
			
		||||
 | 
			
		||||
  unsigned int tex_width;
 | 
			
		||||
  unsigned int tex_height;
 | 
			
		||||
 | 
			
		||||
  gboolean vertical;
 | 
			
		||||
  float brightness;
 | 
			
		||||
  int blur_radius;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (ShellBlurEffect, shell_blur_effect, CLUTTER_TYPE_OFFSCREEN_EFFECT)
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  PROP_0,
 | 
			
		||||
  PROP_BLUR_RADIUS,
 | 
			
		||||
  PROP_BRIGHTNESS,
 | 
			
		||||
  PROP_VERTICAL,
 | 
			
		||||
  N_PROPS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static GParamSpec *properties [N_PROPS] = { NULL, };
 | 
			
		||||
 | 
			
		||||
static CoglPipeline*
 | 
			
		||||
create_pipeline (void)
 | 
			
		||||
{
 | 
			
		||||
  static CoglPipeline *base_pipeline = NULL;
 | 
			
		||||
 | 
			
		||||
  if (G_UNLIKELY (base_pipeline == NULL))
 | 
			
		||||
    {
 | 
			
		||||
      CoglSnippet *snippet;
 | 
			
		||||
      CoglContext *ctx =
 | 
			
		||||
        clutter_backend_get_cogl_context (clutter_get_default_backend ());
 | 
			
		||||
 | 
			
		||||
      base_pipeline = cogl_pipeline_new (ctx);
 | 
			
		||||
 | 
			
		||||
      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP,
 | 
			
		||||
                                  gaussian_blur_glsl_declarations,
 | 
			
		||||
                                  NULL);
 | 
			
		||||
      cogl_snippet_set_replace (snippet, gaussian_blur_glsl);
 | 
			
		||||
      cogl_pipeline_add_layer_snippet (base_pipeline, 0, snippet);
 | 
			
		||||
      cogl_object_unref (snippet);
 | 
			
		||||
 | 
			
		||||
      cogl_pipeline_set_layer_null_texture (base_pipeline, 0);
 | 
			
		||||
      cogl_pipeline_set_layer_filters (base_pipeline,
 | 
			
		||||
                                       0,
 | 
			
		||||
                                       COGL_PIPELINE_FILTER_LINEAR,
 | 
			
		||||
                                       COGL_PIPELINE_FILTER_LINEAR);
 | 
			
		||||
      cogl_pipeline_set_layer_wrap_mode (base_pipeline,
 | 
			
		||||
                                         0,
 | 
			
		||||
                                         COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return cogl_pipeline_copy (base_pipeline);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
queue_actor_repaint (ShellBlurEffect *self)
 | 
			
		||||
{
 | 
			
		||||
  ClutterActor *actor =
 | 
			
		||||
    clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self));
 | 
			
		||||
 | 
			
		||||
  if (actor)
 | 
			
		||||
    clutter_actor_queue_redraw (actor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
update_uniforms (ShellBlurEffect *self)
 | 
			
		||||
{
 | 
			
		||||
  ClutterOffscreenEffect *offscreen_effect =
 | 
			
		||||
    CLUTTER_OFFSCREEN_EFFECT (self);
 | 
			
		||||
  CoglHandle texture;
 | 
			
		||||
 | 
			
		||||
  texture = clutter_offscreen_effect_get_texture (offscreen_effect);
 | 
			
		||||
  self->tex_width = cogl_texture_get_width (texture) * DOWNSCALE_FACTOR;
 | 
			
		||||
  self->tex_height = cogl_texture_get_height (texture) * DOWNSCALE_FACTOR;
 | 
			
		||||
 | 
			
		||||
  if (self->pixel_step_uniform > -1)
 | 
			
		||||
    {
 | 
			
		||||
      ClutterRect rect;
 | 
			
		||||
      float pixel_step;
 | 
			
		||||
 | 
			
		||||
      clutter_offscreen_effect_get_target_rect (CLUTTER_OFFSCREEN_EFFECT (self),
 | 
			
		||||
                                                &rect);
 | 
			
		||||
 | 
			
		||||
      if (self->vertical)
 | 
			
		||||
        pixel_step = 1.f / rect.size.height;
 | 
			
		||||
      else
 | 
			
		||||
        pixel_step = 1.f / rect.size.width;
 | 
			
		||||
 | 
			
		||||
      cogl_pipeline_set_uniform_1f (self->pipeline,
 | 
			
		||||
                                    self->pixel_step_uniform,
 | 
			
		||||
                                    pixel_step / DOWNSCALE_FACTOR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (self->blur_radius_uniform > -1)
 | 
			
		||||
    {
 | 
			
		||||
      cogl_pipeline_set_uniform_1f (self->pipeline,
 | 
			
		||||
                                    self->blur_radius_uniform,
 | 
			
		||||
                                    self->blur_radius / DOWNSCALE_FACTOR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (self->brightness_uniform > -1)
 | 
			
		||||
    {
 | 
			
		||||
      cogl_pipeline_set_uniform_1f (self->pipeline,
 | 
			
		||||
                                    self->brightness_uniform,
 | 
			
		||||
                                    self->brightness);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (self->vertical_uniform > -1)
 | 
			
		||||
    {
 | 
			
		||||
      cogl_pipeline_set_uniform_1i (self->pipeline,
 | 
			
		||||
                                    self->vertical_uniform,
 | 
			
		||||
                                    self->vertical);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
shell_blur_effect_pre_paint (ClutterEffect *effect)
 | 
			
		||||
{
 | 
			
		||||
  gboolean success;
 | 
			
		||||
 | 
			
		||||
  success = CLUTTER_EFFECT_CLASS (shell_blur_effect_parent_class)->pre_paint (effect);
 | 
			
		||||
 | 
			
		||||
  if (success)
 | 
			
		||||
    {
 | 
			
		||||
      CoglFramebuffer *offscreen = cogl_get_draw_framebuffer ();
 | 
			
		||||
 | 
			
		||||
      /* Texture is downscaled, draw downscaled as well */
 | 
			
		||||
      cogl_framebuffer_scale (offscreen,
 | 
			
		||||
                              1.0 / DOWNSCALE_FACTOR,
 | 
			
		||||
                              1.0 / DOWNSCALE_FACTOR,
 | 
			
		||||
                              1.0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
shell_blur_effect_paint_target (ClutterOffscreenEffect *effect)
 | 
			
		||||
{
 | 
			
		||||
  ShellBlurEffect *self = SHELL_BLUR_EFFECT (effect);
 | 
			
		||||
  CoglFramebuffer *framebuffer = cogl_get_draw_framebuffer ();
 | 
			
		||||
  ClutterActor *actor;
 | 
			
		||||
  float blur_radius_offset_h;
 | 
			
		||||
  float blur_radius_offset_v;
 | 
			
		||||
  guint8 paint_opacity;
 | 
			
		||||
 | 
			
		||||
  update_uniforms (self);
 | 
			
		||||
 | 
			
		||||
  actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self));
 | 
			
		||||
  paint_opacity = clutter_actor_get_paint_opacity (actor);
 | 
			
		||||
 | 
			
		||||
  cogl_pipeline_set_color4ub (self->pipeline,
 | 
			
		||||
                              paint_opacity,
 | 
			
		||||
                              paint_opacity,
 | 
			
		||||
                              paint_opacity,
 | 
			
		||||
                              paint_opacity);
 | 
			
		||||
 | 
			
		||||
  blur_radius_offset_h =
 | 
			
		||||
    self->blur_radius / (float) self->tex_width / DOWNSCALE_FACTOR;
 | 
			
		||||
  blur_radius_offset_v =
 | 
			
		||||
    self->blur_radius / (float) self->tex_height / DOWNSCALE_FACTOR;
 | 
			
		||||
 | 
			
		||||
  cogl_framebuffer_draw_textured_rectangle (framebuffer,
 | 
			
		||||
                                            self->pipeline,
 | 
			
		||||
                                            0, 0,
 | 
			
		||||
                                            self->tex_width,
 | 
			
		||||
                                            self->tex_height,
 | 
			
		||||
                                            blur_radius_offset_h,
 | 
			
		||||
                                            blur_radius_offset_v,
 | 
			
		||||
                                            1.f - blur_radius_offset_h,
 | 
			
		||||
                                            1.f - blur_radius_offset_v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
shell_blur_effect_post_paint (ClutterEffect *effect)
 | 
			
		||||
{
 | 
			
		||||
  CoglFramebuffer *offscreen = cogl_get_draw_framebuffer ();
 | 
			
		||||
 | 
			
		||||
  cogl_framebuffer_scale (offscreen,
 | 
			
		||||
                          DOWNSCALE_FACTOR,
 | 
			
		||||
                          DOWNSCALE_FACTOR,
 | 
			
		||||
                          1.f);
 | 
			
		||||
 | 
			
		||||
  CLUTTER_EFFECT_CLASS (shell_blur_effect_parent_class)->post_paint (effect);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static CoglTexture*
 | 
			
		||||
shell_blur_effect_create_texture (ClutterOffscreenEffect *effect,
 | 
			
		||||
                                  float                   width,
 | 
			
		||||
                                  float                   height)
 | 
			
		||||
{
 | 
			
		||||
  CoglContext *ctx =
 | 
			
		||||
    clutter_backend_get_cogl_context (clutter_get_default_backend ());
 | 
			
		||||
 | 
			
		||||
  return cogl_texture_2d_new_with_size (ctx,
 | 
			
		||||
                                        width / DOWNSCALE_FACTOR,
 | 
			
		||||
                                        height / DOWNSCALE_FACTOR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
shell_blur_effect_modify_paint_volume (ClutterEffect      *effect,
 | 
			
		||||
                                       ClutterPaintVolume *volume)
 | 
			
		||||
{
 | 
			
		||||
  ShellBlurEffect *self = SHELL_BLUR_EFFECT (effect);
 | 
			
		||||
  ClutterVertex origin;
 | 
			
		||||
  float width;
 | 
			
		||||
  float height;
 | 
			
		||||
 | 
			
		||||
  clutter_paint_volume_get_origin (volume, &origin);
 | 
			
		||||
  width = clutter_paint_volume_get_width (volume);
 | 
			
		||||
  height = clutter_paint_volume_get_height (volume);
 | 
			
		||||
 | 
			
		||||
  if (self->vertical)
 | 
			
		||||
    {
 | 
			
		||||
      origin.y -= self->blur_radius;
 | 
			
		||||
      height += 2 * self->blur_radius;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      origin.x -= self->blur_radius;
 | 
			
		||||
      width += 2 * self->blur_radius;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  clutter_paint_volume_set_origin (volume, &origin);
 | 
			
		||||
  clutter_paint_volume_set_width (volume, width);
 | 
			
		||||
  clutter_paint_volume_set_height (volume, height);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
shell_blur_effect_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  ShellBlurEffect *self = (ShellBlurEffect *)object;
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&self->pipeline, cogl_object_unref);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (shell_blur_effect_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
shell_blur_effect_get_property (GObject    *object,
 | 
			
		||||
                                guint       prop_id,
 | 
			
		||||
                                GValue     *value,
 | 
			
		||||
                                GParamSpec *pspec)
 | 
			
		||||
{
 | 
			
		||||
  ShellBlurEffect *self = SHELL_BLUR_EFFECT (object);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_BLUR_RADIUS:
 | 
			
		||||
      g_value_set_int (value, self->blur_radius);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case PROP_BRIGHTNESS:
 | 
			
		||||
      g_value_set_int (value, self->brightness);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case PROP_VERTICAL:
 | 
			
		||||
      g_value_set_boolean (value, self->vertical);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
shell_blur_effect_set_property (GObject      *object,
 | 
			
		||||
                                guint         prop_id,
 | 
			
		||||
                                const GValue *value,
 | 
			
		||||
                                GParamSpec   *pspec)
 | 
			
		||||
{
 | 
			
		||||
  ShellBlurEffect *self = SHELL_BLUR_EFFECT (object);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_BLUR_RADIUS:
 | 
			
		||||
      shell_blur_effect_set_blur_radius (self, g_value_get_int (value));
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case PROP_BRIGHTNESS:
 | 
			
		||||
      shell_blur_effect_set_brightness (self, g_value_get_float (value));
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case PROP_VERTICAL:
 | 
			
		||||
      shell_blur_effect_set_vertical (self, g_value_get_boolean (value));
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
shell_blur_effect_class_init (ShellBlurEffectClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
  ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
 | 
			
		||||
  ClutterOffscreenEffectClass *offscreen_class =
 | 
			
		||||
    CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = shell_blur_effect_finalize;
 | 
			
		||||
  object_class->get_property = shell_blur_effect_get_property;
 | 
			
		||||
  object_class->set_property = shell_blur_effect_set_property;
 | 
			
		||||
 | 
			
		||||
  effect_class->pre_paint = shell_blur_effect_pre_paint;
 | 
			
		||||
  effect_class->post_paint = shell_blur_effect_post_paint;
 | 
			
		||||
  effect_class->modify_paint_volume = shell_blur_effect_modify_paint_volume;
 | 
			
		||||
 | 
			
		||||
  offscreen_class->paint_target = shell_blur_effect_paint_target;
 | 
			
		||||
  offscreen_class->create_texture = shell_blur_effect_create_texture;
 | 
			
		||||
 | 
			
		||||
  properties[PROP_BLUR_RADIUS] =
 | 
			
		||||
    g_param_spec_int ("blur-radius",
 | 
			
		||||
                      "Blur radius",
 | 
			
		||||
                      "Blur radius",
 | 
			
		||||
                      0, G_MAXINT, 0,
 | 
			
		||||
                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 | 
			
		||||
 | 
			
		||||
  properties[PROP_BRIGHTNESS] =
 | 
			
		||||
    g_param_spec_float ("brightness",
 | 
			
		||||
                        "Brightness",
 | 
			
		||||
                        "Brightness",
 | 
			
		||||
                        0.f, 1.f, 1.f,
 | 
			
		||||
                        G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 | 
			
		||||
 | 
			
		||||
  properties[PROP_VERTICAL] =
 | 
			
		||||
    g_param_spec_boolean ("vertical",
 | 
			
		||||
                          "Vertical",
 | 
			
		||||
                          "Whether the blur is vertical or horizontal",
 | 
			
		||||
                          FALSE,
 | 
			
		||||
                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 | 
			
		||||
 | 
			
		||||
  g_object_class_install_properties (object_class, N_PROPS, properties);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
shell_blur_effect_init (ShellBlurEffect *self)
 | 
			
		||||
{
 | 
			
		||||
  self->blur_radius = 0;
 | 
			
		||||
  self->brightness = 1.f;
 | 
			
		||||
  self->vertical = FALSE;
 | 
			
		||||
  self->pipeline = create_pipeline ();
 | 
			
		||||
 | 
			
		||||
  self->blur_radius_uniform =
 | 
			
		||||
    cogl_pipeline_get_uniform_location (self->pipeline, "blur_radius");
 | 
			
		||||
  self->brightness_uniform =
 | 
			
		||||
    cogl_pipeline_get_uniform_location (self->pipeline, "brightness");
 | 
			
		||||
  self->pixel_step_uniform =
 | 
			
		||||
    cogl_pipeline_get_uniform_location (self->pipeline, "pixel_step");
 | 
			
		||||
  self->vertical_uniform =
 | 
			
		||||
    cogl_pipeline_get_uniform_location (self->pipeline, "vertical");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ShellBlurEffect *
 | 
			
		||||
shell_blur_effect_new (void)
 | 
			
		||||
{
 | 
			
		||||
  return g_object_new (SHELL_TYPE_BLUR_EFFECT, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
shell_blur_effect_get_blur_radius (ShellBlurEffect *self)
 | 
			
		||||
{
 | 
			
		||||
  g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), -1);
 | 
			
		||||
 | 
			
		||||
  return self->blur_radius;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
shell_blur_effect_set_blur_radius (ShellBlurEffect *self,
 | 
			
		||||
                                   int              radius)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (SHELL_IS_BLUR_EFFECT (self));
 | 
			
		||||
 | 
			
		||||
  if (self->blur_radius == radius)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  self->blur_radius = radius;
 | 
			
		||||
  queue_actor_repaint (self);
 | 
			
		||||
 | 
			
		||||
  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BLUR_RADIUS]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float
 | 
			
		||||
shell_blur_effect_get_brightness (ShellBlurEffect *self)
 | 
			
		||||
{
 | 
			
		||||
  g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), FALSE);
 | 
			
		||||
 | 
			
		||||
  return self->brightness;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
shell_blur_effect_set_brightness (ShellBlurEffect *self,
 | 
			
		||||
                                  float            brightness)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (SHELL_IS_BLUR_EFFECT (self));
 | 
			
		||||
 | 
			
		||||
  if (self->brightness == brightness)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  self->brightness = brightness;
 | 
			
		||||
  queue_actor_repaint (self);
 | 
			
		||||
 | 
			
		||||
  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BRIGHTNESS]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
shell_blur_effect_get_vertical (ShellBlurEffect *self)
 | 
			
		||||
{
 | 
			
		||||
  g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), FALSE);
 | 
			
		||||
 | 
			
		||||
  return self->vertical;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
shell_blur_effect_set_vertical (ShellBlurEffect *self,
 | 
			
		||||
                                gboolean         vertical)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (SHELL_IS_BLUR_EFFECT (self));
 | 
			
		||||
 | 
			
		||||
  if (self->vertical == vertical)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  self->vertical = vertical;
 | 
			
		||||
  queue_actor_repaint (self);
 | 
			
		||||
 | 
			
		||||
  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VERTICAL]);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								src/shell-blur-effect.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/shell-blur-effect.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
/* shell-blur-effect.h
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define SHELL_TYPE_BLUR_EFFECT (shell_blur_effect_get_type())
 | 
			
		||||
 | 
			
		||||
G_DECLARE_FINAL_TYPE (ShellBlurEffect, shell_blur_effect, SHELL, BLUR_EFFECT, ClutterOffscreenEffect)
 | 
			
		||||
 | 
			
		||||
ShellBlurEffect *shell_blur_effect_new (void);
 | 
			
		||||
 | 
			
		||||
int shell_blur_effect_get_blur_radius (ShellBlurEffect *self);
 | 
			
		||||
void shell_blur_effect_set_blur_radius (ShellBlurEffect *self,
 | 
			
		||||
                                        int              radius);
 | 
			
		||||
 | 
			
		||||
float shell_blur_effect_get_brightness (ShellBlurEffect *self);
 | 
			
		||||
void shell_blur_effect_set_brightness (ShellBlurEffect *self,
 | 
			
		||||
                                       float            brightness);
 | 
			
		||||
 | 
			
		||||
gboolean shell_blur_effect_get_vertical (ShellBlurEffect *self);
 | 
			
		||||
void shell_blur_effect_set_vertical (ShellBlurEffect *self,
 | 
			
		||||
                                     gboolean         vertical);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
		Reference in New Issue
	
	Block a user