From fd39875612bb6895e820924608c7a9719a9d326e Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 18 Jul 2017 12:58:14 -0400 Subject: [PATCH] gdm: add AuthList control Ultimately, we want to add support for GDM's new ChoiceList PAM extension. That extension allows PAM modules to present a list of choices to the user. Before we can support that extension, however, we need to have a list control in the login-screen/unlock screen. This commit adds that control. For the most part, it's a copy-and-paste of the gdm userlist, but with less features. It lacks API specific to the users, lacks the built in timed login indicator, etc. It does feature a label heading. --- js/gdm/authList.js | 195 ++++++++++++++++++++++++++++++++++ js/js-resources.gresource.xml | 1 + 2 files changed, 196 insertions(+) create mode 100644 js/gdm/authList.js diff --git a/js/gdm/authList.js b/js/gdm/authList.js new file mode 100644 index 000000000..fc1c3d6e4 --- /dev/null +++ b/js/gdm/authList.js @@ -0,0 +1,195 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +/* + * Copyright 2017 Red Hat, Inc + * + * 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 2, 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 . + */ + +const Clutter = imports.gi.Clutter; +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Signals = imports.signals; +const St = imports.gi.St; + +const Tweener = imports.ui.tweener; + +const _SCROLL_ANIMATION_TIME = 0.5; + +const AuthListItem = new Lang.Class({ + Name: 'AuthListItem', + + _init(key, text) { + this.key = key; + let label = new St.Label({ style_class: 'auth-list-item-label', + y_align: Clutter.ActorAlign.CENTER }); + label.text = text; + + this.actor = new St.Button({ style_class: 'login-dialog-user-list-item', + button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, + can_focus: true, + child: label, + reactive: true, + x_align: St.Align.START, + x_fill: true }); + + this.actor.connect('key-focus-in', () => { + this._setSelected(true); + }); + this.actor.connect('key-focus-out', () => { + this._setSelected(false); + }); + this.actor.connect('notify::hover', () => { + this._setSelected(this.actor.hover); + }); + + this.actor.connect('clicked', this._onClicked.bind(this)); + }, + + _onClicked() { + this.emit('activate'); + }, + + _setSelected(selected) { + if (selected) { + this.actor.add_style_pseudo_class('selected'); + this.actor.grab_key_focus(); + } else { + this.actor.remove_style_pseudo_class('selected'); + } + } +}); +Signals.addSignalMethods(AuthListItem.prototype); + +const AuthList = new Lang.Class({ + Name: 'AuthList', + + _init() { + this.actor = new St.BoxLayout({ vertical: true, + style_class: 'login-dialog-auth-list-layout' }); + + this.label = new St.Label({ style_class: 'prompt-dialog-headline' }); + this.actor.add_actor(this.label); + + this._scrollView = new St.ScrollView({ style_class: 'login-dialog-user-list-view'}); + this._scrollView.set_policy(Gtk.PolicyType.NEVER, + Gtk.PolicyType.AUTOMATIC); + this.actor.add_actor(this._scrollView); + + this._box = new St.BoxLayout({ vertical: true, + style_class: 'login-dialog-user-list', + pseudo_class: 'expanded' }); + + this._scrollView.add_actor(this._box); + this._items = {}; + + this.actor.connect('key-focus-in', this._moveFocusToItems.bind(this)); + }, + + _moveFocusToItems() { + let hasItems = Object.keys(this._items).length > 0; + + if (!hasItems) + return; + + if (global.stage.get_key_focus() != this.actor) + return; + + let focusSet = this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); + if (!focusSet) { + Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { + this._moveFocusToItems(); + return false; + }); + } + }, + + _onItemActivated(activatedItem) { + this.emit('activate', activatedItem.key); + }, + + scrollToItem(item) { + let box = item.actor.get_allocation_box(); + + let adjustment = this._scrollView.get_vscroll_bar().get_adjustment(); + + let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0); + Tweener.removeTweens(adjustment); + Tweener.addTween (adjustment, + { value: value, + time: _SCROLL_ANIMATION_TIME, + transition: 'easeOutQuad' }); + }, + + jumpToItem(item) { + let box = item.actor.get_allocation_box(); + + let adjustment = this._scrollView.get_vscroll_bar().get_adjustment(); + + let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0); + + adjustment.set_value(value); + }, + + getItem(key) { + let item = this._items[key]; + + if (!item) + return null; + + return item; + }, + + addItem(key, text) { + this.removeItem(key); + + let item = new AuthListItem(key, text); + this._box.add(item.actor, { x_fill: true }); + + this._items[key] = item; + + item.connect('activate', + this._onItemActivated.bind(this)); + + // Try to keep the focused item front-and-center + item.actor.connect('key-focus-in', + () => { this.scrollToItem(item); }); + + this._moveFocusToItems(); + + this.emit('item-added', item); + }, + + removeItem(key) { + let item = this._items[key]; + + if (!item) + return; + + item.actor.destroy(); + delete this._items[key]; + }, + + numItems() { + return Object.keys(this._items).length; + }, + + clear() { + this.label.text = ""; + this._box.destroy_all_children(); + this._items = {}; + } +}); +Signals.addSignalMethods(AuthList.prototype); diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml index 883b62d66..58035d303 100644 --- a/js/js-resources.gresource.xml +++ b/js/js-resources.gresource.xml @@ -1,6 +1,7 @@ + gdm/authList.js gdm/authPrompt.js gdm/batch.js gdm/fingerprint.js -- 2.17.1