2011-09-28 13:16:26 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2008-10-31 18:09:20 +00:00
|
|
|
|
2019-04-04 12:29:30 +00:00
|
|
|
const { Atk, Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
2011-02-09 02:12:10 +00:00
|
|
|
const Cairo = imports.cairo;
|
2008-11-21 13:54:25 +00:00
|
|
|
const Mainloop = imports.mainloop;
|
2008-10-31 18:09:20 +00:00
|
|
|
|
2013-06-18 11:35:41 +00:00
|
|
|
const Animation = imports.ui.animation;
|
2012-08-28 21:10:44 +00:00
|
|
|
const Config = imports.misc.config;
|
2011-02-07 16:29:34 +00:00
|
|
|
const CtrlAltTab = imports.ui.ctrlAltTab;
|
2012-02-11 10:14:43 +00:00
|
|
|
const DND = imports.ui.dnd;
|
2010-05-12 21:07:41 +00:00
|
|
|
const Overview = imports.ui.overview;
|
2010-05-20 15:18:46 +00:00
|
|
|
const PopupMenu = imports.ui.popupMenu;
|
2010-06-22 21:02:26 +00:00
|
|
|
const PanelMenu = imports.ui.panelMenu;
|
2008-11-09 18:01:59 +00:00
|
|
|
const Main = imports.ui.main;
|
2010-05-20 15:18:46 +00:00
|
|
|
const Tweener = imports.ui.tweener;
|
2008-10-31 23:09:46 +00:00
|
|
|
|
2017-07-18 17:47:27 +00:00
|
|
|
var PANEL_ICON_SIZE = 16;
|
|
|
|
var APP_MENU_ICON_MARGIN = 0;
|
2009-08-11 15:32:58 +00:00
|
|
|
|
2017-07-18 17:47:27 +00:00
|
|
|
var BUTTON_DND_ACTIVATION_TIMEOUT = 250;
|
2011-01-05 14:47:27 +00:00
|
|
|
|
2017-07-18 17:47:27 +00:00
|
|
|
var SPINNER_ANIMATION_TIME = 1.0;
|
2010-06-10 12:07:33 +00:00
|
|
|
|
2011-02-09 02:12:10 +00:00
|
|
|
// To make sure the panel corners blend nicely with the panel,
|
|
|
|
// we draw background and borders the same way, e.g. drawing
|
|
|
|
// them as filled shapes from the outside inwards instead of
|
|
|
|
// using cairo stroke(). So in order to give the border the
|
|
|
|
// appearance of being drawn on top of the background, we need
|
|
|
|
// to blend border and background color together.
|
|
|
|
// For that purpose we use the following helper methods, taken
|
|
|
|
// from st-theme-node-drawing.c
|
|
|
|
function _norm(x) {
|
|
|
|
return Math.round(x / 255);
|
|
|
|
}
|
|
|
|
|
|
|
|
function _over(srcColor, dstColor) {
|
|
|
|
let src = _premultiply(srcColor);
|
|
|
|
let dst = _premultiply(dstColor);
|
|
|
|
let result = new Clutter.Color();
|
|
|
|
|
|
|
|
result.alpha = src.alpha + _norm((255 - src.alpha) * dst.alpha);
|
|
|
|
result.red = src.red + _norm((255 - src.alpha) * dst.red);
|
|
|
|
result.green = src.green + _norm((255 - src.alpha) * dst.green);
|
|
|
|
result.blue = src.blue + _norm((255 - src.alpha) * dst.blue);
|
|
|
|
|
|
|
|
return _unpremultiply(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
function _premultiply(color) {
|
|
|
|
return new Clutter.Color({ red: _norm(color.red * color.alpha),
|
|
|
|
green: _norm(color.green * color.alpha),
|
|
|
|
blue: _norm(color.blue * color.alpha),
|
|
|
|
alpha: color.alpha });
|
|
|
|
};
|
|
|
|
|
|
|
|
function _unpremultiply(color) {
|
|
|
|
if (color.alpha == 0)
|
|
|
|
return new Clutter.Color();
|
|
|
|
|
|
|
|
let red = Math.min((color.red * 255 + 127) / color.alpha, 255);
|
|
|
|
let green = Math.min((color.green * 255 + 127) / color.alpha, 255);
|
|
|
|
let blue = Math.min((color.blue * 255 + 127) / color.alpha, 255);
|
|
|
|
return new Clutter.Color({ red: red, green: green,
|
|
|
|
blue: blue, alpha: color.alpha });
|
|
|
|
};
|
|
|
|
|
2018-10-04 14:52:34 +00:00
|
|
|
class AppMenu extends PopupMenu.PopupMenu {
|
|
|
|
constructor(sourceActor) {
|
2019-06-14 18:58:50 +00:00
|
|
|
super(sourceActor, 0.5, St.Side.TOP);
|
2018-10-04 14:52:34 +00:00
|
|
|
|
2019-02-05 00:11:43 +00:00
|
|
|
this.actor.add_style_class_name('app-menu');
|
|
|
|
|
2018-10-04 14:52:34 +00:00
|
|
|
this._app = null;
|
|
|
|
this._appSystem = Shell.AppSystem.get_default();
|
|
|
|
|
|
|
|
this._windowsChangedId = 0;
|
|
|
|
|
2019-02-11 18:55:42 +00:00
|
|
|
/* Translators: This is the heading of a list of open windows */
|
|
|
|
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem(_("Open Windows")));
|
|
|
|
|
2018-10-04 14:52:34 +00:00
|
|
|
this._windowSection = new PopupMenu.PopupMenuSection();
|
|
|
|
this.addMenuItem(this._windowSection);
|
|
|
|
|
|
|
|
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
|
|
|
|
|
|
this._newWindowItem = this.addAction(_("New Window"), () => {
|
|
|
|
this._app.open_new_window(-1);
|
|
|
|
});
|
|
|
|
|
|
|
|
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
|
|
|
|
|
|
this._actionSection = new PopupMenu.PopupMenuSection();
|
|
|
|
this.addMenuItem(this._actionSection);
|
|
|
|
|
|
|
|
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
|
|
|
|
|
|
this._detailsItem = this.addAction(_("Show Details"), () => {
|
|
|
|
let id = this._app.get_id();
|
|
|
|
let args = GLib.Variant.new('(ss)', [id, '']);
|
|
|
|
Gio.DBus.get(Gio.BusType.SESSION, null, (o, res) => {
|
|
|
|
let bus = Gio.DBus.get_finish(res);
|
|
|
|
bus.call('org.gnome.Software',
|
|
|
|
'/org/gnome/Software',
|
|
|
|
'org.gtk.Actions', 'Activate',
|
|
|
|
GLib.Variant.new('(sava{sv})',
|
|
|
|
['details', [args], null]),
|
|
|
|
null, 0, -1, null, null);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-02-11 18:50:37 +00:00
|
|
|
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
|
|
|
2018-10-04 14:52:34 +00:00
|
|
|
this.addAction(_("Quit"), () => {
|
|
|
|
this._app.request_quit();
|
|
|
|
});
|
|
|
|
|
|
|
|
this._appSystem.connect('installed-changed', () => {
|
2019-02-24 01:21:56 +00:00
|
|
|
this._updateDetailsVisibility();
|
2018-10-04 14:52:34 +00:00
|
|
|
});
|
2019-02-24 01:21:56 +00:00
|
|
|
this._updateDetailsVisibility();
|
|
|
|
}
|
|
|
|
|
|
|
|
_updateDetailsVisibility() {
|
|
|
|
let sw = this._appSystem.lookup_app('org.gnome.Software.desktop');
|
2019-04-12 21:01:09 +00:00
|
|
|
this._detailsItem.visible = (sw != null);
|
2018-10-04 14:52:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isEmpty() {
|
|
|
|
if (!this._app)
|
|
|
|
return true;
|
|
|
|
return super.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
setApp(app) {
|
|
|
|
if (this._app == app)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (this._windowsChangedId)
|
|
|
|
this._app.disconnect(this._windowsChangedId);
|
|
|
|
this._windowsChangedId = 0;
|
|
|
|
|
|
|
|
this._app = app;
|
|
|
|
|
|
|
|
if (app) {
|
|
|
|
this._windowsChangedId = app.connect('windows-changed', () => {
|
|
|
|
this._updateWindowsSection();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
this._updateWindowsSection();
|
|
|
|
|
|
|
|
let appInfo = app ? app.app_info : null;
|
|
|
|
let actions = appInfo ? appInfo.list_actions() : [];
|
|
|
|
|
|
|
|
this._actionSection.removeAll();
|
|
|
|
actions.forEach(action => {
|
|
|
|
let label = appInfo.get_action_name(action);
|
|
|
|
this._actionSection.addAction(label, event => {
|
|
|
|
this._app.launch_action(action, event.get_time(), -1);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-04-12 21:01:09 +00:00
|
|
|
this._newWindowItem.visible =
|
2018-10-04 14:52:34 +00:00
|
|
|
app && app.can_open_new_window() && !actions.includes('new-window');
|
|
|
|
}
|
|
|
|
|
|
|
|
_updateWindowsSection() {
|
|
|
|
this._windowSection.removeAll();
|
|
|
|
|
|
|
|
if (!this._app)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let windows = this._app.get_windows();
|
|
|
|
windows.forEach(window => {
|
|
|
|
let title = window.title || this._app.get_name();
|
|
|
|
this._windowSection.addAction(title, event => {
|
|
|
|
Main.activateWindow(window, event.get_time());
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-26 17:00:36 +00:00
|
|
|
/**
|
2010-05-05 14:03:48 +00:00
|
|
|
* AppMenuButton:
|
2009-12-26 17:00:36 +00:00
|
|
|
*
|
|
|
|
* This class manages the "application menu" component. It tracks the
|
|
|
|
* currently focused application. However, when an app is launched,
|
|
|
|
* this menu also handles startup notification for it. So when we
|
|
|
|
* have an active startup notification, we switch modes to display that.
|
|
|
|
*/
|
2017-10-31 01:23:39 +00:00
|
|
|
var AppMenuButton = GObject.registerClass({
|
2018-07-06 08:48:15 +00:00
|
|
|
Signals: {'changed': {}},
|
2017-10-31 01:23:39 +00:00
|
|
|
}, class AppMenuButton extends PanelMenu.Button {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init(panel) {
|
2017-10-31 01:23:39 +00:00
|
|
|
super._init(0.0, null, true);
|
2011-05-15 16:55:23 +00:00
|
|
|
|
2019-04-09 23:17:51 +00:00
|
|
|
this.accessible_role = Atk.Role.MENU;
|
2012-02-27 16:31:10 +00:00
|
|
|
|
2010-10-06 21:31:22 +00:00
|
|
|
this._startingApps = [];
|
2009-08-11 15:32:58 +00:00
|
|
|
|
2012-08-28 21:10:44 +00:00
|
|
|
this._menuManager = panel.menuManager;
|
2010-10-06 21:31:22 +00:00
|
|
|
this._targetApp = null;
|
2014-09-16 10:08:19 +00:00
|
|
|
this._busyNotifyId = 0;
|
2009-08-11 15:32:58 +00:00
|
|
|
|
2010-05-05 14:03:48 +00:00
|
|
|
let bin = new St.Bin({ name: 'appMenu' });
|
2017-12-02 00:27:35 +00:00
|
|
|
bin.connect('style-changed', this._onStyleChanged.bind(this));
|
2019-04-09 23:17:51 +00:00
|
|
|
this.add_actor(bin);
|
2011-03-08 17:46:43 +00:00
|
|
|
|
2019-04-09 23:17:51 +00:00
|
|
|
this.bind_property("reactive", this, "can-focus", 0);
|
|
|
|
this.reactive = false;
|
2011-03-08 17:46:43 +00:00
|
|
|
|
2014-11-11 15:30:11 +00:00
|
|
|
this._container = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
|
2010-05-05 14:03:48 +00:00
|
|
|
bin.set_child(this._container);
|
2010-03-12 20:57:01 +00:00
|
|
|
|
2012-10-30 17:30:21 +00:00
|
|
|
let textureCache = St.TextureCache.get_default();
|
|
|
|
textureCache.connect('icon-theme-changed',
|
2017-12-02 00:27:35 +00:00
|
|
|
this._onIconThemeChanged.bind(this));
|
2012-10-30 17:30:21 +00:00
|
|
|
|
2019-02-04 23:30:41 +00:00
|
|
|
let iconEffect = new Clutter.DesaturateEffect();
|
2015-01-14 14:34:04 +00:00
|
|
|
this._iconBox = new St.Bin({ style_class: 'app-menu-icon' });
|
2019-02-04 23:30:41 +00:00
|
|
|
this._iconBox.add_effect(iconEffect);
|
2010-02-28 20:36:13 +00:00
|
|
|
this._container.add_actor(this._iconBox);
|
2013-08-12 12:36:38 +00:00
|
|
|
|
2019-02-04 23:30:41 +00:00
|
|
|
this._iconBox.connect('style-changed', () => {
|
|
|
|
let themeNode = this._iconBox.get_theme_node();
|
|
|
|
iconEffect.enabled = themeNode.get_icon_style() == St.IconStyle.SYMBOLIC;
|
|
|
|
});
|
|
|
|
|
2015-03-04 19:11:29 +00:00
|
|
|
this._label = new St.Label({ y_expand: true,
|
|
|
|
y_align: Clutter.ActorAlign.CENTER });
|
2015-02-18 20:39:33 +00:00
|
|
|
this._container.add_actor(this._label);
|
2014-02-18 12:45:26 +00:00
|
|
|
this._arrow = PopupMenu.arrowIcon(St.Side.BOTTOM);
|
2014-11-11 15:30:11 +00:00
|
|
|
this._container.add_actor(this._arrow);
|
2011-03-29 09:49:50 +00:00
|
|
|
|
2018-10-04 14:52:34 +00:00
|
|
|
this._visible = !Main.overview.visible;
|
2010-05-12 21:30:14 +00:00
|
|
|
if (!this._visible)
|
2018-07-06 08:48:15 +00:00
|
|
|
this.hide();
|
2017-12-02 00:27:35 +00:00
|
|
|
this._overviewHidingId = Main.overview.connect('hiding', this._sync.bind(this));
|
|
|
|
this._overviewShowingId = Main.overview.connect('showing', this._sync.bind(this));
|
2009-08-11 15:32:58 +00:00
|
|
|
|
2011-03-11 23:37:43 +00:00
|
|
|
this._stop = true;
|
2013-04-15 22:40:00 +00:00
|
|
|
|
2013-04-16 14:57:46 +00:00
|
|
|
this._spinner = null;
|
2010-06-10 12:07:33 +00:00
|
|
|
|
2018-10-04 14:52:34 +00:00
|
|
|
let menu = new AppMenu(this);
|
|
|
|
this.setMenu(menu);
|
|
|
|
this._menuManager.addMenu(menu);
|
|
|
|
|
2009-10-15 23:28:29 +00:00
|
|
|
let tracker = Shell.WindowTracker.get_default();
|
apps: Ensure running apps override new .desktop file data
This patch fixes the "apps vanish from alt-TAB bug".
If a "package system" rips away and possibly replaces .desktop files
at some random time, we have historically used inotify to detect this
and reread state (in a racy way, but...). In GNOME 2, this was
generally not too problematic because the menu widget was totally
separate from the list of windows - and the data they operate on was
disjoint as well.
In GNOME 3 we unify these, and this creates architectural problems
because the windows are tied to the app.
What this patch tries to do is, when rereading the application state,
if we have a running application, we keep that app around instead of
making a new instance. This ensures we preserve any state such as the
set of open windows.
This requires moving the running state into ShellAppSystem. Adjust
callers as necessary, and while we're at it drop the unused "contexts"
stuff.
This is just a somewhat quick band-aid; a REAL fix would require us
having low-level control over application installation. As long as
we're on top of random broken tar+wget wrappers, it will be gross.
A slight future improvement to this patch would add an explicit
"merge" between the old and new data. I think probably we always keep
around the ShellApp corresponding to a given ID, but replace its
GMenuTreeEntry.
https://bugzilla.gnome.org/show_bug.cgi?id=657990
2011-09-03 14:32:06 +00:00
|
|
|
let appSys = Shell.AppSystem.get_default();
|
2013-04-21 23:49:14 +00:00
|
|
|
this._focusAppNotifyId =
|
2017-12-02 00:27:35 +00:00
|
|
|
tracker.connect('notify::focus-app', this._focusAppChanged.bind(this));
|
2013-04-21 23:49:14 +00:00
|
|
|
this._appStateChangedSignalId =
|
2017-12-02 00:27:35 +00:00
|
|
|
appSys.connect('app-state-changed', this._onAppStateChanged.bind(this));
|
2013-04-21 23:49:14 +00:00
|
|
|
this._switchWorkspaceNotifyId =
|
2017-12-02 00:27:35 +00:00
|
|
|
global.window_manager.connect('switch-workspace', this._sync.bind(this));
|
2010-10-06 21:31:22 +00:00
|
|
|
|
2009-08-11 15:32:58 +00:00
|
|
|
this._sync();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-05-12 21:30:14 +00:00
|
|
|
|
2018-08-21 09:48:19 +00:00
|
|
|
fadeIn() {
|
2013-01-27 14:45:04 +00:00
|
|
|
if (this._visible)
|
2010-05-12 21:30:14 +00:00
|
|
|
return;
|
|
|
|
|
2011-02-16 20:17:46 +00:00
|
|
|
this._visible = true;
|
2019-04-09 23:17:51 +00:00
|
|
|
this.reactive = true;
|
2018-07-06 08:48:15 +00:00
|
|
|
this.show();
|
2019-04-09 23:17:51 +00:00
|
|
|
Tweener.removeTweens(this);
|
|
|
|
Tweener.addTween(this,
|
2010-05-12 21:30:14 +00:00
|
|
|
{ opacity: 255,
|
|
|
|
time: Overview.ANIMATION_TIME,
|
2011-02-16 20:17:46 +00:00
|
|
|
transition: 'easeOutQuad' });
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-05-12 21:30:14 +00:00
|
|
|
|
2018-08-21 09:48:19 +00:00
|
|
|
fadeOut() {
|
2010-05-12 21:30:14 +00:00
|
|
|
if (!this._visible)
|
|
|
|
return;
|
|
|
|
|
2011-02-16 20:17:46 +00:00
|
|
|
this._visible = false;
|
2019-04-09 23:17:51 +00:00
|
|
|
this.reactive = false;
|
|
|
|
Tweener.removeTweens(this);
|
|
|
|
Tweener.addTween(this,
|
2010-05-12 21:30:14 +00:00
|
|
|
{ opacity: 0,
|
|
|
|
time: Overview.ANIMATION_TIME,
|
|
|
|
transition: 'easeOutQuad',
|
2017-10-31 00:03:21 +00:00
|
|
|
onComplete() {
|
2018-07-06 08:48:15 +00:00
|
|
|
this.hide();
|
2010-05-12 21:30:14 +00:00
|
|
|
},
|
|
|
|
onCompleteScope: this });
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2009-08-11 15:32:58 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onStyleChanged(actor) {
|
2013-04-16 14:57:46 +00:00
|
|
|
let node = actor.get_theme_node();
|
|
|
|
let [success, icon] = node.lookup_url('spinner-image', false);
|
2014-09-19 00:04:00 +00:00
|
|
|
if (!success || (this._spinnerIcon && this._spinnerIcon.equal(icon)))
|
2013-04-16 14:57:46 +00:00
|
|
|
return;
|
|
|
|
this._spinnerIcon = icon;
|
2013-06-18 11:35:41 +00:00
|
|
|
this._spinner = new Animation.AnimatedIcon(this._spinnerIcon, PANEL_ICON_SIZE);
|
2014-11-11 15:30:11 +00:00
|
|
|
this._container.add_actor(this._spinner.actor);
|
2013-04-16 14:57:46 +00:00
|
|
|
this._spinner.actor.hide();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2013-04-16 14:57:46 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_syncIcon() {
|
2013-08-13 11:41:44 +00:00
|
|
|
if (!this._targetApp)
|
|
|
|
return;
|
|
|
|
|
2014-11-11 15:30:11 +00:00
|
|
|
let icon = this._targetApp.create_icon_texture(PANEL_ICON_SIZE - APP_MENU_ICON_MARGIN);
|
2013-07-19 19:39:48 +00:00
|
|
|
this._iconBox.set_child(icon);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2013-07-19 19:39:48 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onIconThemeChanged() {
|
2012-10-30 17:30:21 +00:00
|
|
|
if (this._iconBox.child == null)
|
|
|
|
return;
|
|
|
|
|
2013-07-19 19:39:48 +00:00
|
|
|
this._syncIcon();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-10-30 17:30:21 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
stopAnimation() {
|
2011-03-11 23:37:43 +00:00
|
|
|
if (this._stop)
|
|
|
|
return;
|
2010-06-10 12:07:33 +00:00
|
|
|
|
2011-03-11 23:37:43 +00:00
|
|
|
this._stop = true;
|
2013-04-16 14:57:46 +00:00
|
|
|
|
|
|
|
if (this._spinner == null)
|
|
|
|
return;
|
|
|
|
|
2011-03-11 23:37:43 +00:00
|
|
|
Tweener.addTween(this._spinner.actor,
|
|
|
|
{ opacity: 0,
|
|
|
|
time: SPINNER_ANIMATION_TIME,
|
|
|
|
transition: "easeOutQuad",
|
|
|
|
onCompleteScope: this,
|
2017-10-31 00:03:21 +00:00
|
|
|
onComplete() {
|
2012-11-05 22:11:27 +00:00
|
|
|
this._spinner.stop();
|
2011-03-11 23:37:43 +00:00
|
|
|
this._spinner.actor.opacity = 255;
|
|
|
|
this._spinner.actor.hide();
|
|
|
|
}
|
|
|
|
});
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-06-10 12:07:33 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
startAnimation() {
|
2010-06-10 12:07:33 +00:00
|
|
|
this._stop = false;
|
2013-04-16 14:57:46 +00:00
|
|
|
|
|
|
|
if (this._spinner == null)
|
|
|
|
return;
|
|
|
|
|
2012-11-05 22:11:27 +00:00
|
|
|
this._spinner.play();
|
2010-06-10 12:07:33 +00:00
|
|
|
this._spinner.actor.show();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-06-10 12:07:33 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onAppStateChanged(appSys, app) {
|
2010-06-10 12:07:33 +00:00
|
|
|
let state = app.state;
|
2017-10-31 00:38:18 +00:00
|
|
|
if (state != Shell.AppState.STARTING)
|
|
|
|
this._startingApps = this._startingApps.filter(a => a != app);
|
|
|
|
else if (state == Shell.AppState.STARTING)
|
2010-10-06 21:31:22 +00:00
|
|
|
this._startingApps.push(app);
|
2010-06-10 12:07:33 +00:00
|
|
|
// For now just resync on all running state changes; this is mainly to handle
|
|
|
|
// cases where the focused window's application changes without the focus
|
|
|
|
// changing. An example case is how we map OpenOffice.org based on the window
|
|
|
|
// title which is a dynamic property.
|
|
|
|
this._sync();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-06-10 12:07:33 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_focusAppChanged() {
|
2009-10-15 23:28:29 +00:00
|
|
|
let tracker = Shell.WindowTracker.get_default();
|
|
|
|
let focusedApp = tracker.focus_app;
|
2010-07-02 19:36:56 +00:00
|
|
|
if (!focusedApp) {
|
|
|
|
// If the app has just lost focus to the panel, pretend
|
|
|
|
// nothing happened; otherwise you can't keynav to the
|
|
|
|
// app menu.
|
Rework window / actor focus handling
The duality of the Clutter's key focus and mutter's window focus has long been
a problem for us in lots of case, and caused us to create large and complicated
hacks to get around the issue, including GrabHelper's focus grab model.
Instead of doing this, tie basic focus management into the core of gnome-shell,
instead of requiring complex "application-level" management to get it done
right.
Do this by making sure that only one of an actor or window can be focused at
the same time, and apply the appropriate logic to drop one or the other,
reactively.
Modals are considered a special case, as we grab all keyboard events, but at
the X level, the client window still has focus. Make sure to not do any input
synchronization when we have a modal.
At the same time, remove the FOCUSED input mode, as it's no longer necessary.
https://bugzilla.gnome.org/show_bug.cgi?id=700735
2013-05-18 04:18:13 +00:00
|
|
|
if (global.stage.key_focus != null)
|
2010-07-02 19:36:56 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-03-13 18:20:37 +00:00
|
|
|
this._sync();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-03-13 18:20:37 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_findTargetApp() {
|
2018-01-03 07:55:38 +00:00
|
|
|
let workspaceManager = global.workspace_manager;
|
|
|
|
let workspace = workspaceManager.get_active_workspace();
|
2012-03-13 18:20:37 +00:00
|
|
|
let tracker = Shell.WindowTracker.get_default();
|
|
|
|
let focusedApp = tracker.focus_app;
|
2013-08-13 11:41:44 +00:00
|
|
|
if (focusedApp && focusedApp.is_on_workspace(workspace))
|
|
|
|
return focusedApp;
|
|
|
|
|
2012-03-13 18:20:37 +00:00
|
|
|
for (let i = 0; i < this._startingApps.length; i++)
|
|
|
|
if (this._startingApps[i].is_on_workspace(workspace))
|
2013-08-13 11:41:44 +00:00
|
|
|
return this._startingApps[i];
|
2010-07-02 19:36:56 +00:00
|
|
|
|
2013-08-13 11:41:44 +00:00
|
|
|
return null;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-03-08 17:46:43 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_sync() {
|
2013-08-13 11:41:44 +00:00
|
|
|
let targetApp = this._findTargetApp();
|
2011-11-16 00:12:58 +00:00
|
|
|
|
2013-08-13 11:41:44 +00:00
|
|
|
if (this._targetApp != targetApp) {
|
2014-09-16 10:08:19 +00:00
|
|
|
if (this._busyNotifyId) {
|
|
|
|
this._targetApp.disconnect(this._busyNotifyId);
|
|
|
|
this._busyNotifyId = 0;
|
|
|
|
}
|
2011-03-08 17:46:43 +00:00
|
|
|
|
2013-08-13 11:41:44 +00:00
|
|
|
this._targetApp = targetApp;
|
2011-03-08 17:46:43 +00:00
|
|
|
|
2013-08-13 11:41:44 +00:00
|
|
|
if (this._targetApp) {
|
2017-12-02 00:27:35 +00:00
|
|
|
this._busyNotifyId = this._targetApp.connect('notify::busy', this._sync.bind(this));
|
2015-02-18 20:39:33 +00:00
|
|
|
this._label.set_text(this._targetApp.get_name());
|
2019-04-09 23:17:51 +00:00
|
|
|
this.set_accessible_name(this._targetApp.get_name());
|
2011-05-15 16:55:23 +00:00
|
|
|
}
|
2011-03-08 17:46:43 +00:00
|
|
|
}
|
|
|
|
|
2018-10-04 14:52:34 +00:00
|
|
|
let visible = (this._targetApp != null && !Main.overview.visibleTarget);
|
2013-08-13 11:41:44 +00:00
|
|
|
if (visible)
|
2018-08-21 09:48:19 +00:00
|
|
|
this.fadeIn();
|
2013-08-13 11:41:44 +00:00
|
|
|
else
|
2018-08-21 09:48:19 +00:00
|
|
|
this.fadeOut();
|
2010-06-10 12:07:33 +00:00
|
|
|
|
2013-08-13 11:41:44 +00:00
|
|
|
let isBusy = (this._targetApp != null &&
|
|
|
|
(this._targetApp.get_state() == Shell.AppState.STARTING ||
|
2014-09-16 10:08:19 +00:00
|
|
|
this._targetApp.get_busy()));
|
2013-08-13 11:41:44 +00:00
|
|
|
if (isBusy)
|
2011-03-08 17:46:43 +00:00
|
|
|
this.startAnimation();
|
2011-05-15 16:55:23 +00:00
|
|
|
else
|
2013-08-13 11:41:44 +00:00
|
|
|
this.stopAnimation();
|
2009-08-11 15:32:58 +00:00
|
|
|
|
2019-04-09 23:17:51 +00:00
|
|
|
this.reactive = (visible && !isBusy);
|
2013-08-13 11:41:44 +00:00
|
|
|
|
|
|
|
this._syncIcon();
|
2018-10-04 14:52:34 +00:00
|
|
|
this.menu.setApp(this._targetApp);
|
2009-08-11 15:32:58 +00:00
|
|
|
this.emit('changed');
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-05-15 16:55:23 +00:00
|
|
|
|
2018-07-06 08:48:15 +00:00
|
|
|
_onDestroy() {
|
2013-04-21 23:49:14 +00:00
|
|
|
if (this._appStateChangedSignalId > 0) {
|
|
|
|
let appSys = Shell.AppSystem.get_default();
|
|
|
|
appSys.disconnect(this._appStateChangedSignalId);
|
|
|
|
this._appStateChangedSignalId = 0;
|
|
|
|
}
|
|
|
|
if (this._focusAppNotifyId > 0) {
|
|
|
|
let tracker = Shell.WindowTracker.get_default();
|
|
|
|
tracker.disconnect(this._focusAppNotifyId);
|
|
|
|
this._focusAppNotifyId = 0;
|
|
|
|
}
|
|
|
|
if (this._overviewHidingId > 0) {
|
|
|
|
Main.overview.disconnect(this._overviewHidingId);
|
|
|
|
this._overviewHidingId = 0;
|
|
|
|
}
|
|
|
|
if (this._overviewShowingId > 0) {
|
|
|
|
Main.overview.disconnect(this._overviewShowingId);
|
|
|
|
this._overviewShowingId = 0;
|
|
|
|
}
|
|
|
|
if (this._switchWorkspaceNotifyId > 0) {
|
|
|
|
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
|
|
|
|
this._switchWorkspaceNotifyId = 0;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:23:39 +00:00
|
|
|
super._onDestroy();
|
2009-08-11 15:32:58 +00:00
|
|
|
}
|
2011-11-20 14:38:48 +00:00
|
|
|
});
|
2009-08-11 15:32:58 +00:00
|
|
|
|
2017-10-31 01:23:39 +00:00
|
|
|
var ActivitiesButton = GObject.registerClass(
|
|
|
|
class ActivitiesButton extends PanelMenu.Button {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
2017-10-31 01:23:39 +00:00
|
|
|
super._init(0.0, null, true);
|
2019-04-09 23:17:51 +00:00
|
|
|
this.accessible_role = Atk.Role.TOGGLE_BUTTON;
|
2011-07-14 12:56:14 +00:00
|
|
|
|
2019-04-09 23:17:51 +00:00
|
|
|
this.name = 'panelActivities';
|
2011-07-14 12:35:55 +00:00
|
|
|
|
2011-07-14 12:53:44 +00:00
|
|
|
/* Translators: If there is no suitable word for "Activities"
|
|
|
|
in your language, you can use the word for "Overview". */
|
2013-08-03 12:30:46 +00:00
|
|
|
this._label = new St.Label({ text: _("Activities"),
|
|
|
|
y_align: Clutter.ActorAlign.CENTER });
|
2019-04-09 23:17:51 +00:00
|
|
|
this.add_actor(this._label);
|
2011-07-14 12:35:55 +00:00
|
|
|
|
2019-04-09 23:17:51 +00:00
|
|
|
this.label_actor = this._label;
|
2012-02-17 17:16:53 +00:00
|
|
|
|
2019-04-09 23:17:51 +00:00
|
|
|
this.connect('captured-event', this._onCapturedEvent.bind(this));
|
|
|
|
this.connect_after('key-release-event', this._onKeyRelease.bind(this));
|
2011-07-14 12:53:44 +00:00
|
|
|
|
2017-10-31 00:38:18 +00:00
|
|
|
Main.overview.connect('showing', () => {
|
2019-04-09 23:17:51 +00:00
|
|
|
this.add_style_pseudo_class('overview');
|
|
|
|
this.add_accessible_state (Atk.StateType.CHECKED);
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
|
|
|
Main.overview.connect('hiding', () => {
|
2019-04-09 23:17:51 +00:00
|
|
|
this.remove_style_pseudo_class('overview');
|
|
|
|
this.remove_accessible_state (Atk.StateType.CHECKED);
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
2011-07-14 12:53:44 +00:00
|
|
|
|
|
|
|
this._xdndTimeOut = 0;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-07-14 12:53:44 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
handleDragOver(source, actor, x, y, time) {
|
2011-07-14 12:53:44 +00:00
|
|
|
if (source != Main.xdndHandler)
|
2012-02-11 10:14:43 +00:00
|
|
|
return DND.DragMotionResult.CONTINUE;
|
2011-07-14 12:53:44 +00:00
|
|
|
|
|
|
|
if (this._xdndTimeOut != 0)
|
|
|
|
Mainloop.source_remove(this._xdndTimeOut);
|
2017-12-02 00:27:35 +00:00
|
|
|
this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT, () => {
|
|
|
|
this._xdndToggleOverview(actor);
|
|
|
|
});
|
2014-04-10 17:26:52 +00:00
|
|
|
GLib.Source.set_name_by_id(this._xdndTimeOut, '[gnome-shell] this._xdndToggleOverview');
|
2012-02-11 10:14:43 +00:00
|
|
|
|
|
|
|
return DND.DragMotionResult.CONTINUE;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-07-14 12:53:44 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onCapturedEvent(actor, event) {
|
2014-07-22 10:32:39 +00:00
|
|
|
if (event.type() == Clutter.EventType.BUTTON_PRESS ||
|
|
|
|
event.type() == Clutter.EventType.TOUCH_BEGIN) {
|
2013-03-01 21:00:37 +00:00
|
|
|
if (!Main.overview.shouldToggleByCornerOrButton())
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_STOP;
|
2011-07-14 12:56:14 +00:00
|
|
|
}
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-07-14 12:56:14 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onEvent(actor, event) {
|
2017-10-31 01:23:39 +00:00
|
|
|
super._onEvent(actor, event);
|
2014-07-22 10:32:39 +00:00
|
|
|
|
2014-07-31 15:26:47 +00:00
|
|
|
if (event.type() == Clutter.EventType.TOUCH_END ||
|
|
|
|
event.type() == Clutter.EventType.BUTTON_RELEASE)
|
2015-10-22 16:12:28 +00:00
|
|
|
if (Main.overview.shouldToggleByCornerOrButton())
|
|
|
|
Main.overview.toggle();
|
2014-07-31 15:26:47 +00:00
|
|
|
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-07-14 12:56:14 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onKeyRelease(actor, event) {
|
2011-07-14 12:56:14 +00:00
|
|
|
let symbol = event.get_key_symbol();
|
|
|
|
if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) {
|
2015-10-22 16:12:28 +00:00
|
|
|
if (Main.overview.shouldToggleByCornerOrButton())
|
|
|
|
Main.overview.toggle();
|
2011-07-14 12:56:14 +00:00
|
|
|
}
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-07-14 12:56:14 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_xdndToggleOverview(actor) {
|
2011-07-14 12:53:44 +00:00
|
|
|
let [x, y, mask] = global.get_pointer();
|
|
|
|
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
|
|
|
|
2019-04-09 23:17:51 +00:00
|
|
|
if (pickedActor == this && Main.overview.shouldToggleByCornerOrButton())
|
2013-03-04 22:02:02 +00:00
|
|
|
Main.overview.toggle();
|
2011-07-14 12:53:44 +00:00
|
|
|
|
|
|
|
Mainloop.source_remove(this._xdndTimeOut);
|
|
|
|
this._xdndTimeOut = 0;
|
2013-11-29 00:45:39 +00:00
|
|
|
return GLib.SOURCE_REMOVE;
|
2011-07-14 12:53:44 +00:00
|
|
|
}
|
2011-11-20 17:56:27 +00:00
|
|
|
});
|
2011-02-09 02:12:10 +00:00
|
|
|
|
2017-10-31 01:19:44 +00:00
|
|
|
var PanelCorner = class {
|
|
|
|
constructor(side) {
|
2011-02-09 02:12:10 +00:00
|
|
|
this._side = side;
|
2011-08-28 20:07:25 +00:00
|
|
|
|
2011-02-09 02:12:10 +00:00
|
|
|
this.actor = new St.DrawingArea({ style_class: 'panel-corner' });
|
2017-12-02 00:27:35 +00:00
|
|
|
this.actor.connect('style-changed', this._styleChanged.bind(this));
|
|
|
|
this.actor.connect('repaint', this._repaint.bind(this));
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-02-09 02:12:10 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_findRightmostButton(container) {
|
2011-08-28 20:07:25 +00:00
|
|
|
if (!container.get_children)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
let children = container.get_children();
|
|
|
|
|
|
|
|
if (!children || children.length == 0)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
// Start at the back and work backward
|
2012-07-17 17:27:43 +00:00
|
|
|
let index;
|
|
|
|
for (index = children.length - 1; index >= 0; index--) {
|
|
|
|
if (children[index].visible)
|
|
|
|
break;
|
|
|
|
}
|
2011-08-28 20:07:25 +00:00
|
|
|
if (index < 0)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
if (!(children[index].has_style_class_name('panel-menu')) &&
|
|
|
|
!(children[index].has_style_class_name('panel-button')))
|
|
|
|
return this._findRightmostButton(children[index]);
|
|
|
|
|
|
|
|
return children[index];
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-08-28 20:07:25 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_findLeftmostButton(container) {
|
2011-08-28 20:07:25 +00:00
|
|
|
if (!container.get_children)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
let children = container.get_children();
|
|
|
|
|
|
|
|
if (!children || children.length == 0)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
// Start at the front and work forward
|
2012-07-17 17:27:43 +00:00
|
|
|
let index;
|
|
|
|
for (index = 0; index < children.length; index++) {
|
|
|
|
if (children[index].visible)
|
|
|
|
break;
|
|
|
|
}
|
2011-08-28 20:07:25 +00:00
|
|
|
if (index == children.length)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
if (!(children[index].has_style_class_name('panel-menu')) &&
|
|
|
|
!(children[index].has_style_class_name('panel-button')))
|
|
|
|
return this._findLeftmostButton(children[index]);
|
|
|
|
|
|
|
|
return children[index];
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-08-28 20:07:25 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
setStyleParent(box) {
|
2011-09-10 01:41:39 +00:00
|
|
|
let side = this._side;
|
|
|
|
|
2012-12-13 21:35:00 +00:00
|
|
|
let rtlAwareContainer = box instanceof St.BoxLayout;
|
2011-09-10 01:41:39 +00:00
|
|
|
if (rtlAwareContainer &&
|
2012-12-13 21:35:00 +00:00
|
|
|
box.get_text_direction() == Clutter.TextDirection.RTL) {
|
2011-09-10 01:41:39 +00:00
|
|
|
if (this._side == St.Side.LEFT)
|
|
|
|
side = St.Side.RIGHT;
|
|
|
|
else if (this._side == St.Side.RIGHT)
|
|
|
|
side = St.Side.LEFT;
|
|
|
|
}
|
2011-08-28 20:07:25 +00:00
|
|
|
|
2011-09-10 01:41:39 +00:00
|
|
|
let button;
|
|
|
|
if (side == St.Side.LEFT)
|
2012-12-13 21:35:00 +00:00
|
|
|
button = this._findLeftmostButton(box);
|
2011-09-10 01:41:39 +00:00
|
|
|
else if (side == St.Side.RIGHT)
|
2012-12-13 21:35:00 +00:00
|
|
|
button = this._findRightmostButton(box);
|
2011-08-28 20:07:25 +00:00
|
|
|
|
|
|
|
if (button) {
|
2011-09-07 16:23:43 +00:00
|
|
|
if (this._button && this._buttonStyleChangedSignalId) {
|
2011-08-28 20:07:25 +00:00
|
|
|
this._button.disconnect(this._buttonStyleChangedSignalId);
|
2011-09-07 16:23:43 +00:00
|
|
|
this._button.style = null;
|
|
|
|
}
|
2011-08-28 20:07:25 +00:00
|
|
|
|
|
|
|
this._button = button;
|
|
|
|
|
2017-10-31 00:38:18 +00:00
|
|
|
button.connect('destroy', () => {
|
|
|
|
if (this._button == button) {
|
|
|
|
this._button = null;
|
|
|
|
this._buttonStyleChangedSignalId = 0;
|
|
|
|
}
|
|
|
|
});
|
2011-08-28 20:07:25 +00:00
|
|
|
|
|
|
|
// Synchronize the locate button's pseudo classes with this corner
|
2017-10-31 00:38:18 +00:00
|
|
|
this._buttonStyleChangedSignalId = button.connect('style-changed',
|
|
|
|
actor => {
|
2011-08-28 20:07:25 +00:00
|
|
|
let pseudoClass = button.get_style_pseudo_class();
|
|
|
|
this.actor.set_style_pseudo_class(pseudoClass);
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
2011-09-07 16:23:43 +00:00
|
|
|
|
|
|
|
// The corner doesn't support theme transitions, so override
|
|
|
|
// the .panel-button default
|
2013-01-12 00:29:10 +00:00
|
|
|
button.style = 'transition-duration: 0ms';
|
2011-08-28 20:07:25 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-08-28 20:07:25 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_repaint() {
|
2011-02-09 02:12:10 +00:00
|
|
|
let node = this.actor.get_theme_node();
|
|
|
|
|
|
|
|
let cornerRadius = node.get_length("-panel-corner-radius");
|
2012-02-08 13:31:42 +00:00
|
|
|
let borderWidth = node.get_length('-panel-corner-border-width');
|
2011-02-09 02:12:10 +00:00
|
|
|
|
|
|
|
let backgroundColor = node.get_color('-panel-corner-background-color');
|
2012-02-08 13:31:42 +00:00
|
|
|
let borderColor = node.get_color('-panel-corner-border-color');
|
2011-02-09 02:12:10 +00:00
|
|
|
|
2013-01-07 20:07:40 +00:00
|
|
|
let overlap = borderColor.alpha != 0;
|
|
|
|
let offsetY = overlap ? 0 : borderWidth;
|
2012-09-21 20:10:07 +00:00
|
|
|
|
2011-02-09 02:12:10 +00:00
|
|
|
let cr = this.actor.get_context();
|
|
|
|
cr.setOperator(Cairo.Operator.SOURCE);
|
|
|
|
|
2012-09-21 20:10:07 +00:00
|
|
|
cr.moveTo(0, offsetY);
|
2011-02-09 02:12:10 +00:00
|
|
|
if (this._side == St.Side.LEFT)
|
|
|
|
cr.arc(cornerRadius,
|
2012-02-08 13:31:42 +00:00
|
|
|
borderWidth + cornerRadius,
|
2011-02-09 02:12:10 +00:00
|
|
|
cornerRadius, Math.PI, 3 * Math.PI / 2);
|
|
|
|
else
|
|
|
|
cr.arc(0,
|
2012-02-08 13:31:42 +00:00
|
|
|
borderWidth + cornerRadius,
|
2011-02-09 02:12:10 +00:00
|
|
|
cornerRadius, 3 * Math.PI / 2, 2 * Math.PI);
|
2012-09-21 20:10:07 +00:00
|
|
|
cr.lineTo(cornerRadius, offsetY);
|
2011-02-09 02:12:10 +00:00
|
|
|
cr.closePath();
|
|
|
|
|
|
|
|
let savedPath = cr.copyPath();
|
|
|
|
|
|
|
|
let xOffsetDirection = this._side == St.Side.LEFT ? -1 : 1;
|
2012-02-08 13:31:42 +00:00
|
|
|
let over = _over(borderColor, backgroundColor);
|
2011-02-09 02:12:10 +00:00
|
|
|
Clutter.cairo_set_source_color(cr, over);
|
|
|
|
cr.fill();
|
|
|
|
|
2013-01-07 20:07:40 +00:00
|
|
|
if (overlap) {
|
|
|
|
let offset = borderWidth;
|
|
|
|
Clutter.cairo_set_source_color(cr, backgroundColor);
|
2012-09-21 20:10:07 +00:00
|
|
|
|
2013-01-07 20:07:40 +00:00
|
|
|
cr.save();
|
|
|
|
cr.translate(xOffsetDirection * offset, - offset);
|
|
|
|
cr.appendPath(savedPath);
|
|
|
|
cr.fill();
|
|
|
|
cr.restore();
|
|
|
|
}
|
2011-02-09 02:12:10 +00:00
|
|
|
|
2013-01-07 20:07:40 +00:00
|
|
|
cr.$dispose();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-02-09 02:12:10 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_styleChanged() {
|
2011-02-09 02:12:10 +00:00
|
|
|
let node = this.actor.get_theme_node();
|
|
|
|
|
|
|
|
let cornerRadius = node.get_length("-panel-corner-radius");
|
2012-02-08 13:31:42 +00:00
|
|
|
let borderWidth = node.get_length('-panel-corner-border-width');
|
2011-02-09 02:12:10 +00:00
|
|
|
|
2012-02-08 13:31:42 +00:00
|
|
|
this.actor.set_size(cornerRadius, borderWidth + cornerRadius);
|
|
|
|
this.actor.set_anchor_point(0, borderWidth);
|
2011-02-09 02:12:10 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
};
|
2011-02-09 02:12:10 +00:00
|
|
|
|
2017-10-31 01:23:39 +00:00
|
|
|
var AggregateLayout = GObject.registerClass(
|
|
|
|
class AggregateLayout extends Clutter.BoxLayout {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init(params) {
|
2015-10-04 01:07:32 +00:00
|
|
|
if (!params)
|
|
|
|
params = {};
|
|
|
|
params['orientation'] = Clutter.Orientation.VERTICAL;
|
2017-10-31 01:23:39 +00:00
|
|
|
super._init(params);
|
2015-10-04 01:07:32 +00:00
|
|
|
|
|
|
|
this._sizeChildren = [];
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2015-10-04 01:07:32 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
addSizeChild(actor) {
|
2015-10-04 01:07:32 +00:00
|
|
|
this._sizeChildren.push(actor);
|
|
|
|
this.layout_changed();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2015-10-04 01:07:32 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_get_preferred_width(container, forHeight) {
|
2015-10-04 01:07:32 +00:00
|
|
|
let themeNode = container.get_theme_node();
|
|
|
|
let minWidth = themeNode.get_min_width();
|
|
|
|
let natWidth = minWidth;
|
|
|
|
|
|
|
|
for (let i = 0; i < this._sizeChildren.length; i++) {
|
|
|
|
let child = this._sizeChildren[i];
|
|
|
|
let [childMin, childNat] = child.get_preferred_width(forHeight);
|
|
|
|
minWidth = Math.max(minWidth, childMin);
|
2019-02-25 22:31:45 +00:00
|
|
|
natWidth = Math.max(natWidth, childNat);
|
2015-10-04 01:07:32 +00:00
|
|
|
}
|
|
|
|
return [minWidth, natWidth];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2017-10-31 01:23:39 +00:00
|
|
|
var AggregateMenu = GObject.registerClass(
|
|
|
|
class AggregateMenu extends PanelMenu.Button {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
2017-10-31 01:23:39 +00:00
|
|
|
super._init(0.0, C_("System menu in the top bar", "System"), false);
|
2013-07-01 18:19:12 +00:00
|
|
|
this.menu.actor.add_style_class_name('aggregate-menu');
|
2013-06-06 21:27:32 +00:00
|
|
|
|
2015-10-04 01:07:32 +00:00
|
|
|
let menuLayout = new AggregateLayout();
|
|
|
|
this.menu.box.set_layout_manager(menuLayout);
|
|
|
|
|
2013-06-06 21:27:32 +00:00
|
|
|
this._indicators = new St.BoxLayout({ style_class: 'panel-status-indicators-box' });
|
2019-04-09 23:17:51 +00:00
|
|
|
this.add_child(this._indicators);
|
2013-06-06 21:27:32 +00:00
|
|
|
|
2014-02-11 22:20:15 +00:00
|
|
|
if (Config.HAVE_NETWORKMANAGER) {
|
|
|
|
this._network = new imports.ui.status.network.NMApplet();
|
|
|
|
} else {
|
|
|
|
this._network = null;
|
|
|
|
}
|
2013-09-03 23:22:46 +00:00
|
|
|
if (Config.HAVE_BLUETOOTH) {
|
|
|
|
this._bluetooth = new imports.ui.status.bluetooth.Indicator();
|
|
|
|
} else {
|
|
|
|
this._bluetooth = null;
|
|
|
|
}
|
|
|
|
|
2018-07-20 14:50:50 +00:00
|
|
|
this._remoteAccess = new imports.ui.status.remoteAccess.RemoteAccessApplet();
|
2013-06-06 21:27:32 +00:00
|
|
|
this._power = new imports.ui.status.power.Indicator();
|
2013-05-27 21:54:50 +00:00
|
|
|
this._rfkill = new imports.ui.status.rfkill.Indicator();
|
2013-06-06 21:27:32 +00:00
|
|
|
this._volume = new imports.ui.status.volume.Indicator();
|
2013-04-23 23:26:05 +00:00
|
|
|
this._brightness = new imports.ui.status.brightness.Indicator();
|
2013-06-06 21:27:32 +00:00
|
|
|
this._system = new imports.ui.status.system.Indicator();
|
2013-07-17 19:26:06 +00:00
|
|
|
this._screencast = new imports.ui.status.screencast.Indicator();
|
2014-01-28 17:41:26 +00:00
|
|
|
this._location = new imports.ui.status.location.Indicator();
|
2017-02-10 13:14:14 +00:00
|
|
|
this._nightLight = new imports.ui.status.nightLight.Indicator();
|
2017-12-19 12:41:14 +00:00
|
|
|
this._thunderbolt = new imports.ui.status.thunderbolt.Indicator();
|
2013-06-06 21:27:32 +00:00
|
|
|
|
2017-12-19 12:41:14 +00:00
|
|
|
this._indicators.add_child(this._thunderbolt.indicators);
|
2013-07-17 19:26:06 +00:00
|
|
|
this._indicators.add_child(this._screencast.indicators);
|
2014-01-28 17:41:26 +00:00
|
|
|
this._indicators.add_child(this._location.indicators);
|
2017-02-10 13:14:14 +00:00
|
|
|
this._indicators.add_child(this._nightLight.indicators);
|
2014-02-11 22:20:15 +00:00
|
|
|
if (this._network) {
|
|
|
|
this._indicators.add_child(this._network.indicators);
|
|
|
|
}
|
2013-09-03 23:22:46 +00:00
|
|
|
if (this._bluetooth) {
|
|
|
|
this._indicators.add_child(this._bluetooth.indicators);
|
|
|
|
}
|
2018-07-20 14:50:50 +00:00
|
|
|
this._indicators.add_child(this._remoteAccess.indicators);
|
2013-05-27 21:54:50 +00:00
|
|
|
this._indicators.add_child(this._rfkill.indicators);
|
2013-06-06 21:27:32 +00:00
|
|
|
this._indicators.add_child(this._volume.indicators);
|
2013-06-17 22:19:20 +00:00
|
|
|
this._indicators.add_child(this._power.indicators);
|
2014-02-18 12:45:26 +00:00
|
|
|
this._indicators.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
|
2013-06-06 21:27:32 +00:00
|
|
|
|
|
|
|
this.menu.addMenuItem(this._volume.menu);
|
2013-04-23 23:26:05 +00:00
|
|
|
this.menu.addMenuItem(this._brightness.menu);
|
2013-06-06 21:27:32 +00:00
|
|
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
2014-02-11 22:20:15 +00:00
|
|
|
if (this._network) {
|
|
|
|
this.menu.addMenuItem(this._network.menu);
|
|
|
|
}
|
2013-09-03 23:22:46 +00:00
|
|
|
if (this._bluetooth) {
|
|
|
|
this.menu.addMenuItem(this._bluetooth.menu);
|
|
|
|
}
|
2018-07-20 14:50:50 +00:00
|
|
|
this.menu.addMenuItem(this._remoteAccess.menu);
|
2014-02-13 17:50:32 +00:00
|
|
|
this.menu.addMenuItem(this._location.menu);
|
2013-05-27 21:54:50 +00:00
|
|
|
this.menu.addMenuItem(this._rfkill.menu);
|
2013-06-06 21:27:32 +00:00
|
|
|
this.menu.addMenuItem(this._power.menu);
|
2017-02-10 13:14:14 +00:00
|
|
|
this.menu.addMenuItem(this._nightLight.menu);
|
2013-06-06 21:27:32 +00:00
|
|
|
this.menu.addMenuItem(this._system.menu);
|
2015-10-04 01:07:32 +00:00
|
|
|
|
|
|
|
menuLayout.addSizeChild(this._location.menu.actor);
|
|
|
|
menuLayout.addSizeChild(this._rfkill.menu.actor);
|
|
|
|
menuLayout.addSizeChild(this._power.menu.actor);
|
2019-03-20 12:48:21 +00:00
|
|
|
menuLayout.addSizeChild(this._system.buttonGroup);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2013-06-06 21:27:32 +00:00
|
|
|
});
|
|
|
|
|
2012-08-28 21:10:44 +00:00
|
|
|
const PANEL_ITEM_IMPLEMENTATIONS = {
|
|
|
|
'activities': ActivitiesButton,
|
2013-06-06 21:27:32 +00:00
|
|
|
'aggregateMenu': AggregateMenu,
|
2012-08-28 21:10:44 +00:00
|
|
|
'appMenu': AppMenuButton,
|
|
|
|
'dateMenu': imports.ui.dateMenu.DateMenuButton,
|
|
|
|
'a11y': imports.ui.status.accessibility.ATIndicator,
|
|
|
|
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
2019-03-20 16:46:12 +00:00
|
|
|
'dwellClick': imports.ui.status.dwellClick.DwellClickIndicator,
|
2012-08-28 21:10:44 +00:00
|
|
|
};
|
|
|
|
|
2017-10-31 01:23:39 +00:00
|
|
|
var Panel = GObject.registerClass(
|
|
|
|
class Panel extends St.Widget {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
2017-10-31 01:23:39 +00:00
|
|
|
super._init({ name: 'panel',
|
2018-06-27 19:02:15 +00:00
|
|
|
reactive: true });
|
|
|
|
|
|
|
|
this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
|
2009-11-10 17:13:58 +00:00
|
|
|
|
2012-09-21 20:19:27 +00:00
|
|
|
this._sessionStyle = null;
|
|
|
|
|
2012-08-26 14:05:46 +00:00
|
|
|
this.statusArea = {};
|
2011-04-06 13:26:15 +00:00
|
|
|
|
2015-02-23 19:07:04 +00:00
|
|
|
this.menuManager = new PopupMenu.PopupMenuManager(this);
|
2010-05-20 15:18:46 +00:00
|
|
|
|
2009-11-17 22:46:20 +00:00
|
|
|
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
|
2018-06-27 19:02:15 +00:00
|
|
|
this.add_child(this._leftBox);
|
2009-11-17 22:46:20 +00:00
|
|
|
this._centerBox = new St.BoxLayout({ name: 'panelCenter' });
|
2018-06-27 19:02:15 +00:00
|
|
|
this.add_child(this._centerBox);
|
2009-11-17 22:46:20 +00:00
|
|
|
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
|
2018-06-27 19:02:15 +00:00
|
|
|
this.add_child(this._rightBox);
|
2009-08-11 15:16:25 +00:00
|
|
|
|
2012-12-13 21:35:00 +00:00
|
|
|
this._leftCorner = new PanelCorner(St.Side.LEFT);
|
2018-06-27 19:02:15 +00:00
|
|
|
this.add_child(this._leftCorner.actor);
|
2011-08-28 20:07:25 +00:00
|
|
|
|
2012-12-13 21:35:00 +00:00
|
|
|
this._rightCorner = new PanelCorner(St.Side.RIGHT);
|
2018-06-27 19:02:15 +00:00
|
|
|
this.add_child(this._rightCorner.actor);
|
2010-05-25 14:21:22 +00:00
|
|
|
|
2018-06-27 19:02:15 +00:00
|
|
|
this.connect('button-press-event', this._onButtonPress.bind(this));
|
|
|
|
this.connect('touch-event', this._onButtonPress.bind(this));
|
|
|
|
this.connect('key-press-event', this._onKeyPress.bind(this));
|
2009-08-11 15:16:25 +00:00
|
|
|
|
2017-10-31 00:38:18 +00:00
|
|
|
Main.overview.connect('showing', () => {
|
2018-06-27 19:02:15 +00:00
|
|
|
this.add_style_pseudo_class('overview');
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
|
|
|
Main.overview.connect('hiding', () => {
|
2018-06-27 19:02:15 +00:00
|
|
|
this.remove_style_pseudo_class('overview');
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
2013-02-05 14:24:46 +00:00
|
|
|
|
2018-06-27 19:02:15 +00:00
|
|
|
Main.layoutManager.panelBox.add(this);
|
|
|
|
Main.ctrlAltTabManager.addGroup(this, _("Top Bar"), 'focus-top-bar-symbolic',
|
2011-02-07 16:29:34 +00:00
|
|
|
{ sortGroup: CtrlAltTab.SortGroup.TOP });
|
2012-09-01 12:42:53 +00:00
|
|
|
|
2017-12-02 00:27:35 +00:00
|
|
|
Main.sessionMode.connect('updated', this._updatePanel.bind(this));
|
2016-09-23 19:08:11 +00:00
|
|
|
|
2018-06-27 19:02:15 +00:00
|
|
|
global.display.connect('workareas-changed', () => { this.queue_relayout(); });
|
2012-09-01 12:42:53 +00:00
|
|
|
this._updatePanel();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2008-12-01 19:51:43 +00:00
|
|
|
|
2019-01-31 21:07:38 +00:00
|
|
|
vfunc_get_preferred_width(forHeight) {
|
2017-04-12 06:46:54 +00:00
|
|
|
let primaryMonitor = Main.layoutManager.primaryMonitor;
|
|
|
|
|
|
|
|
if (primaryMonitor)
|
2018-06-27 19:02:15 +00:00
|
|
|
return [0, primaryMonitor.width];
|
2011-07-21 14:49:04 +00:00
|
|
|
|
2018-06-27 19:02:15 +00:00
|
|
|
return [0, 0];
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-07-21 14:49:04 +00:00
|
|
|
|
2018-06-27 19:02:15 +00:00
|
|
|
vfunc_allocate(box, flags) {
|
2019-04-29 17:53:57 +00:00
|
|
|
this.set_allocation(box, flags);
|
2018-06-27 19:02:15 +00:00
|
|
|
|
2011-07-21 14:49:04 +00:00
|
|
|
let allocWidth = box.x2 - box.x1;
|
|
|
|
let allocHeight = box.y2 - box.y1;
|
|
|
|
|
|
|
|
let [leftMinWidth, leftNaturalWidth] = this._leftBox.get_preferred_width(-1);
|
|
|
|
let [centerMinWidth, centerNaturalWidth] = this._centerBox.get_preferred_width(-1);
|
|
|
|
let [rightMinWidth, rightNaturalWidth] = this._rightBox.get_preferred_width(-1);
|
|
|
|
|
|
|
|
let sideWidth, centerWidth;
|
|
|
|
centerWidth = centerNaturalWidth;
|
2018-01-09 08:39:06 +00:00
|
|
|
|
|
|
|
// get workspace area and center date entry relative to it
|
2018-06-27 19:02:15 +00:00
|
|
|
let monitor = Main.layoutManager.findMonitorForActor(this);
|
2018-01-09 08:39:06 +00:00
|
|
|
let centerOffset = 0;
|
|
|
|
if (monitor) {
|
|
|
|
let workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index);
|
|
|
|
centerOffset = 2 * (workArea.x - monitor.x) + workArea.width - monitor.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
sideWidth = Math.max(0, (allocWidth - centerWidth + centerOffset) / 2);
|
2011-07-21 14:49:04 +00:00
|
|
|
|
|
|
|
let childBox = new Clutter.ActorBox();
|
|
|
|
|
|
|
|
childBox.y1 = 0;
|
|
|
|
childBox.y2 = allocHeight;
|
2018-06-27 19:02:15 +00:00
|
|
|
if (this.get_text_direction() == Clutter.TextDirection.RTL) {
|
2017-04-12 06:46:54 +00:00
|
|
|
childBox.x1 = Math.max(allocWidth - Math.min(Math.floor(sideWidth),
|
|
|
|
leftNaturalWidth),
|
|
|
|
0);
|
2011-07-21 14:49:04 +00:00
|
|
|
childBox.x2 = allocWidth;
|
|
|
|
} else {
|
|
|
|
childBox.x1 = 0;
|
|
|
|
childBox.x2 = Math.min(Math.floor(sideWidth),
|
|
|
|
leftNaturalWidth);
|
|
|
|
}
|
|
|
|
this._leftBox.allocate(childBox, flags);
|
|
|
|
|
|
|
|
childBox.x1 = Math.ceil(sideWidth);
|
|
|
|
childBox.y1 = 0;
|
|
|
|
childBox.x2 = childBox.x1 + centerWidth;
|
|
|
|
childBox.y2 = allocHeight;
|
|
|
|
this._centerBox.allocate(childBox, flags);
|
|
|
|
|
|
|
|
childBox.y1 = 0;
|
|
|
|
childBox.y2 = allocHeight;
|
2018-06-27 19:02:15 +00:00
|
|
|
if (this.get_text_direction() == Clutter.TextDirection.RTL) {
|
2011-07-21 14:49:04 +00:00
|
|
|
childBox.x1 = 0;
|
|
|
|
childBox.x2 = Math.min(Math.floor(sideWidth),
|
|
|
|
rightNaturalWidth);
|
|
|
|
} else {
|
2017-04-12 06:46:54 +00:00
|
|
|
childBox.x1 = Math.max(allocWidth - Math.min(Math.floor(sideWidth),
|
|
|
|
rightNaturalWidth),
|
|
|
|
0);
|
2011-07-21 14:49:04 +00:00
|
|
|
childBox.x2 = allocWidth;
|
|
|
|
}
|
|
|
|
this._rightBox.allocate(childBox, flags);
|
|
|
|
|
2012-10-12 17:51:48 +00:00
|
|
|
let cornerMinWidth, cornerMinHeight;
|
|
|
|
let cornerWidth, cornerHeight;
|
|
|
|
|
|
|
|
[cornerMinWidth, cornerWidth] = this._leftCorner.actor.get_preferred_width(-1);
|
|
|
|
[cornerMinHeight, cornerHeight] = this._leftCorner.actor.get_preferred_height(-1);
|
2011-07-21 14:49:04 +00:00
|
|
|
childBox.x1 = 0;
|
|
|
|
childBox.x2 = cornerWidth;
|
|
|
|
childBox.y1 = allocHeight;
|
|
|
|
childBox.y2 = allocHeight + cornerHeight;
|
|
|
|
this._leftCorner.actor.allocate(childBox, flags);
|
|
|
|
|
2012-10-12 17:51:48 +00:00
|
|
|
[cornerMinWidth, cornerWidth] = this._rightCorner.actor.get_preferred_width(-1);
|
|
|
|
[cornerMinHeight, cornerHeight] = this._rightCorner.actor.get_preferred_height(-1);
|
2011-07-21 14:49:04 +00:00
|
|
|
childBox.x1 = allocWidth - cornerWidth;
|
|
|
|
childBox.x2 = allocWidth;
|
|
|
|
childBox.y1 = allocHeight;
|
|
|
|
childBox.y2 = allocHeight + cornerHeight;
|
|
|
|
this._rightCorner.actor.allocate(childBox, flags);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-07-21 14:49:04 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onButtonPress(actor, event) {
|
2013-02-20 01:27:11 +00:00
|
|
|
if (Main.modalCount > 0)
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2013-02-20 01:27:11 +00:00
|
|
|
|
2011-10-04 15:14:29 +00:00
|
|
|
if (event.get_source() != actor)
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2011-10-04 15:14:29 +00:00
|
|
|
|
2018-05-24 15:28:36 +00:00
|
|
|
let type = event.type();
|
|
|
|
let isPress = type == Clutter.EventType.BUTTON_PRESS;
|
|
|
|
if (!isPress && type != Clutter.EventType.TOUCH_BEGIN)
|
|
|
|
return Clutter.EVENT_PROPAGATE;
|
|
|
|
|
|
|
|
let button = isPress ? event.get_button() : -1;
|
|
|
|
if (isPress && button != 1)
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2011-10-04 15:14:29 +00:00
|
|
|
|
|
|
|
let [stageX, stageY] = event.get_coords();
|
|
|
|
|
2018-02-05 18:46:22 +00:00
|
|
|
let dragWindow = this._getDraggableWindowForPosition(stageX);
|
2011-10-04 15:14:29 +00:00
|
|
|
|
2018-02-05 18:46:22 +00:00
|
|
|
if (!dragWindow)
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2011-10-04 15:14:29 +00:00
|
|
|
|
2018-01-03 07:55:38 +00:00
|
|
|
global.display.begin_grab_op(dragWindow,
|
2011-10-04 15:14:29 +00:00
|
|
|
Meta.GrabOp.MOVING,
|
|
|
|
false, /* pointer grab */
|
|
|
|
true, /* frame action */
|
|
|
|
button,
|
|
|
|
event.get_state(),
|
|
|
|
event.get_time(),
|
|
|
|
stageX, stageY);
|
|
|
|
|
2013-11-29 18:17:34 +00:00
|
|
|
return Clutter.EVENT_STOP;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-10-04 15:14:29 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onKeyPress(actor, event) {
|
2017-11-01 18:43:11 +00:00
|
|
|
let symbol = event.get_key_symbol();
|
|
|
|
if (symbol == Clutter.KEY_Escape) {
|
2018-01-03 07:55:38 +00:00
|
|
|
global.display.focus_default_window(event.get_time());
|
2017-11-01 18:43:11 +00:00
|
|
|
return Clutter.EVENT_STOP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-11-01 18:43:11 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_toggleMenu(indicator) {
|
2019-01-23 22:55:12 +00:00
|
|
|
if (!indicator || !indicator.container.visible)
|
|
|
|
return; // menu not supported by current session mode
|
2012-08-28 21:10:44 +00:00
|
|
|
|
|
|
|
let menu = indicator.menu;
|
2019-04-09 23:17:51 +00:00
|
|
|
if (!indicator.reactive)
|
2012-05-18 14:04:47 +00:00
|
|
|
return;
|
2012-03-27 13:26:20 +00:00
|
|
|
|
2013-04-26 14:14:55 +00:00
|
|
|
menu.toggle();
|
|
|
|
if (menu.isOpen)
|
2018-11-27 12:58:25 +00:00
|
|
|
menu.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-03-27 13:26:20 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
toggleAppMenu() {
|
2015-02-18 01:52:07 +00:00
|
|
|
this._toggleMenu(this.statusArea.appMenu);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2015-02-18 01:52:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
toggleCalendar() {
|
2015-02-18 01:52:07 +00:00
|
|
|
this._toggleMenu(this.statusArea.dateMenu);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2015-02-18 01:52:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
closeCalendar() {
|
2015-02-13 09:44:13 +00:00
|
|
|
let indicator = this.statusArea.dateMenu;
|
|
|
|
if (!indicator) // calendar not supported by current session mode
|
|
|
|
return;
|
|
|
|
|
|
|
|
let menu = indicator.menu;
|
2019-04-09 23:17:51 +00:00
|
|
|
if (!indicator.reactive)
|
2015-02-13 09:44:13 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
menu.close();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2015-02-13 09:44:13 +00:00
|
|
|
|
2012-09-01 12:42:53 +00:00
|
|
|
set boxOpacity(value) {
|
|
|
|
let isReactive = value > 0;
|
|
|
|
|
|
|
|
this._leftBox.opacity = value;
|
|
|
|
this._leftBox.reactive = isReactive;
|
|
|
|
this._centerBox.opacity = value;
|
|
|
|
this._centerBox.reactive = isReactive;
|
|
|
|
this._rightBox.opacity = value;
|
|
|
|
this._rightBox.reactive = isReactive;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-09-01 12:42:53 +00:00
|
|
|
|
|
|
|
get boxOpacity() {
|
|
|
|
return this._leftBox.opacity;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-09-01 12:42:53 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_updatePanel() {
|
2012-08-28 21:10:44 +00:00
|
|
|
let panel = Main.sessionMode.panel;
|
2012-09-01 12:42:53 +00:00
|
|
|
this._hideIndicators();
|
|
|
|
this._updateBox(panel.left, this._leftBox);
|
|
|
|
this._updateBox(panel.center, this._centerBox);
|
|
|
|
this._updateBox(panel.right, this._rightBox);
|
2012-09-21 20:19:27 +00:00
|
|
|
|
2018-07-14 20:56:22 +00:00
|
|
|
if (panel.left.includes('dateMenu'))
|
2015-04-23 10:43:03 +00:00
|
|
|
Main.messageTray.bannerAlignment = Clutter.ActorAlign.START;
|
2018-07-14 20:56:22 +00:00
|
|
|
else if (panel.right.includes('dateMenu'))
|
2015-04-23 10:43:03 +00:00
|
|
|
Main.messageTray.bannerAlignment = Clutter.ActorAlign.END;
|
|
|
|
// Default to center if there is no dateMenu
|
|
|
|
else
|
|
|
|
Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER;
|
|
|
|
|
2012-09-21 20:19:27 +00:00
|
|
|
if (this._sessionStyle)
|
|
|
|
this._removeStyleClassName(this._sessionStyle);
|
|
|
|
|
|
|
|
this._sessionStyle = Main.sessionMode.panelStyle;
|
|
|
|
if (this._sessionStyle)
|
|
|
|
this._addStyleClassName(this._sessionStyle);
|
2012-12-13 21:35:00 +00:00
|
|
|
|
2018-06-27 19:02:15 +00:00
|
|
|
if (this.get_text_direction() == Clutter.TextDirection.RTL) {
|
2012-12-13 21:35:00 +00:00
|
|
|
this._leftCorner.setStyleParent(this._rightBox);
|
|
|
|
this._rightCorner.setStyleParent(this._leftBox);
|
|
|
|
} else {
|
|
|
|
this._leftCorner.setStyleParent(this._leftBox);
|
|
|
|
this._rightCorner.setStyleParent(this._rightBox);
|
|
|
|
}
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-08-28 21:10:44 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_hideIndicators() {
|
2012-09-01 12:42:53 +00:00
|
|
|
for (let role in PANEL_ITEM_IMPLEMENTATIONS) {
|
|
|
|
let indicator = this.statusArea[role];
|
|
|
|
if (!indicator)
|
|
|
|
continue;
|
2012-09-04 16:27:50 +00:00
|
|
|
indicator.container.hide();
|
2012-09-01 12:42:53 +00:00
|
|
|
}
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-09-01 12:42:53 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_ensureIndicator(role) {
|
2012-09-01 12:42:53 +00:00
|
|
|
let indicator = this.statusArea[role];
|
|
|
|
if (!indicator) {
|
|
|
|
let constructor = PANEL_ITEM_IMPLEMENTATIONS[role];
|
|
|
|
if (!constructor) {
|
|
|
|
// This icon is not implemented (this is a bug)
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
indicator = new constructor(this);
|
|
|
|
this.statusArea[role] = indicator;
|
|
|
|
}
|
|
|
|
return indicator;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-09-01 12:42:53 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_updateBox(elements, box) {
|
2012-09-01 12:42:53 +00:00
|
|
|
let nChildren = box.get_n_children();
|
|
|
|
|
|
|
|
for (let i = 0; i < elements.length; i++) {
|
|
|
|
let role = elements[i];
|
|
|
|
let indicator = this._ensureIndicator(role);
|
|
|
|
if (indicator == null)
|
|
|
|
continue;
|
2011-04-06 13:26:15 +00:00
|
|
|
|
2012-09-01 12:42:53 +00:00
|
|
|
this._addToPanelBox(role, indicator, i + nChildren, box);
|
2010-07-24 11:57:53 +00:00
|
|
|
}
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-07-24 11:57:53 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_addToPanelBox(role, indicator, position, box) {
|
2012-09-04 16:27:50 +00:00
|
|
|
let container = indicator.container;
|
2012-09-01 12:42:53 +00:00
|
|
|
container.show();
|
|
|
|
|
|
|
|
let parent = container.get_parent();
|
2012-09-04 16:27:50 +00:00
|
|
|
if (parent)
|
2012-09-01 12:42:53 +00:00
|
|
|
parent.remove_actor(container);
|
|
|
|
|
2015-04-23 16:43:58 +00:00
|
|
|
|
2012-09-01 12:42:53 +00:00
|
|
|
box.insert_child_at_index(container, position);
|
2012-08-28 21:10:44 +00:00
|
|
|
if (indicator.menu)
|
|
|
|
this.menuManager.addMenu(indicator.menu);
|
|
|
|
this.statusArea[role] = indicator;
|
2017-10-31 00:38:18 +00:00
|
|
|
let destroyId = indicator.connect('destroy', emitter => {
|
2012-08-28 21:10:44 +00:00
|
|
|
delete this.statusArea[role];
|
|
|
|
emitter.disconnect(destroyId);
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
2017-12-02 00:27:35 +00:00
|
|
|
indicator.connect('menu-set', this._onMenuSet.bind(this));
|
2015-04-28 09:05:58 +00:00
|
|
|
this._onMenuSet(indicator);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-08-25 15:46:25 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
addToStatusArea(role, indicator, position, box) {
|
2012-08-26 14:05:46 +00:00
|
|
|
if (this.statusArea[role])
|
2011-08-22 21:19:13 +00:00
|
|
|
throw new Error('Extension point conflict: there is already a status indicator for role ' + role);
|
|
|
|
|
|
|
|
if (!(indicator instanceof PanelMenu.Button))
|
|
|
|
throw new TypeError('Status indicator must be an instance of PanelMenu.Button');
|
|
|
|
|
2012-08-28 21:10:44 +00:00
|
|
|
position = position || 0;
|
|
|
|
let boxes = {
|
|
|
|
left: this._leftBox,
|
|
|
|
center: this._centerBox,
|
|
|
|
right: this._rightBox
|
|
|
|
};
|
|
|
|
let boxContainer = boxes[box] || this._rightBox;
|
2012-09-01 12:42:53 +00:00
|
|
|
this.statusArea[role] = indicator;
|
2012-08-28 21:10:44 +00:00
|
|
|
this._addToPanelBox(role, indicator, position, boxContainer);
|
2011-08-22 21:19:13 +00:00
|
|
|
return indicator;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-09-21 20:19:27 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_addStyleClassName(className) {
|
2018-06-27 19:02:15 +00:00
|
|
|
this.add_style_class_name(className);
|
2012-09-21 20:19:27 +00:00
|
|
|
this._rightCorner.actor.add_style_class_name(className);
|
|
|
|
this._leftCorner.actor.add_style_class_name(className);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-09-21 20:19:27 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_removeStyleClassName(className) {
|
2018-06-27 19:02:15 +00:00
|
|
|
this.remove_style_class_name(className);
|
2012-09-21 20:19:27 +00:00
|
|
|
this._rightCorner.actor.remove_style_class_name(className);
|
|
|
|
this._leftCorner.actor.remove_style_class_name(className);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2015-04-28 09:05:58 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onMenuSet(indicator) {
|
2017-06-13 02:46:37 +00:00
|
|
|
if (!indicator.menu || indicator.menu.hasOwnProperty('_openChangedId'))
|
2015-04-28 09:05:58 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
indicator.menu._openChangedId = indicator.menu.connect('open-state-changed',
|
2017-10-31 00:38:18 +00:00
|
|
|
(menu, isOpen) => {
|
2015-04-28 09:05:58 +00:00
|
|
|
let boxAlignment;
|
|
|
|
if (this._leftBox.contains(indicator.container))
|
|
|
|
boxAlignment = Clutter.ActorAlign.START;
|
|
|
|
else if (this._centerBox.contains(indicator.container))
|
|
|
|
boxAlignment = Clutter.ActorAlign.CENTER;
|
|
|
|
else if (this._rightBox.contains(indicator.container))
|
|
|
|
boxAlignment = Clutter.ActorAlign.END;
|
|
|
|
|
|
|
|
if (boxAlignment == Main.messageTray.bannerAlignment)
|
|
|
|
Main.messageTray.bannerBlocked = isOpen;
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
2012-09-01 12:42:53 +00:00
|
|
|
}
|
2018-02-05 18:46:22 +00:00
|
|
|
|
|
|
|
_getDraggableWindowForPosition(stageX) {
|
|
|
|
let workspaceManager = global.workspace_manager;
|
|
|
|
let workspace = workspaceManager.get_active_workspace()
|
|
|
|
let allWindowsByStacking = global.display.sort_windows_by_stacking(
|
|
|
|
workspace.list_windows()
|
|
|
|
).reverse();
|
|
|
|
|
|
|
|
return allWindowsByStacking.find(metaWindow => {
|
|
|
|
let rect = metaWindow.get_frame_rect();
|
|
|
|
return metaWindow.is_on_primary_monitor() &&
|
|
|
|
metaWindow.showing_on_its_workspace() &&
|
|
|
|
metaWindow.get_window_type() != Meta.WindowType.DESKTOP &&
|
|
|
|
metaWindow.maximized_vertically &&
|
|
|
|
stageX > rect.x && stageX < rect.x + rect.width
|
|
|
|
});
|
|
|
|
}
|
2011-11-20 17:56:27 +00:00
|
|
|
});
|