/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const Clutter = imports.gi.Clutter; const Gtk = imports.gi.Gtk; const Signals = imports.signals; const St = imports.gi.St; const Lang = imports.lang; const PopupMenu = imports.ui.popupMenu; const Main = imports.ui.main; function Button(menuAlignment) { this._init(menuAlignment); } Button.prototype = { _init: function(menuAlignment) { this.actor = new St.Bin({ style_class: 'panel-button', reactive: true, can_focus: true, x_fill: true, y_fill: false, track_hover: true }); this.actor._delegate = this; this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress)); this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress)); this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP); this.menu.actor.add_style_class_name('panel-menu'); this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged)); this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress)); Main.uiGroup.add_actor(this.menu.actor); this.menu.actor.hide(); }, _onButtonPress: function(actor, event) { if (!this.menu.isOpen) { // 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 let monitor = Main.layoutManager.primaryMonitor; this.menu.actor.style = ('max-height: ' + Math.round(monitor.height - Main.panel.actor.height) + 'px;'); } this.menu.toggle(); }, _onSourceKeyPress: function(actor, event) { let symbol = event.get_key_symbol(); if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) { this.menu.toggle(); return true; } else if (symbol == Clutter.KEY_Escape && this.menu.isOpen) { this.menu.close(); return true; } else if (symbol == Clutter.KEY_Down) { if (!this.menu.isOpen) this.menu.toggle(); this.menu.actor.navigate_focus(this.actor, Gtk.DirectionType.DOWN, false); return true; } else return false; }, _onMenuKeyPress: function(actor, event) { let symbol = event.get_key_symbol(); if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) { let focusManager = St.FocusManager.get_for_stage(global.stage); let group = focusManager.get_group(this.actor); if (group) { let direction = (symbol == Clutter.KEY_Left) ? Gtk.DirectionType.LEFT : Gtk.DirectionType.RIGHT; group.navigate_focus(this.actor, direction, false); return true; } } return false; }, _onOpenStateChanged: function(menu, open) { if (open) this.actor.add_style_pseudo_class('active'); else this.actor.remove_style_pseudo_class('active'); }, destroy: function() { this.actor._delegate = null; this.menu.destroy(); this.actor.destroy(); this.emit('destroy'); } }; Signals.addSignalMethods(Button.prototype); /* SystemStatusButton: * * This class manages one System Status indicator (network, keyboard, * volume, bluetooth...), which is just a PanelMenuButton with an * icon and a tooltip */ function SystemStatusButton() { this._init.apply(this, arguments); } SystemStatusButton.prototype = { __proto__: Button.prototype, _init: function(iconName,tooltipText) { Button.prototype._init.call(this, 0.0); this._iconActor = new St.Icon({ icon_name: iconName, icon_type: St.IconType.SYMBOLIC, style_class: 'system-status-icon' }); this.actor.set_child(this._iconActor); this.actor.add_style_class_name('panel-status-button'); this.setTooltip(tooltipText); }, setIcon: function(iconName) { this._iconActor.icon_name = iconName; }, setGIcon: function(gicon) { this._iconActor.gicon = gicon; }, setTooltip: function(text) { if (text != null) { this.tooltip = text; this.actor.has_tooltip = true; this.actor.tooltip_text = text; } else { this.actor.has_tooltip = false; this.tooltip = null; } } };