/* extension.js * * 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 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 . * * SPDX-License-Identifier: GPL-2.0-or-later */ /* exported init */ const GETTEXT_DOMAIN = 'activities-icon-and-label'; const { Atk, Clutter, GLib, GObject, Meta, Shell, St, Gio } = imports.gi; const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Main = imports.ui.main; const PanelMenu = imports.ui.panelMenu; const PopupMenu = imports.ui.popupMenu; var BUTTON_DND_ACTIVATION_TIMEOUT = 250; const ActivitiesIndicator = GObject.registerClass( class ActivitiesIndicator extends PanelMenu.Button { _init() { super._init(0.0, _('Activities Icon and Label')); this.accessible_role = Atk.Role.TOGGLE_BUTTON; this.name = 'panelActivities'; /* Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". */ const box = new St.BoxLayout(); this.add_child(box); this._icon = new St.Icon({ icon_name: 'calculate', style_class: 'panel-logo-icon', }); box.add_child(this._icon); this._label = new St.Label({ text: _('Activities'), y_align: Clutter.ActorAlign.CENTER, }); box.add_child(this._label); this.label_actor = this._label; this._showingSignal = Main.overview.connect('showing', () => { this.add_style_pseudo_class('overview'); this.add_accessible_state(Atk.StateType.CHECKED); }); this._hidingSignal = Main.overview.connect('hiding', () => { this.remove_style_pseudo_class('overview'); this.remove_accessible_state(Atk.StateType.CHECKED); }); this._xdndTimeOut = 0; } handleDragOver(source, _actor, _x, _y, _time) { if (source != Main.xdndHandler) return DND.DragMotionResult.CONTINUE; if (this._xdndTimeOut != 0) GLib.source_remove(this._xdndTimeOut); this._xdndTimeOut = GLib.timeout_add(GLib.PRIORITY_DEFAULT, BUTTON_DND_ACTIVATION_TIMEOUT, () => { this._xdndToggleOverview(); }); GLib.Source.set_name_by_id(this._xdndTimeOut, '[gnome-shell] this._xdndToggleOverview'); return DND.DragMotionResult.CONTINUE; } vfunc_captured_event(event) { if (event.type() == Clutter.EventType.BUTTON_PRESS || event.type() == Clutter.EventType.TOUCH_BEGIN) { if (!Main.overview.shouldToggleByCornerOrButton()) return Clutter.EVENT_STOP; } return Clutter.EVENT_PROPAGATE; } vfunc_event(event) { if (event.type() == Clutter.EventType.TOUCH_END || event.type() == Clutter.EventType.BUTTON_RELEASE) { if (Main.overview.shouldToggleByCornerOrButton()) Main.overview.toggle(); } return Clutter.EVENT_PROPAGATE; } vfunc_key_release_event(keyEvent) { let symbol = keyEvent.keyval; if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) { if (Main.overview.shouldToggleByCornerOrButton()) { Main.overview.toggle(); return Clutter.EVENT_STOP; } } return Clutter.EVENT_PROPAGATE; } _xdndToggleOverview() { let [x, y] = global.get_pointer(); let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y); if (pickedActor == this && Main.overview.shouldToggleByCornerOrButton()) Main.overview.toggle(); GLib.source_remove(this._xdndTimeOut); this._xdndTimeOut = 0; return GLib.SOURCE_REMOVE; } _onDestroy() { if (this._showingSignal) { Main.overview.disconnect(this._showingSignal); this._showingSignal = null; } if (this._hidingSignal) { Main.overview.disconnect(this._hidingSignal); this._hidingSignal = null; } if (this._xdndTimeOut) { GLib.Source.remove(this._xdndTimeOut); this._xdndTimeOut = null; } super.destroy(); } }); class Extension { constructor(uuid) { this._uuid = uuid; } enable() { Main.panel.statusArea['activities'].hide(); this._indicator = new ActivitiesIndicator(); Main.panel.addToStatusArea(this._uuid, this._indicator, 0, 'left'); } disable() { this._indicator.destroy(); this._indicator = null; if (Main.sessionMode.currentMode !== 'unlock-dialog') Main.panel.statusArea['activities'].show(); } } function init(meta) { return new Extension(meta.uuid); }