2013-02-17 20:54:46 -05:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
|
|
//
|
|
|
|
// A widget showing the user avatar and name
|
2013-08-26 18:36:16 -04:00
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
import Clutter from 'gi://Clutter';
|
|
|
|
import GLib from 'gi://GLib';
|
|
|
|
import GObject from 'gi://GObject';
|
|
|
|
import St from 'gi://St';
|
2013-02-17 20:54:46 -05:00
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
import * as Params from '../misc/params.js';
|
2013-04-23 22:31:08 -04:00
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const AVATAR_ICON_SIZE = 64;
|
2013-04-23 22:31:08 -04:00
|
|
|
|
|
|
|
// Adapted from gdm/gui/user-switch-applet/applet.c
|
|
|
|
//
|
|
|
|
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
|
|
|
|
// Copyright (C) 2008,2009 Red Hat, Inc.
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
export const Avatar = GObject.registerClass(
|
2019-10-28 14:35:33 -04:00
|
|
|
class Avatar extends St.Bin {
|
2019-07-16 05:24:13 -04:00
|
|
|
_init(user, params) {
|
|
|
|
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
2020-01-14 09:53:36 -05:00
|
|
|
params = Params.parse(params, {
|
|
|
|
styleClass: 'user-icon',
|
|
|
|
reactive: false,
|
2020-02-16 17:03:14 -05:00
|
|
|
iconSize: AVATAR_ICON_SIZE,
|
2020-01-14 09:53:36 -05:00
|
|
|
});
|
2013-04-23 22:31:08 -04:00
|
|
|
|
2019-07-16 05:24:13 -04:00
|
|
|
super._init({
|
|
|
|
style_class: params.styleClass,
|
|
|
|
reactive: params.reactive,
|
|
|
|
width: params.iconSize * themeContext.scaleFactor,
|
2019-08-20 17:43:54 -04:00
|
|
|
height: params.iconSize * themeContext.scaleFactor,
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
this._iconSize = params.iconSize;
|
|
|
|
this._user = user;
|
2017-08-10 11:21:50 -04:00
|
|
|
|
2019-08-30 19:32:03 -04:00
|
|
|
this.bind_property('reactive', this, 'track-hover',
|
|
|
|
GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
this.bind_property('reactive', this, 'can-focus',
|
|
|
|
GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
|
2017-08-10 11:21:50 -04:00
|
|
|
// Monitor the scaling factor to make sure we recreate the avatar when needed.
|
2021-08-15 18:36:59 -04:00
|
|
|
themeContext.connectObject('notify::scale-factor', this.update.bind(this), this);
|
2019-07-16 05:24:13 -04:00
|
|
|
}
|
|
|
|
|
2020-01-14 09:53:36 -05:00
|
|
|
vfunc_style_changed() {
|
|
|
|
super.vfunc_style_changed();
|
|
|
|
|
|
|
|
let node = this.get_theme_node();
|
|
|
|
let [found, iconSize] = node.lookup_length('icon-size', false);
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
|
|
|
|
|
|
|
// node.lookup_length() returns a scaled value, but we
|
|
|
|
// need unscaled
|
|
|
|
this._iconSize = iconSize / themeContext.scaleFactor;
|
|
|
|
this.update();
|
|
|
|
}
|
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
setSensitive(sensitive) {
|
2019-07-16 05:24:13 -04:00
|
|
|
this.reactive = sensitive;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2013-04-23 22:31:08 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
update() {
|
2020-01-17 01:47:34 -05:00
|
|
|
let iconFile = null;
|
|
|
|
if (this._user) {
|
|
|
|
iconFile = this._user.get_icon_file();
|
|
|
|
if (iconFile && !GLib.file_test(iconFile, GLib.FileTest.EXISTS))
|
|
|
|
iconFile = null;
|
|
|
|
}
|
2013-04-23 22:31:08 -04:00
|
|
|
|
2020-02-16 17:16:52 -05:00
|
|
|
let { scaleFactor } = St.ThemeContext.get_for_stage(global.stage);
|
|
|
|
this.set_size(
|
|
|
|
this._iconSize * scaleFactor,
|
|
|
|
this._iconSize * scaleFactor);
|
|
|
|
|
2013-04-23 22:31:08 -04:00
|
|
|
if (iconFile) {
|
2019-07-16 05:24:13 -04:00
|
|
|
this.child = null;
|
2020-11-01 07:40:47 -05:00
|
|
|
this.add_style_class_name('user-avatar');
|
2019-07-16 05:24:13 -04:00
|
|
|
this.style = `
|
2019-03-07 07:39:17 -05:00
|
|
|
background-image: url("${iconFile}");
|
2019-07-10 11:18:16 -04:00
|
|
|
background-size: cover;`;
|
2013-04-23 22:31:08 -04:00
|
|
|
} else {
|
2019-07-16 05:24:13 -04:00
|
|
|
this.style = null;
|
2020-01-14 09:53:36 -05:00
|
|
|
this.child = new St.Icon({
|
|
|
|
icon_name: 'avatar-default-symbolic',
|
2020-02-16 17:03:14 -05:00
|
|
|
icon_size: this._iconSize,
|
2020-01-14 09:53:36 -05:00
|
|
|
});
|
2013-04-23 22:31:08 -04:00
|
|
|
}
|
|
|
|
}
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|
2013-02-17 20:54:46 -05:00
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
export const UserWidgetLabel = GObject.registerClass(
|
2017-10-30 21:23:39 -04:00
|
|
|
class UserWidgetLabel extends St.Widget {
|
2017-10-30 20:03:21 -04:00
|
|
|
_init(user) {
|
2017-10-30 21:23:39 -04:00
|
|
|
super._init({ layout_manager: new Clutter.BinLayout() });
|
2013-08-26 18:36:16 -04:00
|
|
|
|
|
|
|
this._user = user;
|
|
|
|
|
2020-03-29 17:51:13 -04:00
|
|
|
this._realNameLabel = new St.Label({
|
|
|
|
style_class: 'user-widget-label',
|
|
|
|
y_align: Clutter.ActorAlign.CENTER,
|
|
|
|
});
|
2013-08-26 18:36:16 -04:00
|
|
|
this.add_child(this._realNameLabel);
|
|
|
|
|
2020-03-29 17:51:13 -04:00
|
|
|
this._userNameLabel = new St.Label({
|
|
|
|
style_class: 'user-widget-label',
|
|
|
|
y_align: Clutter.ActorAlign.CENTER,
|
|
|
|
});
|
2013-08-26 18:36:16 -04:00
|
|
|
this.add_child(this._userNameLabel);
|
|
|
|
|
|
|
|
this._currentLabel = null;
|
|
|
|
|
2021-08-15 18:36:59 -04:00
|
|
|
this._user.connectObject(
|
|
|
|
'notify::is-loaded', this._updateUser.bind(this),
|
|
|
|
'changed', this._updateUser.bind(this), this);
|
2013-08-26 18:36:16 -04:00
|
|
|
this._updateUser();
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2013-08-26 18:36:16 -04:00
|
|
|
|
2020-05-09 15:30:26 -04:00
|
|
|
vfunc_allocate(box) {
|
|
|
|
this.set_allocation(box);
|
2013-08-26 18:36:16 -04:00
|
|
|
|
|
|
|
let availWidth = box.x2 - box.x1;
|
|
|
|
let availHeight = box.y2 - box.y1;
|
|
|
|
|
2019-02-01 08:41:55 -05:00
|
|
|
let [, , natRealNameWidth] = this._realNameLabel.get_preferred_size();
|
2013-08-26 18:36:16 -04:00
|
|
|
|
2020-10-24 14:25:49 -04:00
|
|
|
let childBox = new Clutter.ActorBox();
|
|
|
|
|
|
|
|
let hiddenLabel;
|
|
|
|
if (natRealNameWidth <= availWidth) {
|
2013-08-26 18:36:16 -04:00
|
|
|
this._currentLabel = this._realNameLabel;
|
2020-10-24 14:25:49 -04:00
|
|
|
hiddenLabel = this._userNameLabel;
|
|
|
|
} else {
|
2013-08-26 18:36:16 -04:00
|
|
|
this._currentLabel = this._userNameLabel;
|
2020-10-24 14:25:49 -04:00
|
|
|
hiddenLabel = this._realNameLabel;
|
|
|
|
}
|
2015-03-06 10:56:11 -05:00
|
|
|
this.label_actor = this._currentLabel;
|
2013-08-26 18:36:16 -04:00
|
|
|
|
2020-10-24 14:25:49 -04:00
|
|
|
hiddenLabel.allocate(childBox);
|
|
|
|
|
|
|
|
childBox.set_size(availWidth, availHeight);
|
2013-08-26 18:36:16 -04:00
|
|
|
|
2020-05-09 15:30:26 -04:00
|
|
|
this._currentLabel.allocate(childBox);
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2013-08-26 18:36:16 -04:00
|
|
|
|
2019-11-22 12:35:55 -05:00
|
|
|
vfunc_paint(paintContext) {
|
|
|
|
this._currentLabel.paint(paintContext);
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2013-08-26 18:36:16 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_updateUser() {
|
2013-08-26 18:36:16 -04:00
|
|
|
if (this._user.is_loaded) {
|
|
|
|
this._realNameLabel.text = this._user.get_real_name();
|
|
|
|
this._userNameLabel.text = this._user.get_user_name();
|
|
|
|
} else {
|
|
|
|
this._realNameLabel.text = '';
|
|
|
|
this._userNameLabel.text = '';
|
|
|
|
}
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2013-08-26 18:36:16 -04:00
|
|
|
});
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
export const UserWidget = GObject.registerClass(
|
2019-07-16 05:24:13 -04:00
|
|
|
class UserWidget extends St.BoxLayout {
|
2020-01-14 09:53:36 -05:00
|
|
|
_init(user, orientation = Clutter.Orientation.HORIZONTAL) {
|
2020-01-17 01:47:34 -05:00
|
|
|
// If user is null, that implies a username-based login authorization.
|
2013-02-17 20:54:46 -05:00
|
|
|
this._user = user;
|
|
|
|
|
2020-01-14 09:53:36 -05:00
|
|
|
let vertical = orientation == Clutter.Orientation.VERTICAL;
|
|
|
|
let xAlign = vertical ? Clutter.ActorAlign.CENTER : Clutter.ActorAlign.START;
|
|
|
|
let styleClass = vertical ? 'user-widget vertical' : 'user-widget horizontal';
|
|
|
|
|
|
|
|
super._init({
|
|
|
|
styleClass,
|
|
|
|
vertical,
|
|
|
|
xAlign,
|
|
|
|
});
|
|
|
|
|
2013-04-23 22:31:08 -04:00
|
|
|
this._avatar = new Avatar(user);
|
2020-01-14 09:53:36 -05:00
|
|
|
this._avatar.x_align = Clutter.ActorAlign.CENTER;
|
2019-07-16 05:24:13 -04:00
|
|
|
this.add_child(this._avatar);
|
2013-08-26 18:36:16 -04:00
|
|
|
|
2020-01-17 01:47:34 -05:00
|
|
|
this._userLoadedId = 0;
|
|
|
|
this._userChangedId = 0;
|
|
|
|
if (user) {
|
|
|
|
this._label = new UserWidgetLabel(user);
|
|
|
|
this.add_child(this._label);
|
2013-08-26 18:36:16 -04:00
|
|
|
|
2020-01-17 01:47:34 -05:00
|
|
|
this._label.bind_property('label-actor', this, 'label-actor',
|
|
|
|
GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
|
2021-08-15 18:36:59 -04:00
|
|
|
this._user.connectObject(
|
|
|
|
'notify::is-loaded', this._updateUser.bind(this),
|
|
|
|
'changed', this._updateUser.bind(this), this);
|
2020-02-11 08:39:22 -05:00
|
|
|
} else {
|
|
|
|
this._label = new St.Label({
|
|
|
|
style_class: 'user-widget-label',
|
|
|
|
text: 'Empty User',
|
|
|
|
opacity: 0,
|
|
|
|
});
|
|
|
|
this.add_child(this._label);
|
2020-01-17 01:47:34 -05:00
|
|
|
}
|
2015-03-06 10:56:11 -05:00
|
|
|
|
2013-08-26 18:36:16 -04:00
|
|
|
this._updateUser();
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2013-02-17 20:54:46 -05:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_updateUser() {
|
2013-02-17 20:54:46 -05:00
|
|
|
this._avatar.update();
|
|
|
|
}
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|