2011-09-28 13:16:26 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2019-01-31 14:07:06 +00:00
|
|
|
/* exported Button, SystemIndicator */
|
2010-06-22 21:02:26 +00:00
|
|
|
|
2023-06-08 04:52:46 +00:00
|
|
|
const Atk = imports.gi.Atk;
|
|
|
|
const Clutter = imports.gi.Clutter;
|
|
|
|
const GObject = imports.gi.GObject;
|
|
|
|
const St = imports.gi.St;
|
2011-02-08 19:53:43 +00:00
|
|
|
|
2010-06-22 21:02:26 +00:00
|
|
|
const Main = imports.ui.main;
|
2011-06-09 15:50:24 +00:00
|
|
|
const Params = imports.misc.params;
|
|
|
|
const PopupMenu = imports.ui.popupMenu;
|
|
|
|
|
2017-10-31 01:23:39 +00:00
|
|
|
var ButtonBox = GObject.registerClass(
|
|
|
|
class ButtonBox extends St.Widget {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init(params) {
|
2019-10-17 21:40:24 +00:00
|
|
|
params = Params.parse(params, {
|
|
|
|
style_class: 'panel-button',
|
|
|
|
x_expand: true,
|
|
|
|
y_expand: true,
|
|
|
|
}, true);
|
2018-07-06 08:48:15 +00:00
|
|
|
|
2017-10-31 01:23:39 +00:00
|
|
|
super._init(params);
|
2018-07-06 08:48:15 +00:00
|
|
|
|
|
|
|
this._delegate = this;
|
2011-06-09 15:50:24 +00:00
|
|
|
|
2019-10-17 21:40:24 +00:00
|
|
|
this.container = new St.Bin({ child: this });
|
2012-09-04 16:27:50 +00:00
|
|
|
|
2018-07-06 08:48:15 +00:00
|
|
|
this.connect('style-changed', this._onStyleChanged.bind(this));
|
2018-08-29 01:37:27 +00:00
|
|
|
this.connect('destroy', this._onDestroy.bind(this));
|
|
|
|
|
2011-06-09 15:50:24 +00:00
|
|
|
this._minHPadding = this._natHPadding = 0.0;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-06-09 15:50:24 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onStyleChanged(actor) {
|
2011-06-09 15:50:24 +00:00
|
|
|
let themeNode = actor.get_theme_node();
|
|
|
|
|
|
|
|
this._minHPadding = themeNode.get_length('-minimum-hpadding');
|
|
|
|
this._natHPadding = themeNode.get_length('-natural-hpadding');
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-06-09 15:50:24 +00:00
|
|
|
|
2019-01-31 14:08:10 +00:00
|
|
|
vfunc_get_preferred_width(_forHeight) {
|
2018-07-06 08:48:15 +00:00
|
|
|
let child = this.get_first_child();
|
|
|
|
let minimumSize, naturalSize;
|
2011-06-09 15:50:24 +00:00
|
|
|
|
2018-07-06 08:48:15 +00:00
|
|
|
if (child)
|
|
|
|
[minimumSize, naturalSize] = child.get_preferred_width(-1);
|
|
|
|
else
|
|
|
|
minimumSize = naturalSize = 0;
|
|
|
|
|
|
|
|
minimumSize += 2 * this._minHPadding;
|
|
|
|
naturalSize += 2 * this._natHPadding;
|
2011-06-09 15:50:24 +00:00
|
|
|
|
2018-07-06 08:48:15 +00:00
|
|
|
return [minimumSize, naturalSize];
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-06-09 15:50:24 +00:00
|
|
|
|
2019-01-31 14:08:10 +00:00
|
|
|
vfunc_get_preferred_height(_forWidth) {
|
2018-07-06 08:48:15 +00:00
|
|
|
let child = this.get_first_child();
|
2011-06-09 15:50:24 +00:00
|
|
|
|
2018-07-06 08:48:15 +00:00
|
|
|
if (child)
|
|
|
|
return child.get_preferred_height(-1);
|
|
|
|
|
|
|
|
return [0, 0];
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-06-09 15:50:24 +00:00
|
|
|
|
2020-05-09 19:30:26 +00:00
|
|
|
vfunc_allocate(box) {
|
|
|
|
this.set_allocation(box);
|
2018-07-06 08:48:15 +00:00
|
|
|
|
|
|
|
let child = this.get_first_child();
|
2014-06-08 19:18:49 +00:00
|
|
|
if (!child)
|
2011-06-09 15:50:24 +00:00
|
|
|
return;
|
|
|
|
|
2019-02-01 13:41:55 +00:00
|
|
|
let [, natWidth] = child.get_preferred_width(-1);
|
2011-06-09 15:50:24 +00:00
|
|
|
|
|
|
|
let availWidth = box.x2 - box.x1;
|
|
|
|
let availHeight = box.y2 - box.y1;
|
|
|
|
|
|
|
|
let childBox = new Clutter.ActorBox();
|
|
|
|
if (natWidth + 2 * this._natHPadding <= availWidth) {
|
|
|
|
childBox.x1 = this._natHPadding;
|
|
|
|
childBox.x2 = availWidth - this._natHPadding;
|
|
|
|
} else {
|
|
|
|
childBox.x1 = this._minHPadding;
|
|
|
|
childBox.x2 = availWidth - this._minHPadding;
|
|
|
|
}
|
|
|
|
|
2013-08-03 12:30:46 +00:00
|
|
|
childBox.y1 = 0;
|
|
|
|
childBox.y2 = availHeight;
|
2011-06-09 15:50:24 +00:00
|
|
|
|
2020-05-09 19:30:26 +00:00
|
|
|
child.allocate(childBox);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2018-08-29 01:37:27 +00:00
|
|
|
|
|
|
|
_onDestroy() {
|
|
|
|
this.container.child = null;
|
|
|
|
this.container.destroy();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-11-20 14:38:48 +00:00
|
|
|
});
|
2010-06-22 21:02:26 +00:00
|
|
|
|
2017-10-31 01:23:39 +00:00
|
|
|
var Button = GObject.registerClass({
|
2019-01-29 01:27:05 +00:00
|
|
|
Signals: { 'menu-set': {} },
|
2017-10-31 01:23:39 +00:00
|
|
|
}, class PanelMenuButton extends ButtonBox {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init(menuAlignment, nameText, dontCreateMenu) {
|
2020-08-12 18:59:01 +00:00
|
|
|
super._init({
|
|
|
|
reactive: true,
|
|
|
|
can_focus: true,
|
|
|
|
track_hover: true,
|
|
|
|
accessible_name: nameText ?? '',
|
|
|
|
accessible_role: Atk.Role.MENU,
|
|
|
|
});
|
2011-06-09 15:50:24 +00:00
|
|
|
|
2011-05-15 16:55:23 +00:00
|
|
|
if (dontCreateMenu)
|
2019-04-09 23:17:51 +00:00
|
|
|
this.menu = new PopupMenu.PopupDummyMenu(this);
|
2011-05-15 16:55:23 +00:00
|
|
|
else
|
2019-04-09 23:17:51 +00:00
|
|
|
this.setMenu(new PopupMenu.PopupMenu(this, menuAlignment, St.Side.TOP, 0));
|
2023-03-08 03:48:05 +00:00
|
|
|
|
|
|
|
this.connect('key-press-event',
|
|
|
|
(o, ev) => global.focus_manager.navigate_from_event(ev));
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-01-05 18:00:06 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
setSensitive(sensitive) {
|
2018-07-06 08:48:15 +00:00
|
|
|
this.reactive = sensitive;
|
|
|
|
this.can_focus = sensitive;
|
|
|
|
this.track_hover = sensitive;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-09-01 21:44:46 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
setMenu(menu) {
|
2011-05-15 16:55:23 +00:00
|
|
|
if (this.menu)
|
|
|
|
this.menu.destroy();
|
|
|
|
|
|
|
|
this.menu = menu;
|
|
|
|
if (this.menu) {
|
|
|
|
this.menu.actor.add_style_class_name('panel-menu');
|
2017-12-02 00:27:35 +00:00
|
|
|
this.menu.connect('open-state-changed', this._onOpenStateChanged.bind(this));
|
|
|
|
this.menu.actor.connect('key-press-event', this._onMenuKeyPress.bind(this));
|
2011-05-15 16:55:23 +00:00
|
|
|
|
|
|
|
Main.uiGroup.add_actor(this.menu.actor);
|
|
|
|
this.menu.actor.hide();
|
|
|
|
}
|
2015-04-28 09:05:58 +00:00
|
|
|
this.emit('menu-set');
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-06-22 21:02:26 +00:00
|
|
|
|
2019-09-10 05:42:48 +00:00
|
|
|
vfunc_event(event) {
|
2014-07-22 10:28:00 +00:00
|
|
|
if (this.menu &&
|
|
|
|
(event.type() == Clutter.EventType.TOUCH_BEGIN ||
|
|
|
|
event.type() == Clutter.EventType.BUTTON_PRESS))
|
|
|
|
this.menu.toggle();
|
2011-05-15 16:55:23 +00:00
|
|
|
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-06-22 21:02:26 +00:00
|
|
|
|
2019-09-10 05:42:48 +00:00
|
|
|
vfunc_hide() {
|
|
|
|
super.vfunc_hide();
|
2013-07-03 13:55:35 +00:00
|
|
|
|
2019-09-10 05:42:48 +00:00
|
|
|
if (this.menu)
|
2013-07-03 13:55:35 +00:00
|
|
|
this.menu.close();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2013-07-03 13:55:35 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onMenuKeyPress(actor, event) {
|
2013-05-04 01:33:05 +00:00
|
|
|
if (global.focus_manager.navigate_from_event(event))
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_STOP;
|
2013-05-04 01:33:05 +00:00
|
|
|
|
2011-02-08 19:53:43 +00:00
|
|
|
let symbol = event.get_key_symbol();
|
|
|
|
if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
|
2019-04-09 23:17:51 +00:00
|
|
|
let group = global.focus_manager.get_group(this);
|
2011-02-08 19:53:43 +00:00
|
|
|
if (group) {
|
2019-08-19 19:38:51 +00:00
|
|
|
let direction = symbol == Clutter.KEY_Left ? St.DirectionType.LEFT : St.DirectionType.RIGHT;
|
2019-04-09 23:17:51 +00:00
|
|
|
group.navigate_focus(this, direction, false);
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_STOP;
|
2011-02-08 19:53:43 +00:00
|
|
|
}
|
|
|
|
}
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-02-08 19:53:43 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onOpenStateChanged(menu, open) {
|
2010-11-03 17:30:08 +00:00
|
|
|
if (open)
|
2019-04-09 23:17:51 +00:00
|
|
|
this.add_style_pseudo_class('active');
|
2010-11-03 17:30:08 +00:00
|
|
|
else
|
2019-04-09 23:17:51 +00:00
|
|
|
this.remove_style_pseudo_class('active');
|
2012-02-28 18:09:56 +00:00
|
|
|
|
|
|
|
// Setting the max-height won't do any good if the minimum height of the
|
|
|
|
// menu is higher then the screen; it's useful if part of the menu is
|
|
|
|
// scrollable so the minimum height is smaller than the natural height
|
2013-01-28 05:09:12 +00:00
|
|
|
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
2017-04-07 01:17:12 +00:00
|
|
|
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
2015-02-13 19:52:11 +00:00
|
|
|
let verticalMargins = this.menu.actor.margin_top + this.menu.actor.margin_bottom;
|
2017-04-07 01:17:12 +00:00
|
|
|
|
|
|
|
// The workarea and margin dimensions are in physical pixels, but CSS
|
|
|
|
// measures are in logical pixels, so make sure to consider the scale
|
|
|
|
// factor when computing max-height
|
|
|
|
let maxHeight = Math.round((workArea.height - verticalMargins) / scaleFactor);
|
2022-02-07 14:14:06 +00:00
|
|
|
this.menu.actor.style = `max-height: ${maxHeight}px;`;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-08-22 21:19:13 +00:00
|
|
|
|
2018-07-06 08:48:15 +00:00
|
|
|
_onDestroy() {
|
2012-10-26 10:34:45 +00:00
|
|
|
if (this.menu)
|
|
|
|
this.menu.destroy();
|
2020-07-28 16:52:53 +00:00
|
|
|
super._onDestroy();
|
2010-06-22 21:02:26 +00:00
|
|
|
}
|
2011-11-20 14:38:48 +00:00
|
|
|
});
|
2010-06-22 21:06:17 +00:00
|
|
|
|
2013-06-06 21:27:25 +00:00
|
|
|
/* SystemIndicator:
|
2010-06-22 21:06:17 +00:00
|
|
|
*
|
2013-06-06 21:27:25 +00:00
|
|
|
* This class manages one system indicator, which are the icons
|
|
|
|
* that you see at the top right. A system indicator is composed
|
|
|
|
* of an icon and a menu section, which will be composed into the
|
|
|
|
* aggregate menu.
|
2010-06-22 21:06:17 +00:00
|
|
|
*/
|
2019-10-28 18:35:33 +00:00
|
|
|
var SystemIndicator = GObject.registerClass(
|
|
|
|
class SystemIndicator extends St.BoxLayout {
|
2019-07-16 09:24:13 +00:00
|
|
|
_init() {
|
|
|
|
super._init({
|
|
|
|
style_class: 'panel-status-indicators-box',
|
|
|
|
reactive: true,
|
2019-08-20 21:43:54 +00:00
|
|
|
visible: false,
|
2019-07-16 09:24:13 +00:00
|
|
|
});
|
2013-06-06 21:27:32 +00:00
|
|
|
this.menu = new PopupMenu.PopupMenuSection();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-12-21 01:25:54 +00:00
|
|
|
|
2019-07-16 09:24:13 +00:00
|
|
|
get indicators() {
|
|
|
|
let klass = this.constructor.name;
|
|
|
|
let { stack } = new Error();
|
|
|
|
log(`Usage of indicator.indicators is deprecated for ${klass}\n${stack}`);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_syncIndicatorsVisible() {
|
2019-07-16 09:24:13 +00:00
|
|
|
this.visible = this.get_children().some(a => a.visible);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-07-15 23:46:25 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_addIndicator() {
|
2013-07-19 10:05:47 +00:00
|
|
|
let icon = new St.Icon({ style_class: 'system-status-icon' });
|
2019-07-16 09:24:13 +00:00
|
|
|
this.add_actor(icon);
|
2017-12-02 00:27:35 +00:00
|
|
|
icon.connect('notify::visible', this._syncIndicatorsVisible.bind(this));
|
2013-07-15 23:46:25 +00:00
|
|
|
this._syncIndicatorsVisible();
|
2012-08-26 13:49:18 +00:00
|
|
|
return icon;
|
2010-06-22 21:06:17 +00:00
|
|
|
}
|
2019-07-16 09:24:13 +00:00
|
|
|
});
|