2011-09-28 09:16:26 -04:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2023-07-10 05:53:00 -04:00
|
|
|
|
|
|
|
import Clutter from 'gi://Clutter';
|
|
|
|
import Cogl from 'gi://Cogl';
|
|
|
|
import Gio from 'gi://Gio';
|
|
|
|
import GLib from 'gi://GLib';
|
|
|
|
import GObject from 'gi://GObject';
|
|
|
|
import Graphene from 'gi://Graphene';
|
|
|
|
import Meta from 'gi://Meta';
|
|
|
|
import Pango from 'gi://Pango';
|
|
|
|
import Shell from 'gi://Shell';
|
|
|
|
import St from 'gi://St';
|
|
|
|
import * as Signals from '../misc/signals.js';
|
|
|
|
import System from 'system';
|
|
|
|
|
|
|
|
import * as History from '../misc/history.js';
|
|
|
|
import {ExtensionState} from '../misc/extensionUtils.js';
|
|
|
|
import * as PopupMenu from './popupMenu.js';
|
|
|
|
import * as ShellEntry from './shellEntry.js';
|
|
|
|
import * as Main from './main.js';
|
|
|
|
import * as JsParse from '../misc/jsParse.js';
|
2019-07-06 09:31:57 -04:00
|
|
|
|
2012-07-14 18:24:10 -04:00
|
|
|
const CHEVRON = '>>> ';
|
|
|
|
|
2009-09-10 01:38:13 -04:00
|
|
|
/* Imports...feel free to add here as needed */
|
2023-07-12 15:32:56 -04:00
|
|
|
const commandHeader = `
|
|
|
|
const {Clutter, Gio, GLib, GObject, Meta, Shell, St} = imports.gi;
|
2023-07-10 05:53:00 -04:00
|
|
|
const Main = await import('resource:///org/gnome/shell/ui/main.js');
|
2023-07-12 15:32:56 -04:00
|
|
|
|
|
|
|
/* Utility functions...we should probably be able to use these
|
|
|
|
* in the shell core code too. */
|
|
|
|
const stage = global.stage;
|
|
|
|
|
|
|
|
/* Special lookingGlass functions */
|
|
|
|
const inspect = Main.lookingGlass.inspect.bind(Main.lookingGlass);
|
|
|
|
const it = Main.lookingGlass.getIt();
|
|
|
|
const r = Main.lookingGlass.getResult.bind(Main.lookingGlass);
|
|
|
|
`;
|
2023-07-12 15:40:05 -04:00
|
|
|
const AsyncFunction = async function () {}.constructor;
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2011-02-13 11:43:32 -05:00
|
|
|
const HISTORY_KEY = 'looking-glass-history';
|
2011-10-29 04:20:49 -04:00
|
|
|
// Time between tabs for them to count as a double-tab event
|
2023-07-10 05:53:00 -04:00
|
|
|
|
|
|
|
const AUTO_COMPLETE_DOUBLE_TAB_DELAY = 500;
|
|
|
|
const AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION = 200;
|
|
|
|
const AUTO_COMPLETE_GLOBAL_KEYWORDS = _getAutoCompleteGlobalKeywords();
|
2011-10-29 04:20:49 -04:00
|
|
|
|
2018-07-20 15:46:19 -04:00
|
|
|
const LG_ANIMATION_TIME = 500;
|
|
|
|
|
2021-09-29 14:09:19 -04:00
|
|
|
const CLUTTER_DEBUG_FLAG_CATEGORIES = new Map([
|
|
|
|
// Paint debugging can easily result in a non-responsive session
|
2023-08-06 18:40:20 -04:00
|
|
|
['DebugFlag', {argPos: 0, exclude: ['PAINT']}],
|
|
|
|
['DrawDebugFlag', {argPos: 1, exclude: []}],
|
2021-09-29 14:09:19 -04:00
|
|
|
// Exluded due to the only current option likely to result in shooting ones
|
|
|
|
// foot
|
|
|
|
// ['PickDebugFlag', { argPos: 2, exclude: [] }],
|
|
|
|
]);
|
|
|
|
|
2011-10-29 04:20:49 -04:00
|
|
|
function _getAutoCompleteGlobalKeywords() {
|
|
|
|
const keywords = ['true', 'false', 'null', 'new'];
|
2020-04-23 19:06:36 -04:00
|
|
|
// Don't add the private properties of globalThis (i.e., ones starting with '_')
|
|
|
|
const windowProperties = Object.getOwnPropertyNames(globalThis).filter(
|
2020-04-03 19:52:29 -04:00
|
|
|
a => a.charAt(0) !== '_');
|
2011-10-29 04:20:49 -04:00
|
|
|
const headerProperties = JsParse.getDeclaredConstants(commandHeader);
|
|
|
|
|
|
|
|
return keywords.concat(windowProperties).concat(headerProperties);
|
|
|
|
}
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
class AutoComplete extends Signals.EventEmitter {
|
2017-10-30 21:19:44 -04:00
|
|
|
constructor(entry) {
|
2022-07-04 18:30:44 -04:00
|
|
|
super();
|
|
|
|
|
2011-10-29 04:20:49 -04:00
|
|
|
this._entry = entry;
|
2017-12-01 19:27:35 -05:00
|
|
|
this._entry.connect('key-press-event', this._entryKeyPressEvent.bind(this));
|
2011-10-29 04:20:49 -04:00
|
|
|
this._lastTabTime = global.get_current_time();
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-10-29 04:20:49 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_processCompletionRequest(event) {
|
2023-08-06 20:51:19 -04:00
|
|
|
if (event.completions.length === 0)
|
2011-10-29 04:20:49 -04:00
|
|
|
return;
|
2019-08-19 20:51:42 -04:00
|
|
|
|
2011-10-29 04:20:49 -04:00
|
|
|
// Unique match = go ahead and complete; multiple matches + single tab = complete the common starting string;
|
|
|
|
// multiple matches + double tab = emit a suggest event with all possible options
|
2023-08-06 20:51:19 -04:00
|
|
|
if (event.completions.length === 1) {
|
2011-10-29 04:20:49 -04:00
|
|
|
this.additionalCompletionText(event.completions[0], event.attrHead);
|
2023-08-06 18:40:20 -04:00
|
|
|
this.emit('completion', {completion: event.completions[0], type: 'whole-word'});
|
2011-10-29 04:20:49 -04:00
|
|
|
} else if (event.completions.length > 1 && event.tabType === 'single') {
|
|
|
|
let commonPrefix = JsParse.getCommonPrefix(event.completions);
|
|
|
|
|
|
|
|
if (commonPrefix.length > 0) {
|
|
|
|
this.additionalCompletionText(commonPrefix, event.attrHead);
|
2023-08-06 18:40:20 -04:00
|
|
|
this.emit('completion', {completion: commonPrefix, type: 'prefix'});
|
|
|
|
this.emit('suggest', {completions: event.completions});
|
2011-10-29 04:20:49 -04:00
|
|
|
}
|
|
|
|
} else if (event.completions.length > 1 && event.tabType === 'double') {
|
2023-08-06 18:40:20 -04:00
|
|
|
this.emit('suggest', {completions: event.completions});
|
2011-10-29 04:20:49 -04:00
|
|
|
}
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-10-29 04:20:49 -04:00
|
|
|
|
2023-07-12 19:52:06 -04:00
|
|
|
async _handleCompletions(text, time) {
|
|
|
|
const [completions, attrHead] =
|
|
|
|
await JsParse.getCompletions(text, commandHeader, AUTO_COMPLETE_GLOBAL_KEYWORDS);
|
|
|
|
|
|
|
|
const tabType = (time - this._lastTabTime) < AUTO_COMPLETE_DOUBLE_TAB_DELAY
|
|
|
|
? 'double' : 'single';
|
|
|
|
|
|
|
|
this._processCompletionRequest({
|
|
|
|
tabType,
|
|
|
|
completions,
|
|
|
|
attrHead,
|
|
|
|
});
|
|
|
|
this._lastTabTime = time;
|
|
|
|
}
|
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_entryKeyPressEvent(actor, event) {
|
2011-10-29 04:20:49 -04:00
|
|
|
let cursorPos = this._entry.clutter_text.get_cursor_position();
|
|
|
|
let text = this._entry.get_text();
|
2023-08-06 20:51:19 -04:00
|
|
|
if (cursorPos !== -1)
|
2011-10-29 04:20:49 -04:00
|
|
|
text = text.slice(0, cursorPos);
|
2019-08-19 20:51:42 -04:00
|
|
|
|
2023-07-12 19:52:06 -04:00
|
|
|
if (event.get_key_symbol() === Clutter.KEY_Tab)
|
|
|
|
this._handleCompletions(text, event.get_time()).catch(logError);
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-10-29 04:20:49 -04:00
|
|
|
|
|
|
|
// Insert characters of text not already included in head at cursor position. i.e., if text="abc" and head="a",
|
|
|
|
// the string "bc" will be appended to this._entry
|
2017-10-30 20:03:21 -04:00
|
|
|
additionalCompletionText(text, head) {
|
2011-10-29 04:20:49 -04:00
|
|
|
let additionalCompletionText = text.slice(head.length);
|
|
|
|
let cursorPos = this._entry.clutter_text.get_cursor_position();
|
|
|
|
|
|
|
|
this._entry.clutter_text.insert_text(additionalCompletionText, cursorPos);
|
|
|
|
}
|
2023-07-10 05:53:00 -04:00
|
|
|
}
|
2011-02-13 11:43:32 -05:00
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const Notebook = GObject.registerClass({
|
2023-08-06 18:40:20 -04:00
|
|
|
Signals: {'selection': {param_types: [Clutter.Actor.$gtype]}},
|
2019-07-16 05:24:13 -04:00
|
|
|
}, class Notebook extends St.BoxLayout {
|
|
|
|
_init() {
|
2019-10-21 14:44:00 -04:00
|
|
|
super._init({
|
|
|
|
vertical: true,
|
|
|
|
y_expand: true,
|
|
|
|
});
|
2009-08-04 09:49:03 -04:00
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
this.tabControls = new St.BoxLayout({style_class: 'labels'});
|
2009-08-04 09:49:03 -04:00
|
|
|
|
|
|
|
this._selectedIndex = -1;
|
|
|
|
this._tabs = [];
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-04 09:49:03 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
appendPage(name, child) {
|
2020-03-29 17:51:13 -04:00
|
|
|
const labelBox = new St.BoxLayout({
|
|
|
|
style_class: 'notebook-tab',
|
|
|
|
reactive: true,
|
|
|
|
track_hover: true,
|
|
|
|
});
|
2023-08-06 18:40:20 -04:00
|
|
|
let label = new St.Button({label: name});
|
2017-10-30 20:38:18 -04:00
|
|
|
label.connect('clicked', () => {
|
2009-08-04 09:49:03 -04:00
|
|
|
this.selectChild(child);
|
|
|
|
return true;
|
2017-10-30 20:38:18 -04:00
|
|
|
});
|
2019-10-21 14:44:00 -04:00
|
|
|
labelBox.add_child(label);
|
2009-10-27 13:27:00 -04:00
|
|
|
this.tabControls.add(labelBox);
|
2009-09-10 01:38:13 -04:00
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
let scrollview = new St.ScrollView({y_expand: true});
|
2009-09-10 01:38:13 -04:00
|
|
|
scrollview.get_hscroll_bar().hide();
|
|
|
|
scrollview.add_actor(child);
|
|
|
|
|
2020-03-29 17:51:13 -04:00
|
|
|
const tabData = {
|
|
|
|
child,
|
|
|
|
labelBox,
|
|
|
|
label,
|
|
|
|
scrollView: scrollview,
|
|
|
|
_scrollToBottom: false,
|
|
|
|
};
|
2009-10-08 20:11:45 -04:00
|
|
|
this._tabs.push(tabData);
|
2009-09-10 01:38:13 -04:00
|
|
|
scrollview.hide();
|
2019-10-21 14:44:00 -04:00
|
|
|
this.add_child(scrollview);
|
2009-09-10 01:38:13 -04:00
|
|
|
|
2009-10-08 20:11:45 -04:00
|
|
|
let vAdjust = scrollview.vscroll.adjustment;
|
2019-01-27 19:42:00 -05:00
|
|
|
vAdjust.connect('changed', () => this._onAdjustScopeChanged(tabData));
|
|
|
|
vAdjust.connect('notify::value', () => this._onAdjustValueChanged(tabData));
|
2009-10-08 20:11:45 -04:00
|
|
|
|
2023-08-06 20:51:19 -04:00
|
|
|
if (this._selectedIndex === -1)
|
2009-08-04 09:49:03 -04:00
|
|
|
this.selectIndex(0);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-04 09:49:03 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_unselect() {
|
2009-08-04 09:49:03 -04:00
|
|
|
if (this._selectedIndex < 0)
|
|
|
|
return;
|
2009-10-08 20:11:45 -04:00
|
|
|
let tabData = this._tabs[this._selectedIndex];
|
2010-03-19 11:37:04 -04:00
|
|
|
tabData.labelBox.remove_style_pseudo_class('selected');
|
2009-10-08 20:11:45 -04:00
|
|
|
tabData.scrollView.hide();
|
2009-08-04 09:49:03 -04:00
|
|
|
this._selectedIndex = -1;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-04 09:49:03 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
selectIndex(index) {
|
2023-08-06 20:51:19 -04:00
|
|
|
if (index === this._selectedIndex)
|
2009-08-04 09:49:03 -04:00
|
|
|
return;
|
|
|
|
if (index < 0) {
|
2011-04-20 12:41:22 -04:00
|
|
|
this._unselect();
|
2009-08-04 09:49:03 -04:00
|
|
|
this.emit('selection', null);
|
|
|
|
return;
|
|
|
|
}
|
2011-04-20 12:41:22 -04:00
|
|
|
|
|
|
|
// Focus the new tab before unmapping the old one
|
2009-10-08 20:11:45 -04:00
|
|
|
let tabData = this._tabs[index];
|
2018-11-27 07:58:25 -05:00
|
|
|
if (!tabData.scrollView.navigate_focus(null, St.DirectionType.TAB_FORWARD, false))
|
2019-07-16 05:24:13 -04:00
|
|
|
this.grab_key_focus();
|
2011-04-20 12:41:22 -04:00
|
|
|
|
|
|
|
this._unselect();
|
|
|
|
|
2010-03-19 11:37:04 -04:00
|
|
|
tabData.labelBox.add_style_pseudo_class('selected');
|
2009-10-08 20:11:45 -04:00
|
|
|
tabData.scrollView.show();
|
2009-08-04 09:49:03 -04:00
|
|
|
this._selectedIndex = index;
|
2009-10-08 20:11:45 -04:00
|
|
|
this.emit('selection', tabData.child);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-04 09:49:03 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
selectChild(child) {
|
2019-01-29 16:02:57 -05:00
|
|
|
if (child == null) {
|
2009-08-04 09:49:03 -04:00
|
|
|
this.selectIndex(-1);
|
2019-01-29 16:02:57 -05:00
|
|
|
} else {
|
2009-08-04 09:49:03 -04:00
|
|
|
for (let i = 0; i < this._tabs.length; i++) {
|
2009-10-08 20:11:45 -04:00
|
|
|
let tabData = this._tabs[i];
|
2023-08-06 20:51:19 -04:00
|
|
|
if (tabData.child === child) {
|
2009-08-04 09:49:03 -04:00
|
|
|
this.selectIndex(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-10-08 20:11:45 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
scrollToBottom(index) {
|
2009-10-08 20:11:45 -04:00
|
|
|
let tabData = this._tabs[index];
|
|
|
|
tabData._scrollToBottom = true;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-10-08 20:11:45 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_onAdjustValueChanged(tabData) {
|
2009-10-08 20:11:45 -04:00
|
|
|
let vAdjust = tabData.scrollView.vscroll.adjustment;
|
|
|
|
if (vAdjust.value < (vAdjust.upper - vAdjust.lower - 0.5))
|
|
|
|
tabData._scrolltoBottom = false;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-10-08 20:11:45 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_onAdjustScopeChanged(tabData) {
|
2009-10-08 20:11:45 -04:00
|
|
|
if (!tabData._scrollToBottom)
|
|
|
|
return;
|
|
|
|
let vAdjust = tabData.scrollView.vscroll.adjustment;
|
|
|
|
vAdjust.value = vAdjust.upper - vAdjust.page_size;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-10-21 01:23:08 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
nextTab() {
|
2011-10-21 01:23:08 -04:00
|
|
|
let nextIndex = this._selectedIndex;
|
2019-08-19 20:51:42 -04:00
|
|
|
if (nextIndex < this._tabs.length - 1)
|
2011-10-21 01:23:08 -04:00
|
|
|
++nextIndex;
|
|
|
|
|
|
|
|
this.selectIndex(nextIndex);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-10-21 01:23:08 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
prevTab() {
|
2011-10-21 01:23:08 -04:00
|
|
|
let prevIndex = this._selectedIndex;
|
2019-08-19 20:51:42 -04:00
|
|
|
if (prevIndex > 0)
|
2011-10-21 01:23:08 -04:00
|
|
|
--prevIndex;
|
|
|
|
|
|
|
|
this.selectIndex(prevIndex);
|
2009-08-04 09:49:03 -04:00
|
|
|
}
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|
2009-08-04 09:49:03 -04:00
|
|
|
|
2010-05-15 12:43:56 -04:00
|
|
|
function objectToString(o) {
|
2023-08-06 20:51:19 -04:00
|
|
|
if (typeof o === typeof objectToString) {
|
2010-05-15 12:43:56 -04:00
|
|
|
// special case this since the default is way, way too verbose
|
2011-09-30 17:30:47 -04:00
|
|
|
return '<js function>';
|
2023-07-12 18:25:43 -04:00
|
|
|
} else if (o && o.toString === undefined) {
|
|
|
|
// eeks, something unprintable. we'll have to guess, probably a module
|
|
|
|
return typeof o === 'object' && !(o instanceof Object)
|
|
|
|
? '<module>'
|
|
|
|
: '<unknown>';
|
2010-05-15 12:43:56 -04:00
|
|
|
} else {
|
2022-02-07 09:14:06 -05:00
|
|
|
return `${o}`;
|
2010-05-15 12:43:56 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const ObjLink = GObject.registerClass(
|
2019-07-16 05:24:13 -04:00
|
|
|
class ObjLink extends St.Button {
|
|
|
|
_init(lookingGlass, o, title) {
|
2010-05-15 12:43:56 -04:00
|
|
|
let text;
|
|
|
|
if (title)
|
|
|
|
text = title;
|
|
|
|
else
|
|
|
|
text = objectToString(o);
|
|
|
|
text = GLib.markup_escape_text(text, -1);
|
2011-11-20 11:07:14 -05:00
|
|
|
|
2019-07-16 05:24:13 -04:00
|
|
|
super._init({
|
|
|
|
reactive: true,
|
|
|
|
track_hover: true,
|
|
|
|
style_class: 'shell-link',
|
2019-10-17 17:40:24 -04:00
|
|
|
label: text,
|
2019-10-17 17:27:27 -04:00
|
|
|
x_align: Clutter.ActorAlign.START,
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|
|
|
|
this.get_child().single_line_mode = true;
|
2012-07-14 19:29:55 -04:00
|
|
|
|
2019-07-16 05:24:13 -04:00
|
|
|
this._obj = o;
|
2012-07-14 19:29:55 -04:00
|
|
|
this._lookingGlass = lookingGlass;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2010-05-15 12:43:56 -04:00
|
|
|
|
2019-09-10 01:42:48 -04:00
|
|
|
vfunc_clicked() {
|
2019-07-16 05:24:13 -04:00
|
|
|
this._lookingGlass.inspectObject(this._obj, this);
|
2010-05-15 12:43:56 -04:00
|
|
|
}
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const Result = GObject.registerClass(
|
2019-10-28 14:35:33 -04:00
|
|
|
class Result extends St.BoxLayout {
|
2019-07-16 05:24:13 -04:00
|
|
|
_init(lookingGlass, command, o, index) {
|
2023-08-06 18:40:20 -04:00
|
|
|
super._init({vertical: true});
|
2009-08-02 03:46:01 -04:00
|
|
|
|
|
|
|
this.index = index;
|
|
|
|
this.o = o;
|
|
|
|
|
2012-07-14 19:29:55 -04:00
|
|
|
this._lookingGlass = lookingGlass;
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
let cmdTxt = new St.Label({text: command});
|
2010-05-15 12:43:56 -04:00
|
|
|
cmdTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
2019-07-16 05:24:13 -04:00
|
|
|
this.add(cmdTxt);
|
2010-05-15 12:43:56 -04:00
|
|
|
let box = new St.BoxLayout({});
|
2019-07-16 05:24:13 -04:00
|
|
|
this.add(box);
|
2023-08-06 18:40:20 -04:00
|
|
|
let resultTxt = new St.Label({text: `r(${index}) = `});
|
2010-05-15 12:43:56 -04:00
|
|
|
resultTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
|
|
|
box.add(resultTxt);
|
2012-07-14 19:29:55 -04:00
|
|
|
let objLink = new ObjLink(this._lookingGlass, o);
|
2019-07-16 05:24:13 -04:00
|
|
|
box.add(objLink);
|
2009-08-02 03:46:01 -04:00
|
|
|
}
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const WindowList = GObject.registerClass({
|
2019-07-16 05:24:13 -04:00
|
|
|
}, class WindowList extends St.BoxLayout {
|
|
|
|
_init(lookingGlass) {
|
2023-08-06 18:40:20 -04:00
|
|
|
super._init({name: 'Windows', vertical: true, style: 'spacing: 8px'});
|
2010-04-20 14:57:31 -04:00
|
|
|
let tracker = Shell.WindowTracker.get_default();
|
2019-07-16 05:24:13 -04:00
|
|
|
this._updateId = Main.initializeDeferredWork(this, this._updateWindowList.bind(this));
|
2017-12-01 19:27:35 -05:00
|
|
|
global.display.connect('window-created', this._updateWindowList.bind(this));
|
|
|
|
tracker.connect('tracked-windows-changed', this._updateWindowList.bind(this));
|
2012-07-14 19:29:55 -04:00
|
|
|
|
|
|
|
this._lookingGlass = lookingGlass;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_updateWindowList() {
|
2019-09-12 14:45:04 -04:00
|
|
|
if (!this._lookingGlass.isOpen)
|
|
|
|
return;
|
|
|
|
|
2019-07-16 05:24:13 -04:00
|
|
|
this.destroy_all_children();
|
2010-10-19 14:55:43 -04:00
|
|
|
let windows = global.get_window_actors();
|
2010-04-20 14:57:31 -04:00
|
|
|
let tracker = Shell.WindowTracker.get_default();
|
|
|
|
for (let i = 0; i < windows.length; i++) {
|
|
|
|
let metaWindow = windows[i].metaWindow;
|
2010-05-30 16:48:41 -04:00
|
|
|
// Avoid multiple connections
|
|
|
|
if (!metaWindow._lookingGlassManaged) {
|
2017-12-01 19:27:35 -05:00
|
|
|
metaWindow.connect('unmanaged', this._updateWindowList.bind(this));
|
2010-05-30 16:48:41 -04:00
|
|
|
metaWindow._lookingGlassManaged = true;
|
|
|
|
}
|
2023-08-06 18:40:20 -04:00
|
|
|
let box = new St.BoxLayout({vertical: true});
|
2019-07-16 05:24:13 -04:00
|
|
|
this.add(box);
|
2012-07-14 19:29:55 -04:00
|
|
|
let windowLink = new ObjLink(this._lookingGlass, metaWindow, metaWindow.title);
|
2019-10-21 14:44:00 -04:00
|
|
|
box.add_child(windowLink);
|
2023-08-06 18:40:20 -04:00
|
|
|
let propsBox = new St.BoxLayout({vertical: true, style: 'padding-left: 6px;'});
|
2010-04-20 14:57:31 -04:00
|
|
|
box.add(propsBox);
|
2023-08-06 18:40:20 -04:00
|
|
|
propsBox.add(new St.Label({text: `wmclass: ${metaWindow.get_wm_class()}`}));
|
2010-04-20 14:57:31 -04:00
|
|
|
let app = tracker.get_window_app(metaWindow);
|
Kill off ShellAppInfo, move into ShellApp
This dramatically thins down and sanitizes the application code.
The ShellAppSystem changes in a number of ways:
* Preferences are special cased more explicitly; they aren't apps,
they're shortcuts for an app), and we don't have many of them, so
don't need e.g. the optimizations in ShellAppSystem for searching.
* get_app() changes to lookup_app() and returns null if an app isn't
found. The semantics where it tried to find the .desktop file
if we didn't know about it were just broken; I am pretty sure no
caller needs this, and if they do we'll fix them.
* ShellAppSystem maintains two indexes on apps (by desktop file id
and by GMenuTreeEntry), but is no longer in the business of
dealing with GMenuTree as far as hierarchy and categories go. That
is moved up into js/ui/appDisplay.js. Actually, it flattens both
apps and settings.
Also, ShellWindowTracker is now the sole reference-owner for
window-backed apps. We still do the weird "window:0x1234beef" id
for these apps, but a reference is not stored in ShellAppSystem.
The js/ui/appDisplay.js code is rewritten, and sucks a lot less.
Variable names are clearer:
_apps -> _appIcons
_filterApp -> _visibleApps
_filters -> _categoryBox
Similarly for function names. We no longer call (for every app) a
recursive lookup in GMenuTree to see if it's in a particular section
on every category switch; it's all cached.
NOTE - this intentionally reverts the incremental loading code from
commit 7813c5b93f6bcde8c4beae286e82bfc472b2b656. It's fast enough
here without that.
https://bugzilla.gnome.org/show_bug.cgi?id=648149
2011-04-21 13:35:01 -04:00
|
|
|
if (app != null && !app.is_window_backed()) {
|
2010-04-20 14:57:31 -04:00
|
|
|
let icon = app.create_icon_texture(22);
|
2023-08-06 18:40:20 -04:00
|
|
|
let propBox = new St.BoxLayout({style: 'spacing: 6px; '});
|
2010-04-20 14:57:31 -04:00
|
|
|
propsBox.add(propBox);
|
2023-08-06 18:40:20 -04:00
|
|
|
propBox.add_child(new St.Label({text: 'app: '}));
|
2012-07-14 19:29:55 -04:00
|
|
|
let appLink = new ObjLink(this._lookingGlass, app, app.get_id());
|
2019-10-21 14:44:00 -04:00
|
|
|
propBox.add_child(appLink);
|
|
|
|
propBox.add_child(icon);
|
2010-04-20 14:57:31 -04:00
|
|
|
} else {
|
2023-08-06 18:40:20 -04:00
|
|
|
propsBox.add(new St.Label({text: '<untracked>'}));
|
2010-04-20 14:57:31 -04:00
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
}
|
|
|
|
}
|
2019-09-12 14:45:04 -04:00
|
|
|
|
|
|
|
update() {
|
|
|
|
this._updateWindowList();
|
|
|
|
}
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const ObjInspector = GObject.registerClass(
|
2019-07-16 05:24:13 -04:00
|
|
|
class ObjInspector extends St.ScrollView {
|
|
|
|
_init(lookingGlass) {
|
|
|
|
super._init({
|
2023-08-06 18:40:20 -04:00
|
|
|
pivot_point: new Graphene.Point({x: 0.5, y: 0.5}),
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2010-05-15 12:43:56 -04:00
|
|
|
this._obj = null;
|
|
|
|
this._previousObj = null;
|
2009-08-02 03:46:01 -04:00
|
|
|
|
|
|
|
this._parentList = [];
|
|
|
|
|
2019-07-16 05:24:13 -04:00
|
|
|
this.get_hscroll_bar().hide();
|
2019-10-17 17:40:24 -04:00
|
|
|
this._container = new St.BoxLayout({
|
|
|
|
name: 'LookingGlassPropertyInspector',
|
|
|
|
style_class: 'lg-dialog',
|
|
|
|
vertical: true,
|
|
|
|
x_expand: true,
|
|
|
|
y_expand: true,
|
|
|
|
});
|
2019-07-16 05:24:13 -04:00
|
|
|
this.add_actor(this._container);
|
2012-07-14 19:29:55 -04:00
|
|
|
|
|
|
|
this._lookingGlass = lookingGlass;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
selectObject(obj, skipPrevious) {
|
2010-05-15 12:43:56 -04:00
|
|
|
if (!skipPrevious)
|
|
|
|
this._previousObj = this._obj;
|
|
|
|
else
|
|
|
|
this._previousObj = null;
|
|
|
|
this._obj = obj;
|
|
|
|
|
2012-05-29 20:36:45 -04:00
|
|
|
this._container.destroy_all_children();
|
2010-05-15 12:43:56 -04:00
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
let hbox = new St.BoxLayout({style_class: 'lg-obj-inspector-title'});
|
2010-05-15 12:43:56 -04:00
|
|
|
this._container.add_actor(hbox);
|
2019-10-21 14:44:00 -04:00
|
|
|
let label = new St.Label({
|
2022-02-07 09:14:06 -05:00
|
|
|
text: `Inspecting: ${typeof obj}: ${objectToString(obj)}`,
|
2019-10-21 14:44:00 -04:00
|
|
|
x_expand: true,
|
|
|
|
});
|
2010-05-15 12:43:56 -04:00
|
|
|
label.single_line_mode = true;
|
2019-10-21 14:44:00 -04:00
|
|
|
hbox.add_child(label);
|
2023-08-06 18:40:20 -04:00
|
|
|
let button = new St.Button({label: 'Insert', style_class: 'lg-obj-inspector-button'});
|
2017-12-01 19:27:35 -05:00
|
|
|
button.connect('clicked', this._onInsert.bind(this));
|
2010-05-15 12:43:56 -04:00
|
|
|
hbox.add(button);
|
|
|
|
|
|
|
|
if (this._previousObj != null) {
|
2023-08-06 18:40:20 -04:00
|
|
|
button = new St.Button({label: 'Back', style_class: 'lg-obj-inspector-button'});
|
2017-12-01 19:27:35 -05:00
|
|
|
button.connect('clicked', this._onBack.bind(this));
|
2010-05-15 12:43:56 -04:00
|
|
|
hbox.add(button);
|
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2022-03-21 11:44:24 -04:00
|
|
|
button = new St.Button({
|
|
|
|
style_class: 'window-close',
|
|
|
|
icon_name: 'window-close-symbolic',
|
|
|
|
});
|
2017-12-01 19:27:35 -05:00
|
|
|
button.connect('clicked', this.close.bind(this));
|
2010-05-15 12:43:56 -04:00
|
|
|
hbox.add(button);
|
2023-08-06 20:51:19 -04:00
|
|
|
if (typeof obj === typeof {}) {
|
2012-03-30 11:15:33 -04:00
|
|
|
let properties = [];
|
2019-08-19 20:51:42 -04:00
|
|
|
for (let propName in obj)
|
2012-03-30 11:15:33 -04:00
|
|
|
properties.push(propName);
|
|
|
|
properties.sort();
|
|
|
|
|
|
|
|
for (let i = 0; i < properties.length; i++) {
|
|
|
|
let propName = properties[i];
|
2010-05-15 12:43:56 -04:00
|
|
|
let link;
|
|
|
|
try {
|
|
|
|
let prop = obj[propName];
|
2019-07-16 05:24:13 -04:00
|
|
|
link = new ObjLink(this._lookingGlass, prop);
|
2010-05-15 12:43:56 -04:00
|
|
|
} catch (e) {
|
2023-08-06 18:40:20 -04:00
|
|
|
link = new St.Label({text: '<error>'});
|
2010-05-15 12:43:56 -04:00
|
|
|
}
|
2019-08-19 20:20:08 -04:00
|
|
|
let box = new St.BoxLayout();
|
2023-08-06 18:40:20 -04:00
|
|
|
box.add(new St.Label({text: `${propName}: `}));
|
2019-08-19 20:20:08 -04:00
|
|
|
box.add(link);
|
|
|
|
this._container.add_actor(box);
|
2009-08-02 03:46:01 -04:00
|
|
|
}
|
|
|
|
}
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2010-05-15 12:43:56 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
open(sourceActor) {
|
2010-05-15 12:43:56 -04:00
|
|
|
if (this._open)
|
|
|
|
return;
|
2022-02-26 12:10:46 -05:00
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
const grab = Main.pushModal(this, {actionMode: Shell.ActionMode.LOOKING_GLASS});
|
2022-04-30 02:18:39 -04:00
|
|
|
if (grab.get_seat_state() !== Clutter.GrabState.ALL) {
|
2022-02-26 12:10:46 -05:00
|
|
|
Main.popModal(grab);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._grab = grab;
|
2010-05-15 12:43:56 -04:00
|
|
|
this._previousObj = null;
|
|
|
|
this._open = true;
|
2019-07-16 05:24:13 -04:00
|
|
|
this.show();
|
2010-05-15 12:43:56 -04:00
|
|
|
if (sourceActor) {
|
2019-07-16 05:24:13 -04:00
|
|
|
this.set_scale(0, 0);
|
|
|
|
this.ease({
|
2018-07-20 15:46:19 -04:00
|
|
|
scale_x: 1,
|
|
|
|
scale_y: 1,
|
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
2019-08-20 17:43:54 -04:00
|
|
|
duration: 200,
|
2018-07-20 15:46:19 -04:00
|
|
|
});
|
2010-05-15 12:43:56 -04:00
|
|
|
} else {
|
2019-07-16 05:24:13 -04:00
|
|
|
this.set_scale(1, 1);
|
2010-05-15 12:43:56 -04:00
|
|
|
}
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2010-05-15 12:43:56 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
close() {
|
2010-05-15 12:43:56 -04:00
|
|
|
if (!this._open)
|
|
|
|
return;
|
2022-02-26 12:10:46 -05:00
|
|
|
Main.popModal(this._grab);
|
|
|
|
this._grab = null;
|
2010-05-15 12:43:56 -04:00
|
|
|
this._open = false;
|
2019-07-16 05:24:13 -04:00
|
|
|
this.hide();
|
2010-05-15 12:43:56 -04:00
|
|
|
this._previousObj = null;
|
|
|
|
this._obj = null;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2010-05-15 12:43:56 -04:00
|
|
|
|
2023-08-08 12:14:04 -04:00
|
|
|
vfunc_key_press_event(event) {
|
|
|
|
const symbol = event.get_key_symbol();
|
2022-04-18 11:23:45 -04:00
|
|
|
if (symbol === Clutter.KEY_Escape) {
|
|
|
|
this.close();
|
|
|
|
return Clutter.EVENT_STOP;
|
|
|
|
}
|
2023-08-08 12:14:04 -04:00
|
|
|
return super.vfunc_key_press_event(event);
|
2022-04-18 11:23:45 -04:00
|
|
|
}
|
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_onInsert() {
|
2010-05-15 12:43:56 -04:00
|
|
|
let obj = this._obj;
|
|
|
|
this.close();
|
2012-07-14 19:29:55 -04:00
|
|
|
this._lookingGlass.insertObject(obj);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2010-05-15 12:43:56 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_onBack() {
|
2010-05-15 12:43:56 -04:00
|
|
|
this.selectObject(this._previousObj, true);
|
2009-08-02 03:46:01 -04:00
|
|
|
}
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const RedBorderEffect = GObject.registerClass(
|
2017-10-30 21:23:39 -04:00
|
|
|
class RedBorderEffect extends Clutter.Effect {
|
2019-11-22 12:36:17 -05:00
|
|
|
_init() {
|
|
|
|
super._init();
|
|
|
|
this._pipeline = null;
|
|
|
|
}
|
|
|
|
|
2020-06-29 17:01:44 -04:00
|
|
|
vfunc_paint_node(node, paintContext) {
|
2012-06-21 14:42:33 -04:00
|
|
|
let actor = this.get_actor();
|
2020-06-29 17:01:44 -04:00
|
|
|
|
|
|
|
const actorNode = new Clutter.ActorNode(actor, -1);
|
|
|
|
node.add_child(actorNode);
|
2012-06-21 14:42:33 -04:00
|
|
|
|
2019-11-22 12:36:17 -05:00
|
|
|
if (!this._pipeline) {
|
2020-06-29 17:01:44 -04:00
|
|
|
const framebuffer = paintContext.get_framebuffer();
|
|
|
|
const coglContext = framebuffer.get_context();
|
|
|
|
|
2019-11-22 12:36:17 -05:00
|
|
|
let color = new Cogl.Color();
|
|
|
|
color.init_from_4ub(0xff, 0, 0, 0xc4);
|
|
|
|
|
|
|
|
this._pipeline = new Cogl.Pipeline(coglContext);
|
|
|
|
this._pipeline.set_color(color);
|
|
|
|
}
|
2012-06-21 14:42:33 -04:00
|
|
|
|
2019-10-21 11:42:12 -04:00
|
|
|
let alloc = actor.get_allocation_box();
|
2012-06-21 14:42:33 -04:00
|
|
|
let width = 2;
|
|
|
|
|
2020-06-29 17:01:44 -04:00
|
|
|
const pipelineNode = new Clutter.PipelineNode(this._pipeline);
|
|
|
|
pipelineNode.set_name('Red Border');
|
|
|
|
node.add_child(pipelineNode);
|
|
|
|
|
|
|
|
const box = new Clutter.ActorBox();
|
|
|
|
|
2012-06-21 14:42:33 -04:00
|
|
|
// clockwise order
|
2020-06-29 17:01:44 -04:00
|
|
|
box.set_origin(0, 0);
|
|
|
|
box.set_size(alloc.get_width(), width);
|
|
|
|
pipelineNode.add_rectangle(box);
|
|
|
|
|
|
|
|
box.set_origin(alloc.get_width() - width, width);
|
2021-06-09 02:09:51 -04:00
|
|
|
box.set_size(width, alloc.get_height() - width);
|
2020-06-29 17:01:44 -04:00
|
|
|
pipelineNode.add_rectangle(box);
|
|
|
|
|
|
|
|
box.set_origin(0, alloc.get_height() - width);
|
|
|
|
box.set_size(alloc.get_width() - width, width);
|
|
|
|
pipelineNode.add_rectangle(box);
|
|
|
|
|
|
|
|
box.set_origin(0, width);
|
2021-06-09 02:21:21 -04:00
|
|
|
box.set_size(width, alloc.get_height() - width * 2);
|
2020-06-29 17:01:44 -04:00
|
|
|
pipelineNode.add_rectangle(box);
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2012-06-21 14:42:33 -04:00
|
|
|
});
|
2011-02-10 14:35:33 -05:00
|
|
|
|
2023-08-17 13:32:42 -04:00
|
|
|
export const Inspector = GObject.registerClass({
|
2020-03-29 17:51:13 -04:00
|
|
|
Signals: {
|
|
|
|
'closed': {},
|
2023-08-06 18:40:20 -04:00
|
|
|
'target': {param_types: [Clutter.Actor.$gtype, GObject.TYPE_DOUBLE, GObject.TYPE_DOUBLE]},
|
2020-03-29 17:51:13 -04:00
|
|
|
},
|
2017-10-30 21:23:39 -04:00
|
|
|
}, class Inspector extends Clutter.Actor {
|
2017-10-30 20:03:21 -04:00
|
|
|
_init(lookingGlass) {
|
2023-08-06 18:40:20 -04:00
|
|
|
super._init({width: 0, height: 0});
|
2018-07-09 03:49:37 -04:00
|
|
|
|
|
|
|
Main.uiGroup.add_actor(this);
|
2010-07-21 11:50:58 -04:00
|
|
|
|
2020-03-29 17:51:13 -04:00
|
|
|
const eventHandler = new St.BoxLayout({
|
|
|
|
name: 'LookingGlassDialog',
|
|
|
|
vertical: false,
|
|
|
|
reactive: true,
|
|
|
|
});
|
2010-07-21 11:08:15 -04:00
|
|
|
this._eventHandler = eventHandler;
|
2018-07-09 03:49:37 -04:00
|
|
|
this.add_actor(eventHandler);
|
2023-08-06 18:40:20 -04:00
|
|
|
this._displayText = new St.Label({x_expand: true});
|
2019-10-21 14:44:00 -04:00
|
|
|
eventHandler.add_child(this._displayText);
|
2009-08-04 09:49:03 -04:00
|
|
|
|
2017-12-01 19:27:35 -05:00
|
|
|
eventHandler.connect('key-press-event', this._onKeyPressEvent.bind(this));
|
|
|
|
eventHandler.connect('button-press-event', this._onButtonPressEvent.bind(this));
|
|
|
|
eventHandler.connect('scroll-event', this._onScrollEvent.bind(this));
|
|
|
|
eventHandler.connect('motion-event', this._onMotionEvent.bind(this));
|
2019-04-14 12:32:11 -04:00
|
|
|
|
2021-11-17 18:13:45 -05:00
|
|
|
this._grab = global.stage.grab(eventHandler);
|
2010-07-21 11:29:05 -04:00
|
|
|
|
|
|
|
// this._target is the actor currently shown by the inspector.
|
|
|
|
// this._pointerTarget is the actor directly under the pointer.
|
|
|
|
// Normally these are the same, but if you use the scroll wheel
|
|
|
|
// to drill down, they'll diverge until you either scroll back
|
|
|
|
// out, or move the pointer outside of _pointerTarget.
|
|
|
|
this._target = null;
|
|
|
|
this._pointerTarget = null;
|
2012-07-14 19:29:55 -04:00
|
|
|
|
|
|
|
this._lookingGlass = lookingGlass;
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2010-07-21 11:29:05 -04:00
|
|
|
|
2020-05-09 15:30:26 -04:00
|
|
|
vfunc_allocate(box) {
|
|
|
|
this.set_allocation(box);
|
2018-07-09 03:49:37 -04:00
|
|
|
|
2011-01-11 15:14:16 -05:00
|
|
|
if (!this._eventHandler)
|
|
|
|
return;
|
|
|
|
|
2011-06-13 09:54:05 -04:00
|
|
|
let primary = Main.layoutManager.primaryMonitor;
|
2010-07-21 11:50:58 -04:00
|
|
|
|
2019-02-01 08:41:55 -05:00
|
|
|
let [, , natWidth, natHeight] =
|
2010-07-21 11:50:58 -04:00
|
|
|
this._eventHandler.get_preferred_size();
|
|
|
|
|
|
|
|
let childBox = new Clutter.ActorBox();
|
|
|
|
childBox.x1 = primary.x + Math.floor((primary.width - natWidth) / 2);
|
|
|
|
childBox.x2 = childBox.x1 + natWidth;
|
|
|
|
childBox.y1 = primary.y + Math.floor((primary.height - natHeight) / 2);
|
|
|
|
childBox.y2 = childBox.y1 + natHeight;
|
2020-05-09 15:30:26 -04:00
|
|
|
this._eventHandler.allocate(childBox);
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2010-07-21 11:50:58 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_close() {
|
2021-11-17 18:13:45 -05:00
|
|
|
if (this._grab) {
|
|
|
|
this._grab.dismiss();
|
|
|
|
this._grab = null;
|
|
|
|
}
|
2010-07-21 11:29:05 -04:00
|
|
|
this._eventHandler.destroy();
|
2011-01-11 15:14:16 -05:00
|
|
|
this._eventHandler = null;
|
2010-07-21 11:29:05 -04:00
|
|
|
this.emit('closed');
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2010-07-21 11:08:15 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_onKeyPressEvent(actor, event) {
|
2019-11-05 14:37:28 -05:00
|
|
|
if (event.get_key_symbol() === Clutter.KEY_Escape)
|
2010-07-21 11:37:08 -04:00
|
|
|
this._close();
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_STOP;
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2010-07-21 11:37:08 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_onButtonPressEvent(actor, event) {
|
2010-07-21 11:29:05 -04:00
|
|
|
if (this._target) {
|
|
|
|
let [stageX, stageY] = event.get_coords();
|
|
|
|
this.emit('target', this._target, stageX, stageY);
|
|
|
|
}
|
|
|
|
this._close();
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_STOP;
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2010-07-21 11:08:15 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_onScrollEvent(actor, event) {
|
2010-07-21 11:29:05 -04:00
|
|
|
switch (event.get_scroll_direction()) {
|
2019-01-29 18:22:10 -05:00
|
|
|
case Clutter.ScrollDirection.UP: {
|
2010-07-21 11:29:05 -04:00
|
|
|
// select parent
|
|
|
|
let parent = this._target.get_parent();
|
|
|
|
if (parent != null) {
|
|
|
|
this._target = parent;
|
|
|
|
this._update(event);
|
|
|
|
}
|
|
|
|
break;
|
2019-01-29 18:22:10 -05:00
|
|
|
}
|
2010-07-21 11:29:05 -04:00
|
|
|
|
|
|
|
case Clutter.ScrollDirection.DOWN:
|
|
|
|
// select child
|
2023-08-06 20:51:19 -04:00
|
|
|
if (this._target !== this._pointerTarget) {
|
2010-07-21 11:29:05 -04:00
|
|
|
let child = this._pointerTarget;
|
|
|
|
while (child) {
|
|
|
|
let parent = child.get_parent();
|
2023-08-06 20:51:19 -04:00
|
|
|
if (parent === this._target)
|
2010-07-21 11:29:05 -04:00
|
|
|
break;
|
|
|
|
child = parent;
|
|
|
|
}
|
|
|
|
if (child) {
|
|
|
|
this._target = child;
|
|
|
|
this._update(event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_STOP;
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2010-07-21 11:08:15 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_onMotionEvent(actor, event) {
|
2010-07-21 11:29:05 -04:00
|
|
|
this._update(event);
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_STOP;
|
2017-10-30 21:23:39 -04:00
|
|
|
}
|
2010-07-21 11:29:05 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_update(event) {
|
2010-07-21 11:08:15 -04:00
|
|
|
let [stageX, stageY] = event.get_coords();
|
2023-08-06 19:45:22 -04:00
|
|
|
let target = global.stage.get_actor_at_pos(
|
|
|
|
Clutter.PickMode.ALL, stageX, stageY);
|
2010-07-21 11:29:05 -04:00
|
|
|
|
2023-08-06 20:51:19 -04:00
|
|
|
if (target !== this._pointerTarget)
|
2010-07-21 11:29:05 -04:00
|
|
|
this._target = target;
|
|
|
|
this._pointerTarget = target;
|
|
|
|
|
2022-02-07 09:14:06 -05:00
|
|
|
let position = `[inspect x: ${stageX} y: ${stageY}]`;
|
2010-07-21 11:08:15 -04:00
|
|
|
this._displayText.text = '';
|
2022-02-07 09:14:06 -05:00
|
|
|
this._displayText.text = `${position} ${this._target}`;
|
2011-02-10 14:35:33 -05:00
|
|
|
|
2012-07-14 19:30:47 -04:00
|
|
|
this._lookingGlass.setBorderPaintTarget(this._target);
|
2009-08-04 09:49:03 -04:00
|
|
|
}
|
2011-11-20 12:56:27 -05:00
|
|
|
});
|
2009-08-04 09:49:03 -04:00
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const Extensions = GObject.registerClass({
|
2019-07-16 05:24:13 -04:00
|
|
|
}, class Extensions extends St.BoxLayout {
|
|
|
|
_init(lookingGlass) {
|
2023-08-06 18:40:20 -04:00
|
|
|
super._init({vertical: true, name: 'lookingGlassExtensions'});
|
2019-07-16 05:24:13 -04:00
|
|
|
|
2013-02-14 10:28:43 -05:00
|
|
|
this._lookingGlass = lookingGlass;
|
2020-03-29 17:51:13 -04:00
|
|
|
this._noExtensions = new St.Label({
|
|
|
|
style_class: 'lg-extensions-none',
|
|
|
|
text: _('No extensions installed'),
|
|
|
|
});
|
2011-06-11 00:21:35 -04:00
|
|
|
this._numExtensions = 0;
|
2020-03-29 17:51:13 -04:00
|
|
|
this._extensionsList = new St.BoxLayout({
|
|
|
|
vertical: true,
|
|
|
|
style_class: 'lg-extensions-list',
|
|
|
|
});
|
2011-06-11 00:21:35 -04:00
|
|
|
this._extensionsList.add(this._noExtensions);
|
2019-07-16 05:24:13 -04:00
|
|
|
this.add(this._extensionsList);
|
2011-06-11 00:21:35 -04:00
|
|
|
|
2019-07-07 18:01:11 -04:00
|
|
|
Main.extensionManager.getUuids().forEach(uuid => {
|
2011-06-11 00:21:35 -04:00
|
|
|
this._loadExtension(null, uuid);
|
2019-07-07 18:01:11 -04:00
|
|
|
});
|
2011-06-11 00:21:35 -04:00
|
|
|
|
2019-03-06 19:45:45 -05:00
|
|
|
Main.extensionManager.connect('extension-loaded',
|
2023-08-06 19:45:22 -04:00
|
|
|
this._loadExtension.bind(this));
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-10-28 18:05:34 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_loadExtension(o, uuid) {
|
2019-07-07 18:01:11 -04:00
|
|
|
let extension = Main.extensionManager.lookup(uuid);
|
2011-06-11 00:21:35 -04:00
|
|
|
// There can be cases where we create dummy extension metadata
|
|
|
|
// that's not really a proper extension. Don't bother with these.
|
2012-01-30 20:58:29 -05:00
|
|
|
if (!extension.metadata.name)
|
2011-06-11 00:21:35 -04:00
|
|
|
return;
|
|
|
|
|
|
|
|
let extensionDisplay = this._createExtensionDisplay(extension);
|
2023-08-06 20:51:19 -04:00
|
|
|
if (this._numExtensions === 0)
|
2011-06-11 00:21:35 -04:00
|
|
|
this._extensionsList.remove_actor(this._noExtensions);
|
|
|
|
|
2019-08-19 13:55:49 -04:00
|
|
|
this._numExtensions++;
|
2023-08-06 18:40:20 -04:00
|
|
|
const {name} = extension.metadata;
|
2020-12-03 17:36:33 -05:00
|
|
|
const pos = [...this._extensionsList].findIndex(
|
|
|
|
dsp => dsp._extension.metadata.name.localeCompare(name) > 0);
|
|
|
|
this._extensionsList.insert_child_at_index(extensionDisplay, pos);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-10-28 18:05:34 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_onViewSource(actor) {
|
2012-01-30 20:58:29 -05:00
|
|
|
let extension = actor._extension;
|
|
|
|
let uri = extension.dir.get_uri();
|
2014-01-19 12:34:32 -05:00
|
|
|
Gio.app_info_launch_default_for_uri(uri, global.create_app_launch_context(0, -1));
|
2012-07-14 19:29:55 -04:00
|
|
|
this._lookingGlass.close();
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-10-28 18:05:34 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_onWebPage(actor) {
|
2012-01-30 20:58:29 -05:00
|
|
|
let extension = actor._extension;
|
2014-01-19 12:34:32 -05:00
|
|
|
Gio.app_info_launch_default_for_uri(extension.metadata.url, global.create_app_launch_context(0, -1));
|
2012-07-14 19:29:55 -04:00
|
|
|
this._lookingGlass.close();
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-10-28 18:05:34 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_onViewErrors(actor) {
|
2012-01-30 20:58:29 -05:00
|
|
|
let extension = actor._extension;
|
2011-09-30 03:58:44 -04:00
|
|
|
let shouldShow = !actor._isShowing;
|
|
|
|
|
|
|
|
if (shouldShow) {
|
2012-01-30 20:58:29 -05:00
|
|
|
let errors = extension.errors;
|
2023-08-06 18:40:20 -04:00
|
|
|
let errorDisplay = new St.BoxLayout({vertical: true});
|
2011-09-30 03:58:44 -04:00
|
|
|
if (errors && errors.length) {
|
2019-08-19 13:55:49 -04:00
|
|
|
for (let i = 0; i < errors.length; i++)
|
2023-08-06 18:40:20 -04:00
|
|
|
errorDisplay.add(new St.Label({text: errors[i]}));
|
2011-09-30 03:58:44 -04:00
|
|
|
} else {
|
|
|
|
/* Translators: argument is an extension UUID. */
|
2023-08-06 18:34:20 -04:00
|
|
|
let message = _('%s has not emitted any errors.').format(extension.uuid);
|
2023-08-06 18:40:20 -04:00
|
|
|
errorDisplay.add(new St.Label({text: message}));
|
2011-09-30 03:58:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
actor._errorDisplay = errorDisplay;
|
|
|
|
actor._parentBox.add(errorDisplay);
|
2023-08-06 18:34:20 -04:00
|
|
|
actor.label = _('Hide Errors');
|
2011-09-30 03:58:44 -04:00
|
|
|
} else {
|
|
|
|
actor._errorDisplay.destroy();
|
|
|
|
actor._errorDisplay = null;
|
2023-08-06 18:34:20 -04:00
|
|
|
actor.label = _('Show Errors');
|
2011-09-30 03:58:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
actor._isShowing = shouldShow;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-09-30 03:58:44 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_stateToString(extensionState) {
|
2009-10-28 18:05:34 -04:00
|
|
|
switch (extensionState) {
|
2019-07-06 09:31:57 -04:00
|
|
|
case ExtensionState.ENABLED:
|
2022-07-24 22:25:23 -04:00
|
|
|
return _('Enabled');
|
2019-07-06 09:31:57 -04:00
|
|
|
case ExtensionState.DISABLED:
|
|
|
|
case ExtensionState.INITIALIZED:
|
2022-07-24 22:25:23 -04:00
|
|
|
return _('Disabled');
|
2019-07-06 09:31:57 -04:00
|
|
|
case ExtensionState.ERROR:
|
2022-07-24 22:25:23 -04:00
|
|
|
return _('Error');
|
2019-07-06 09:31:57 -04:00
|
|
|
case ExtensionState.OUT_OF_DATE:
|
2022-07-24 22:25:23 -04:00
|
|
|
return _('Out of date');
|
2019-07-06 09:31:57 -04:00
|
|
|
case ExtensionState.DOWNLOADING:
|
2022-07-24 22:25:23 -04:00
|
|
|
return _('Downloading');
|
|
|
|
case ExtensionState.DISABLING:
|
|
|
|
return _('Disabling');
|
|
|
|
case ExtensionState.ENABLING:
|
|
|
|
return _('Enabling');
|
2009-10-28 18:05:34 -04:00
|
|
|
}
|
2010-05-13 15:46:04 -04:00
|
|
|
return 'Unknown'; // Not translated, shouldn't appear
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-10-28 18:05:34 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_createExtensionDisplay(extension) {
|
2023-08-06 18:40:20 -04:00
|
|
|
let box = new St.BoxLayout({style_class: 'lg-extension', vertical: true});
|
2020-12-03 17:36:33 -05:00
|
|
|
box._extension = extension;
|
2019-10-21 14:44:00 -04:00
|
|
|
let name = new St.Label({
|
|
|
|
style_class: 'lg-extension-name',
|
|
|
|
text: extension.metadata.name,
|
|
|
|
x_expand: true,
|
|
|
|
});
|
|
|
|
box.add_child(name);
|
|
|
|
let description = new St.Label({
|
|
|
|
style_class: 'lg-extension-description',
|
|
|
|
text: extension.metadata.description || 'No description',
|
|
|
|
x_expand: true,
|
|
|
|
});
|
|
|
|
box.add_child(description);
|
2009-10-28 18:05:34 -04:00
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
let metaBox = new St.BoxLayout({style_class: 'lg-extension-meta'});
|
2009-10-28 18:05:34 -04:00
|
|
|
box.add(metaBox);
|
2020-03-29 17:51:13 -04:00
|
|
|
const state = new St.Label({
|
|
|
|
style_class: 'lg-extension-state',
|
|
|
|
text: this._stateToString(extension.state),
|
|
|
|
});
|
2011-09-29 12:34:46 -04:00
|
|
|
metaBox.add(state);
|
2009-10-28 18:05:34 -04:00
|
|
|
|
2020-03-29 17:51:13 -04:00
|
|
|
const viewsource = new St.Button({
|
|
|
|
reactive: true,
|
|
|
|
track_hover: true,
|
|
|
|
style_class: 'shell-link',
|
|
|
|
label: _('View Source'),
|
|
|
|
});
|
2012-07-14 18:49:06 -04:00
|
|
|
viewsource._extension = extension;
|
2017-12-01 19:27:35 -05:00
|
|
|
viewsource.connect('clicked', this._onViewSource.bind(this));
|
2012-07-14 18:49:06 -04:00
|
|
|
metaBox.add(viewsource);
|
2009-10-28 18:05:34 -04:00
|
|
|
|
2012-01-30 20:58:29 -05:00
|
|
|
if (extension.metadata.url) {
|
2020-03-29 17:51:13 -04:00
|
|
|
const webpage = new St.Button({
|
|
|
|
reactive: true,
|
|
|
|
track_hover: true,
|
|
|
|
style_class: 'shell-link',
|
|
|
|
label: _('Web Page'),
|
|
|
|
});
|
2012-07-14 18:49:06 -04:00
|
|
|
webpage._extension = extension;
|
2017-12-01 19:27:35 -05:00
|
|
|
webpage.connect('clicked', this._onWebPage.bind(this));
|
2012-07-14 18:49:06 -04:00
|
|
|
metaBox.add(webpage);
|
2009-10-28 18:05:34 -04:00
|
|
|
}
|
|
|
|
|
2020-03-29 17:51:13 -04:00
|
|
|
const viewerrors = new St.Button({
|
|
|
|
reactive: true,
|
|
|
|
track_hover: true,
|
|
|
|
style_class: 'shell-link',
|
|
|
|
label: _('Show Errors'),
|
|
|
|
});
|
2012-07-14 18:49:06 -04:00
|
|
|
viewerrors._extension = extension;
|
|
|
|
viewerrors._parentBox = box;
|
|
|
|
viewerrors._isShowing = false;
|
2017-12-01 19:27:35 -05:00
|
|
|
viewerrors.connect('clicked', this._onViewErrors.bind(this));
|
2012-07-14 18:49:06 -04:00
|
|
|
metaBox.add(viewerrors);
|
2011-09-30 03:58:44 -04:00
|
|
|
|
2009-10-28 18:05:34 -04:00
|
|
|
return box;
|
|
|
|
}
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|
|
|
|
|
2020-05-31 16:31:48 -04:00
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const ActorLink = GObject.registerClass({
|
2020-05-31 16:31:48 -04:00
|
|
|
Signals: {
|
|
|
|
'inspect-actor': {},
|
|
|
|
},
|
|
|
|
}, class ActorLink extends St.Button {
|
|
|
|
_init(actor) {
|
|
|
|
this._arrow = new St.Icon({
|
|
|
|
icon_name: 'pan-end-symbolic',
|
|
|
|
icon_size: 8,
|
|
|
|
x_align: Clutter.ActorAlign.CENTER,
|
|
|
|
y_align: Clutter.ActorAlign.CENTER,
|
2023-08-06 18:40:20 -04:00
|
|
|
pivot_point: new Graphene.Point({x: 0.5, y: 0.5}),
|
2020-05-31 16:31:48 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
const label = new St.Label({
|
|
|
|
text: actor.toString(),
|
|
|
|
x_align: Clutter.ActorAlign.START,
|
|
|
|
});
|
|
|
|
|
|
|
|
const inspectButton = new St.Button({
|
2022-03-21 11:44:24 -04:00
|
|
|
icon_name: 'insert-object-symbolic',
|
2020-05-31 16:31:48 -04:00
|
|
|
reactive: true,
|
|
|
|
x_expand: true,
|
|
|
|
x_align: Clutter.ActorAlign.START,
|
|
|
|
y_align: Clutter.ActorAlign.CENTER,
|
|
|
|
});
|
|
|
|
inspectButton.connect('clicked', () => this.emit('inspect-actor'));
|
|
|
|
|
|
|
|
const box = new St.BoxLayout();
|
|
|
|
box.add_child(this._arrow);
|
|
|
|
box.add_child(label);
|
|
|
|
box.add_child(inspectButton);
|
|
|
|
|
|
|
|
super._init({
|
|
|
|
reactive: true,
|
|
|
|
track_hover: true,
|
|
|
|
toggle_mode: true,
|
|
|
|
style_class: 'actor-link',
|
|
|
|
child: box,
|
|
|
|
x_align: Clutter.ActorAlign.START,
|
|
|
|
});
|
|
|
|
|
|
|
|
this._actor = actor;
|
|
|
|
}
|
|
|
|
|
|
|
|
vfunc_clicked() {
|
|
|
|
this._arrow.ease({
|
|
|
|
rotation_angle_z: this.checked ? 90 : 0,
|
|
|
|
duration: 250,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const ActorTreeViewer = GObject.registerClass(
|
2020-05-31 16:31:48 -04:00
|
|
|
class ActorTreeViewer extends St.BoxLayout {
|
|
|
|
_init(lookingGlass) {
|
|
|
|
super._init();
|
|
|
|
|
|
|
|
this._lookingGlass = lookingGlass;
|
|
|
|
this._actorData = new Map();
|
|
|
|
}
|
|
|
|
|
|
|
|
_showActorChildren(actor) {
|
|
|
|
const data = this._actorData.get(actor);
|
|
|
|
if (!data || data.visible)
|
|
|
|
return;
|
|
|
|
|
|
|
|
data.visible = true;
|
|
|
|
data.actorAddedId = actor.connect('actor-added', (container, child) => {
|
|
|
|
this._addActor(data.children, child);
|
|
|
|
});
|
|
|
|
data.actorRemovedId = actor.connect('actor-removed', (container, child) => {
|
|
|
|
this._removeActor(child);
|
|
|
|
});
|
|
|
|
|
|
|
|
for (let child of actor)
|
|
|
|
this._addActor(data.children, child);
|
|
|
|
}
|
|
|
|
|
|
|
|
_hideActorChildren(actor) {
|
|
|
|
const data = this._actorData.get(actor);
|
|
|
|
if (!data || !data.visible)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (let child of actor)
|
|
|
|
this._removeActor(child);
|
|
|
|
|
|
|
|
data.visible = false;
|
|
|
|
if (data.actorAddedId > 0) {
|
|
|
|
actor.disconnect(data.actorAddedId);
|
|
|
|
data.actorAddedId = 0;
|
|
|
|
}
|
|
|
|
if (data.actorRemovedId > 0) {
|
|
|
|
actor.disconnect(data.actorRemovedId);
|
|
|
|
data.actorRemovedId = 0;
|
|
|
|
}
|
|
|
|
data.children.remove_all_children();
|
|
|
|
}
|
|
|
|
|
|
|
|
_addActor(container, actor) {
|
|
|
|
if (this._actorData.has(actor))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (actor === this._lookingGlass)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const button = new ActorLink(actor);
|
|
|
|
button.connect('notify::checked', () => {
|
|
|
|
this._lookingGlass.setBorderPaintTarget(actor);
|
|
|
|
if (button.checked)
|
|
|
|
this._showActorChildren(actor);
|
|
|
|
else
|
|
|
|
this._hideActorChildren(actor);
|
|
|
|
});
|
|
|
|
button.connect('inspect-actor', () => {
|
|
|
|
this._lookingGlass.inspectObject(actor, button);
|
|
|
|
});
|
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
const mainContainer = new St.BoxLayout({vertical: true});
|
2020-05-31 16:31:48 -04:00
|
|
|
const childrenContainer = new St.BoxLayout({
|
|
|
|
vertical: true,
|
|
|
|
style: 'padding: 0 0 0 18px',
|
|
|
|
});
|
|
|
|
|
|
|
|
mainContainer.add_child(button);
|
|
|
|
mainContainer.add_child(childrenContainer);
|
|
|
|
|
|
|
|
this._actorData.set(actor, {
|
|
|
|
button,
|
|
|
|
container: mainContainer,
|
|
|
|
children: childrenContainer,
|
|
|
|
visible: false,
|
|
|
|
actorAddedId: 0,
|
|
|
|
actorRemovedId: 0,
|
|
|
|
actorDestroyedId: actor.connect('destroy', () => this._removeActor(actor)),
|
|
|
|
});
|
|
|
|
|
|
|
|
let belowChild = null;
|
|
|
|
const nextSibling = actor.get_next_sibling();
|
|
|
|
if (nextSibling && this._actorData.has(nextSibling))
|
|
|
|
belowChild = this._actorData.get(nextSibling).container;
|
|
|
|
|
|
|
|
container.insert_child_above(mainContainer, belowChild);
|
|
|
|
}
|
|
|
|
|
|
|
|
_removeActor(actor) {
|
|
|
|
const data = this._actorData.get(actor);
|
|
|
|
if (!data)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (let child of actor)
|
|
|
|
this._removeActor(child);
|
|
|
|
|
|
|
|
if (data.actorAddedId > 0) {
|
|
|
|
actor.disconnect(data.actorAddedId);
|
|
|
|
data.actorAddedId = 0;
|
|
|
|
}
|
|
|
|
if (data.actorRemovedId > 0) {
|
|
|
|
actor.disconnect(data.actorRemovedId);
|
|
|
|
data.actorRemovedId = 0;
|
|
|
|
}
|
|
|
|
if (data.actorDestroyedId > 0) {
|
|
|
|
actor.disconnect(data.actorDestroyedId);
|
|
|
|
data.actorDestroyedId = 0;
|
|
|
|
}
|
|
|
|
data.container.destroy();
|
|
|
|
this._actorData.delete(actor);
|
|
|
|
}
|
|
|
|
|
|
|
|
vfunc_map() {
|
|
|
|
super.vfunc_map();
|
|
|
|
this._addActor(this, global.stage);
|
|
|
|
}
|
|
|
|
|
|
|
|
vfunc_unmap() {
|
|
|
|
super.vfunc_unmap();
|
|
|
|
this._removeActor(global.stage);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const DebugFlag = GObject.registerClass({
|
2021-09-29 14:09:19 -04:00
|
|
|
GTypeFlags: GObject.TypeFlags.ABSTRACT,
|
|
|
|
}, class DebugFlag extends St.Button {
|
|
|
|
_init(label) {
|
|
|
|
const box = new St.BoxLayout();
|
|
|
|
|
|
|
|
const flagLabel = new St.Label({
|
|
|
|
text: label,
|
|
|
|
x_expand: true,
|
|
|
|
x_align: Clutter.ActorAlign.START,
|
|
|
|
y_align: Clutter.ActorAlign.CENTER,
|
|
|
|
});
|
|
|
|
box.add_child(flagLabel);
|
|
|
|
|
|
|
|
this._flagSwitch = new PopupMenu.Switch(false);
|
|
|
|
this._stateHandler = this._flagSwitch.connect('notify::state', () => {
|
|
|
|
if (this._flagSwitch.state)
|
|
|
|
this._enable();
|
|
|
|
else
|
|
|
|
this._disable();
|
|
|
|
});
|
|
|
|
|
|
|
|
// Update state whenever the switch is mapped, because most debug flags
|
|
|
|
// don't have a way of notifying us of changes.
|
|
|
|
this._flagSwitch.connect('notify::mapped', () => {
|
|
|
|
if (!this._flagSwitch.is_mapped())
|
|
|
|
return;
|
|
|
|
|
|
|
|
const state = this._isEnabled();
|
|
|
|
if (state === this._flagSwitch.state)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._flagSwitch.block_signal_handler(this._stateHandler);
|
|
|
|
this._flagSwitch.state = state;
|
|
|
|
this._flagSwitch.unblock_signal_handler(this._stateHandler);
|
|
|
|
});
|
|
|
|
|
|
|
|
box.add_child(this._flagSwitch);
|
|
|
|
|
|
|
|
super._init({
|
|
|
|
style_class: 'lg-debug-flag-button',
|
|
|
|
can_focus: true,
|
|
|
|
toggleMode: true,
|
|
|
|
child: box,
|
|
|
|
label_actor: flagLabel,
|
|
|
|
y_align: Clutter.ActorAlign.CENTER,
|
|
|
|
});
|
|
|
|
|
|
|
|
this.connect('clicked', () => this._flagSwitch.toggle());
|
|
|
|
}
|
|
|
|
|
|
|
|
_isEnabled() {
|
|
|
|
throw new Error('Method not implemented');
|
|
|
|
}
|
|
|
|
|
|
|
|
_enable() {
|
|
|
|
throw new Error('Method not implemented');
|
|
|
|
}
|
|
|
|
|
|
|
|
_disable() {
|
|
|
|
throw new Error('Method not implemented');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const ClutterDebugFlag = GObject.registerClass(
|
2021-09-29 14:09:19 -04:00
|
|
|
class ClutterDebugFlag extends DebugFlag {
|
|
|
|
_init(categoryName, flagName) {
|
|
|
|
super._init(flagName);
|
|
|
|
|
|
|
|
this._argPos = CLUTTER_DEBUG_FLAG_CATEGORIES.get(categoryName).argPos;
|
|
|
|
this._enumValue = Clutter[categoryName][flagName];
|
|
|
|
}
|
|
|
|
|
|
|
|
_isEnabled() {
|
|
|
|
const enabledFlags = Meta.get_clutter_debug_flags();
|
|
|
|
return !!(enabledFlags[this._argPos] & this._enumValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
_getArgs() {
|
|
|
|
const args = [0, 0, 0];
|
|
|
|
args[this._argPos] = this._enumValue;
|
|
|
|
return args;
|
|
|
|
}
|
|
|
|
|
|
|
|
_enable() {
|
|
|
|
Meta.add_clutter_debug_flags(...this._getArgs());
|
|
|
|
}
|
|
|
|
|
|
|
|
_disable() {
|
|
|
|
Meta.remove_clutter_debug_flags(...this._getArgs());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const MutterPaintDebugFlag = GObject.registerClass(
|
2021-09-29 14:09:19 -04:00
|
|
|
class MutterPaintDebugFlag extends DebugFlag {
|
|
|
|
_init(flagName) {
|
|
|
|
super._init(flagName);
|
|
|
|
|
|
|
|
this._enumValue = Meta.DebugPaintFlag[flagName];
|
|
|
|
}
|
|
|
|
|
|
|
|
_isEnabled() {
|
|
|
|
return !!(Meta.get_debug_paint_flags() & this._enumValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
_enable() {
|
|
|
|
Meta.add_debug_paint_flag(this._enumValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
_disable() {
|
|
|
|
Meta.remove_debug_paint_flag(this._enumValue);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const MutterTopicDebugFlag = GObject.registerClass(
|
2021-09-29 14:09:19 -04:00
|
|
|
class MutterTopicDebugFlag extends DebugFlag {
|
|
|
|
_init(flagName) {
|
|
|
|
super._init(flagName);
|
|
|
|
|
|
|
|
this._enumValue = Meta.DebugTopic[flagName];
|
|
|
|
}
|
|
|
|
|
|
|
|
_isEnabled() {
|
|
|
|
return Meta.is_topic_enabled(this._enumValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
_enable() {
|
|
|
|
Meta.add_verbose_topic(this._enumValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
_disable() {
|
|
|
|
Meta.remove_verbose_topic(this._enumValue);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const UnsafeModeDebugFlag = GObject.registerClass(
|
2021-09-29 14:09:19 -04:00
|
|
|
class UnsafeModeDebugFlag extends DebugFlag {
|
|
|
|
_init() {
|
|
|
|
super._init('unsafe-mode');
|
|
|
|
}
|
|
|
|
|
|
|
|
_isEnabled() {
|
|
|
|
return global.context.unsafe_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
_enable() {
|
|
|
|
global.context.unsafe_mode = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
_disable() {
|
|
|
|
global.context.unsafe_mode = false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
const DebugFlags = GObject.registerClass(
|
2021-09-29 14:09:19 -04:00
|
|
|
class DebugFlags extends St.BoxLayout {
|
|
|
|
_init() {
|
|
|
|
super._init({
|
|
|
|
name: 'lookingGlassDebugFlags',
|
|
|
|
vertical: true,
|
|
|
|
x_align: Clutter.ActorAlign.CENTER,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Clutter debug flags
|
|
|
|
for (const [categoryName, props] of CLUTTER_DEBUG_FLAG_CATEGORIES.entries()) {
|
2022-02-07 09:14:06 -05:00
|
|
|
this._addHeader(`Clutter${categoryName}`);
|
2021-09-29 14:09:19 -04:00
|
|
|
for (const flagName of this._getFlagNames(Clutter[categoryName])) {
|
|
|
|
if (props.exclude.includes(flagName))
|
|
|
|
continue;
|
|
|
|
this.add_child(new ClutterDebugFlag(categoryName, flagName));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Meta paint flags
|
|
|
|
this._addHeader('MetaDebugPaintFlag');
|
|
|
|
for (const flagName of this._getFlagNames(Meta.DebugPaintFlag))
|
|
|
|
this.add_child(new MutterPaintDebugFlag(flagName));
|
|
|
|
|
|
|
|
// Meta debug topics
|
|
|
|
this._addHeader('MetaDebugTopic');
|
|
|
|
for (const flagName of this._getFlagNames(Meta.DebugTopic))
|
|
|
|
this.add_child(new MutterTopicDebugFlag(flagName));
|
|
|
|
|
|
|
|
// MetaContext::unsafe-mode
|
|
|
|
this._addHeader('MetaContext');
|
|
|
|
this.add_child(new UnsafeModeDebugFlag());
|
|
|
|
}
|
|
|
|
|
|
|
|
_addHeader(title) {
|
|
|
|
const header = new St.Label({
|
|
|
|
text: title,
|
|
|
|
style_class: 'lg-debug-flags-header',
|
|
|
|
x_align: Clutter.ActorAlign.START,
|
|
|
|
});
|
|
|
|
this.add_child(header);
|
|
|
|
}
|
|
|
|
|
|
|
|
*_getFlagNames(enumObject) {
|
|
|
|
for (const flagName of Object.getOwnPropertyNames(enumObject)) {
|
|
|
|
if (typeof enumObject[flagName] !== 'number')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (enumObject[flagName] <= 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
yield flagName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2023-07-10 05:53:00 -04:00
|
|
|
export const LookingGlass = GObject.registerClass(
|
2019-07-16 05:24:13 -04:00
|
|
|
class LookingGlass extends St.BoxLayout {
|
|
|
|
_init() {
|
|
|
|
super._init({
|
|
|
|
name: 'LookingGlassDialog',
|
|
|
|
style_class: 'lg-dialog',
|
|
|
|
vertical: true,
|
|
|
|
visible: false,
|
2019-08-20 17:43:54 -04:00
|
|
|
reactive: true,
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|
2009-10-28 18:05:34 -04:00
|
|
|
|
2009-11-11 13:12:55 -05:00
|
|
|
this._borderPaintTarget = null;
|
2012-06-21 14:42:33 -04:00
|
|
|
this._redBorderEffect = new RedBorderEffect();
|
2009-11-11 13:12:55 -05:00
|
|
|
|
2009-08-02 03:46:01 -04:00
|
|
|
this._open = false;
|
|
|
|
|
2017-06-12 22:24:12 -04:00
|
|
|
this._it = null;
|
2009-08-02 03:46:01 -04:00
|
|
|
this._offset = 0;
|
|
|
|
|
2009-09-10 01:38:13 -04:00
|
|
|
// Sort of magic, but...eh.
|
|
|
|
this._maxItems = 150;
|
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
this._interfaceSettings = new Gio.Settings({schema_id: 'org.gnome.desktop.interface'});
|
2010-11-30 13:11:11 -05:00
|
|
|
this._interfaceSettings.connect('changed::monospace-font-name',
|
2023-08-06 19:45:22 -04:00
|
|
|
this._updateFont.bind(this));
|
2009-09-21 20:13:00 -04:00
|
|
|
this._updateFont();
|
|
|
|
|
2011-09-06 11:35:16 -04:00
|
|
|
// We want it to appear to slide out from underneath the panel
|
2019-07-16 05:24:13 -04:00
|
|
|
Main.uiGroup.add_actor(this);
|
|
|
|
Main.uiGroup.set_child_below_sibling(this,
|
2023-08-06 19:45:22 -04:00
|
|
|
Main.layoutManager.panelBox);
|
2020-05-09 15:37:18 -04:00
|
|
|
Main.layoutManager.panelBox.connect('notify::allocation',
|
2023-08-06 19:45:22 -04:00
|
|
|
this._queueResize.bind(this));
|
2020-05-09 15:37:18 -04:00
|
|
|
Main.layoutManager.keyboardBox.connect('notify::allocation',
|
2023-08-06 19:45:22 -04:00
|
|
|
this._queueResize.bind(this));
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2012-07-14 19:29:55 -04:00
|
|
|
this._objInspector = new ObjInspector(this);
|
2019-07-16 05:24:13 -04:00
|
|
|
Main.uiGroup.add_actor(this._objInspector);
|
|
|
|
this._objInspector.hide();
|
2010-05-15 12:43:56 -04:00
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
let toolbar = new St.BoxLayout({name: 'Toolbar'});
|
2019-07-16 05:24:13 -04:00
|
|
|
this.add_actor(toolbar);
|
2022-02-04 11:42:27 -05:00
|
|
|
const inspectButton = new St.Button({
|
|
|
|
style_class: 'lg-toolbar-button',
|
2022-03-21 11:44:24 -04:00
|
|
|
icon_name: 'find-location-symbolic',
|
2022-02-04 11:42:27 -05:00
|
|
|
});
|
|
|
|
toolbar.add_actor(inspectButton);
|
|
|
|
inspectButton.connect('clicked', () => {
|
2012-07-14 19:29:55 -04:00
|
|
|
let inspector = new Inspector(this);
|
2017-10-30 20:38:18 -04:00
|
|
|
inspector.connect('target', (i, target, stageX, stageY) => {
|
2022-02-07 09:14:06 -05:00
|
|
|
this._pushResult(`inspect(${Math.round(stageX)}, ${Math.round(stageY)})`, target);
|
2017-10-30 20:38:18 -04:00
|
|
|
});
|
|
|
|
inspector.connect('closed', () => {
|
2019-07-16 05:24:13 -04:00
|
|
|
this.show();
|
2009-08-02 03:46:01 -04:00
|
|
|
global.stage.set_key_focus(this._entry);
|
2017-10-30 20:38:18 -04:00
|
|
|
});
|
2019-07-16 05:24:13 -04:00
|
|
|
this.hide();
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_STOP;
|
2017-10-30 20:38:18 -04:00
|
|
|
});
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2022-02-04 11:42:27 -05:00
|
|
|
const gcButton = new St.Button({
|
|
|
|
style_class: 'lg-toolbar-button',
|
2022-03-21 11:44:24 -04:00
|
|
|
icon_name: 'user-trash-full-symbolic',
|
2022-02-04 11:42:27 -05:00
|
|
|
});
|
|
|
|
toolbar.add_actor(gcButton);
|
|
|
|
gcButton.connect('clicked', () => {
|
|
|
|
gcButton.child.icon_name = 'user-trash-symbolic';
|
2019-01-29 14:36:54 -05:00
|
|
|
System.gc();
|
2019-08-19 14:50:33 -04:00
|
|
|
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, () => {
|
2022-02-04 11:42:27 -05:00
|
|
|
gcButton.child.icon_name = 'user-trash-full-symbolic';
|
2014-04-10 15:08:49 -04:00
|
|
|
this._timeoutId = 0;
|
2013-11-28 19:45:39 -05:00
|
|
|
return GLib.SOURCE_REMOVE;
|
2019-01-29 14:36:54 -05:00
|
|
|
});
|
2021-06-13 11:36:50 -04:00
|
|
|
GLib.Source.set_name_by_id(
|
|
|
|
this._timeoutId,
|
2022-02-04 11:42:27 -05:00
|
|
|
'[gnome-shell] gcButton.child.icon_name = \'user-trash-full-symbolic\''
|
2021-06-13 11:36:50 -04:00
|
|
|
);
|
2019-01-29 14:36:54 -05:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2017-10-30 20:38:18 -04:00
|
|
|
});
|
2013-10-29 01:55:24 -04:00
|
|
|
|
2009-08-04 09:49:03 -04:00
|
|
|
let notebook = new Notebook();
|
2009-10-08 20:11:45 -04:00
|
|
|
this._notebook = notebook;
|
2019-10-21 14:44:00 -04:00
|
|
|
this.add_child(notebook);
|
2009-09-10 01:38:13 -04:00
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
let emptyBox = new St.Bin({x_expand: true});
|
2019-10-21 14:44:00 -04:00
|
|
|
toolbar.add_child(emptyBox);
|
2009-09-10 01:38:13 -04:00
|
|
|
toolbar.add_actor(notebook.tabControls);
|
2009-08-04 09:49:03 -04:00
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
this._evalBox = new St.BoxLayout({name: 'EvalBox', vertical: true});
|
2009-08-04 09:49:03 -04:00
|
|
|
notebook.appendPage('Evaluator', this._evalBox);
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2019-10-21 14:44:00 -04:00
|
|
|
this._resultsArea = new St.BoxLayout({
|
|
|
|
name: 'ResultsArea',
|
|
|
|
vertical: true,
|
|
|
|
y_expand: true,
|
|
|
|
});
|
|
|
|
this._evalBox.add_child(this._resultsArea);
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2019-10-21 14:44:00 -04:00
|
|
|
this._entryArea = new St.BoxLayout({
|
|
|
|
name: 'EntryArea',
|
|
|
|
y_align: Clutter.ActorAlign.END,
|
|
|
|
});
|
2011-10-29 04:20:49 -04:00
|
|
|
this._evalBox.add_actor(this._entryArea);
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
let label = new St.Label({text: CHEVRON});
|
2011-10-29 04:20:49 -04:00
|
|
|
this._entryArea.add(label);
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2019-10-21 14:44:00 -04:00
|
|
|
this._entry = new St.Entry({
|
|
|
|
can_focus: true,
|
|
|
|
x_expand: true,
|
|
|
|
});
|
2011-10-11 18:38:24 -04:00
|
|
|
ShellEntry.addContextMenu(this._entry);
|
2019-10-21 14:44:00 -04:00
|
|
|
this._entryArea.add_child(this._entry);
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2012-07-14 19:29:55 -04:00
|
|
|
this._windowList = new WindowList(this);
|
2019-07-16 05:24:13 -04:00
|
|
|
notebook.appendPage('Windows', this._windowList);
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2013-02-14 10:28:43 -05:00
|
|
|
this._extensions = new Extensions(this);
|
2019-07-16 05:24:13 -04:00
|
|
|
notebook.appendPage('Extensions', this._extensions);
|
2009-10-28 18:05:34 -04:00
|
|
|
|
2020-05-31 16:31:48 -04:00
|
|
|
this._actorTreeViewer = new ActorTreeViewer(this);
|
|
|
|
notebook.appendPage('Actors', this._actorTreeViewer);
|
|
|
|
|
2021-09-29 14:09:19 -04:00
|
|
|
this._debugFlags = new DebugFlags();
|
|
|
|
notebook.appendPage('Flags', this._debugFlags);
|
|
|
|
|
2019-01-31 09:08:10 -05:00
|
|
|
this._entry.clutter_text.connect('activate', (o, _e) => {
|
2011-10-29 04:20:49 -04:00
|
|
|
// Hide any completions we are currently showing
|
|
|
|
this._hideCompletions();
|
|
|
|
|
2009-08-02 03:46:01 -04:00
|
|
|
let text = o.get_text();
|
|
|
|
// Ensure we don't get newlines in the command; the history file is
|
|
|
|
// newline-separated.
|
2013-09-11 00:38:38 -04:00
|
|
|
text = text.replace('\n', ' ');
|
2023-07-12 15:40:05 -04:00
|
|
|
this._evaluate(text).catch(logError);
|
2009-08-02 03:46:01 -04:00
|
|
|
return true;
|
2017-10-30 20:38:18 -04:00
|
|
|
});
|
2011-02-13 11:43:32 -05:00
|
|
|
|
2020-03-29 17:51:13 -04:00
|
|
|
this._history = new History.HistoryManager({
|
|
|
|
gsettingsKey: HISTORY_KEY,
|
|
|
|
entry: this._entry.clutter_text,
|
|
|
|
});
|
2011-09-06 11:35:16 -04:00
|
|
|
|
2011-10-29 04:20:49 -04:00
|
|
|
this._autoComplete = new AutoComplete(this._entry);
|
2017-10-30 20:38:18 -04:00
|
|
|
this._autoComplete.connect('suggest', (a, e) => {
|
2011-10-29 04:20:49 -04:00
|
|
|
this._showCompletions(e.completions);
|
2017-10-30 20:38:18 -04:00
|
|
|
});
|
2011-10-29 04:20:49 -04:00
|
|
|
// If a completion is completed unambiguously, the currently-displayed completion
|
|
|
|
// suggestions become irrelevant.
|
2017-10-30 20:38:18 -04:00
|
|
|
this._autoComplete.connect('completion', (a, e) => {
|
2023-08-06 20:51:19 -04:00
|
|
|
if (e.type === 'whole-word')
|
2011-10-29 04:20:49 -04:00
|
|
|
this._hideCompletions();
|
2017-10-30 20:38:18 -04:00
|
|
|
});
|
2011-10-29 04:20:49 -04:00
|
|
|
|
2011-09-06 11:35:16 -04:00
|
|
|
this._resize();
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2022-04-06 06:51:45 -04:00
|
|
|
vfunc_captured_event(event) {
|
|
|
|
if (Main.keyboard.maybeHandleEvent(event))
|
|
|
|
return Clutter.EVENT_STOP;
|
|
|
|
|
|
|
|
return Clutter.EVENT_PROPAGATE;
|
|
|
|
}
|
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_updateFont() {
|
2010-11-30 13:11:11 -05:00
|
|
|
let fontName = this._interfaceSettings.get_string('monospace-font-name');
|
2013-02-07 06:01:29 -05:00
|
|
|
let fontDesc = Pango.FontDescription.from_string(fontName);
|
2009-09-21 20:13:00 -04:00
|
|
|
// We ignore everything but size and style; you'd be crazy to set your system-wide
|
|
|
|
// monospace font to be bold/oblique/etc. Could easily be added here.
|
2019-01-29 19:18:24 -05:00
|
|
|
let size = fontDesc.get_size() / 1024.;
|
|
|
|
let unit = fontDesc.get_size_is_absolute() ? 'px' : 'pt';
|
2022-02-07 09:14:06 -05:00
|
|
|
this.style = `
|
|
|
|
font-size: ${size}${unit};
|
|
|
|
font-family: "${fontDesc.get_family()}";`;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-09-21 20:13:00 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
setBorderPaintTarget(obj) {
|
2012-06-21 14:42:33 -04:00
|
|
|
if (this._borderPaintTarget != null)
|
|
|
|
this._borderPaintTarget.remove_effect(this._redBorderEffect);
|
|
|
|
this._borderPaintTarget = obj;
|
|
|
|
if (this._borderPaintTarget != null)
|
|
|
|
this._borderPaintTarget.add_effect(this._redBorderEffect);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2012-06-21 14:42:33 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_pushResult(command, obj) {
|
2019-05-20 17:25:14 -04:00
|
|
|
let index = this._resultsArea.get_n_children() + this._offset;
|
2012-07-14 19:29:55 -04:00
|
|
|
let result = new Result(this, CHEVRON + command, obj, index);
|
2019-07-16 05:24:13 -04:00
|
|
|
this._resultsArea.add(result);
|
2012-06-21 14:42:33 -04:00
|
|
|
if (obj instanceof Clutter.Actor)
|
2012-07-14 19:30:47 -04:00
|
|
|
this.setBorderPaintTarget(obj);
|
2012-06-21 14:42:33 -04:00
|
|
|
|
2019-05-20 17:25:14 -04:00
|
|
|
if (this._resultsArea.get_n_children() > this._maxItems) {
|
|
|
|
this._resultsArea.get_first_child().destroy();
|
2009-08-02 03:46:01 -04:00
|
|
|
this._offset++;
|
|
|
|
}
|
|
|
|
this._it = obj;
|
2009-10-08 20:11:45 -04:00
|
|
|
|
|
|
|
// Scroll to bottom
|
|
|
|
this._notebook.scrollToBottom(0);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_showCompletions(completions) {
|
2011-10-29 04:20:49 -04:00
|
|
|
if (!this._completionActor) {
|
2023-08-06 18:40:20 -04:00
|
|
|
this._completionActor = new St.Label({name: 'LookingGlassAutoCompletionText', style_class: 'lg-completions-text'});
|
2013-02-25 14:56:46 -05:00
|
|
|
this._completionActor.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
|
|
|
this._completionActor.clutter_text.line_wrap = true;
|
2012-02-13 15:27:16 -05:00
|
|
|
this._evalBox.insert_child_below(this._completionActor, this._entryArea);
|
2011-10-29 04:20:49 -04:00
|
|
|
}
|
|
|
|
|
2013-02-25 14:56:46 -05:00
|
|
|
this._completionActor.set_text(completions.join(', '));
|
2011-10-29 04:20:49 -04:00
|
|
|
|
|
|
|
// Setting the height to -1 allows us to get its actual preferred height rather than
|
2018-07-20 15:46:19 -04:00
|
|
|
// whatever was last set when animating
|
2011-10-29 04:20:49 -04:00
|
|
|
this._completionActor.set_height(-1);
|
2019-02-01 08:41:55 -05:00
|
|
|
let [, naturalHeight] = this._completionActor.get_preferred_height(this._resultsArea.get_width());
|
2011-10-29 04:20:49 -04:00
|
|
|
|
|
|
|
// Don't reanimate if we are already visible
|
|
|
|
if (this._completionActor.visible) {
|
|
|
|
this._completionActor.height = naturalHeight;
|
|
|
|
} else {
|
2019-07-25 06:50:26 -04:00
|
|
|
let settings = St.Settings.get();
|
2018-07-20 15:46:19 -04:00
|
|
|
let duration = AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / settings.slow_down_factor;
|
2011-10-29 04:20:49 -04:00
|
|
|
this._completionActor.show();
|
2018-07-20 15:46:19 -04:00
|
|
|
this._completionActor.remove_all_transitions();
|
|
|
|
this._completionActor.ease({
|
|
|
|
height: naturalHeight,
|
|
|
|
opacity: 255,
|
|
|
|
duration,
|
2019-08-20 17:43:54 -04:00
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
2018-07-20 15:46:19 -04:00
|
|
|
});
|
2011-10-29 04:20:49 -04:00
|
|
|
}
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-10-29 04:20:49 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_hideCompletions() {
|
2011-10-29 04:20:49 -04:00
|
|
|
if (this._completionActor) {
|
2019-07-25 06:50:26 -04:00
|
|
|
let settings = St.Settings.get();
|
2018-07-20 15:46:19 -04:00
|
|
|
let duration = AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / settings.slow_down_factor;
|
|
|
|
this._completionActor.remove_all_transitions();
|
|
|
|
this._completionActor.ease({
|
|
|
|
height: 0,
|
|
|
|
opacity: 0,
|
|
|
|
duration,
|
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
|
|
|
onComplete: () => {
|
|
|
|
this._completionActor.hide();
|
2019-08-20 17:43:54 -04:00
|
|
|
},
|
2018-07-20 15:46:19 -04:00
|
|
|
});
|
2011-10-29 04:20:49 -04:00
|
|
|
}
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-10-29 04:20:49 -04:00
|
|
|
|
2023-07-12 15:40:05 -04:00
|
|
|
async _evaluate(command) {
|
2021-02-11 13:44:03 -05:00
|
|
|
command = this._history.addItem(command); // trims command
|
|
|
|
if (!command)
|
|
|
|
return;
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2018-11-30 10:57:47 -05:00
|
|
|
let lines = command.split(';');
|
2022-02-07 09:14:06 -05:00
|
|
|
lines.push(`return ${lines.pop()}`);
|
2018-11-30 10:57:47 -05:00
|
|
|
|
|
|
|
let fullCmd = commandHeader + lines.join(';');
|
2009-08-02 03:46:01 -04:00
|
|
|
|
|
|
|
let resultObj;
|
|
|
|
try {
|
2023-07-12 15:40:05 -04:00
|
|
|
resultObj = await AsyncFunction(fullCmd)();
|
2009-08-02 03:46:01 -04:00
|
|
|
} catch (e) {
|
2022-02-07 09:14:06 -05:00
|
|
|
resultObj = `<exception ${e}>`;
|
2009-08-02 03:46:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
this._pushResult(command, resultObj);
|
|
|
|
this._entry.text = '';
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
inspect(x, y) {
|
2012-12-25 22:16:39 -05:00
|
|
|
return global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2012-12-25 22:16:39 -05:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
getIt() {
|
2009-08-02 03:46:01 -04:00
|
|
|
return this._it;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
getResult(idx) {
|
2019-05-20 17:27:48 -04:00
|
|
|
try {
|
2019-05-20 17:25:14 -04:00
|
|
|
return this._resultsArea.get_child_at_index(idx - this._offset).o;
|
2019-05-20 17:27:48 -04:00
|
|
|
} catch (e) {
|
2022-02-07 09:14:06 -05:00
|
|
|
throw new Error(`Unknown result at index ${idx}`);
|
2019-05-20 17:27:48 -04:00
|
|
|
}
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
toggle() {
|
2009-08-02 03:46:01 -04:00
|
|
|
if (this._open)
|
|
|
|
this.close();
|
|
|
|
else
|
|
|
|
this.open();
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_queueResize() {
|
2022-09-07 14:23:38 -04:00
|
|
|
const laters = global.compositor.get_laters();
|
|
|
|
laters.add(Meta.LaterType.BEFORE_REDRAW, () => {
|
2019-07-22 14:37:33 -04:00
|
|
|
this._resize();
|
|
|
|
return GLib.SOURCE_REMOVE;
|
|
|
|
});
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-09-06 11:35:16 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_resize() {
|
2011-06-13 09:54:05 -04:00
|
|
|
let primary = Main.layoutManager.primaryMonitor;
|
2009-08-25 15:23:53 -04:00
|
|
|
let myWidth = primary.width * 0.7;
|
2011-09-06 11:35:16 -04:00
|
|
|
let availableHeight = primary.height - Main.layoutManager.keyboardBox.height;
|
|
|
|
let myHeight = Math.min(primary.height * 0.7, availableHeight * 0.9);
|
2019-07-16 05:24:13 -04:00
|
|
|
this.x = primary.x + (primary.width - myWidth) / 2;
|
2015-02-14 10:51:20 -05:00
|
|
|
this._hiddenY = primary.y + Main.layoutManager.panelBox.height - myHeight;
|
2009-08-02 03:46:01 -04:00
|
|
|
this._targetY = this._hiddenY + myHeight;
|
2019-07-16 05:24:13 -04:00
|
|
|
this.y = this._hiddenY;
|
|
|
|
this.width = myWidth;
|
|
|
|
this.height = myHeight;
|
|
|
|
this._objInspector.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8));
|
2023-08-06 19:45:22 -04:00
|
|
|
this._objInspector.set_position(
|
|
|
|
this.x + Math.floor(myWidth * 0.1),
|
|
|
|
this._targetY + Math.floor(myHeight * 0.1));
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
insertObject(obj) {
|
2010-05-15 12:43:56 -04:00
|
|
|
this._pushResult('<insert>', obj);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2010-05-15 12:43:56 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
inspectObject(obj, sourceActor) {
|
2010-05-15 12:43:56 -04:00
|
|
|
this._objInspector.open(sourceActor);
|
|
|
|
this._objInspector.selectObject(obj);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2010-05-15 12:43:56 -04:00
|
|
|
|
2009-12-18 15:22:58 -05:00
|
|
|
// Handle key events which are relevant for all tabs of the LookingGlass
|
2023-08-08 12:14:04 -04:00
|
|
|
vfunc_key_press_event(event) {
|
|
|
|
let symbol = event.get_key_symbol();
|
2023-08-06 20:51:19 -04:00
|
|
|
if (symbol === Clutter.KEY_Escape) {
|
2022-04-18 11:23:45 -04:00
|
|
|
this.close();
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_STOP;
|
2009-12-18 15:22:58 -05:00
|
|
|
}
|
2011-10-21 01:23:08 -04:00
|
|
|
// Ctrl+PgUp and Ctrl+PgDown switches tabs in the notebook view
|
2023-08-08 12:14:04 -04:00
|
|
|
if (event.get_state() & Clutter.ModifierType.CONTROL_MASK) {
|
2023-08-06 20:51:19 -04:00
|
|
|
if (symbol === Clutter.KEY_Page_Up)
|
2011-10-21 01:23:08 -04:00
|
|
|
this._notebook.prevTab();
|
2023-08-06 20:51:19 -04:00
|
|
|
else if (symbol === Clutter.KEY_Page_Down)
|
2011-10-21 01:23:08 -04:00
|
|
|
this._notebook.nextTab();
|
|
|
|
}
|
2023-08-08 12:14:04 -04:00
|
|
|
return super.vfunc_key_press_event(event);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-12-18 15:22:58 -05:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
open() {
|
2009-08-02 03:46:01 -04:00
|
|
|
if (this._open)
|
|
|
|
return;
|
|
|
|
|
2023-08-06 18:40:20 -04:00
|
|
|
let grab = Main.pushModal(this, {actionMode: Shell.ActionMode.LOOKING_GLASS});
|
2022-04-30 02:18:39 -04:00
|
|
|
if (grab.get_seat_state() !== Clutter.GrabState.ALL) {
|
2021-11-25 04:49:42 -05:00
|
|
|
Main.popModal(grab);
|
2009-09-16 11:37:51 -04:00
|
|
|
return;
|
2021-11-25 04:49:42 -05:00
|
|
|
}
|
2009-09-16 11:37:51 -04:00
|
|
|
|
2021-11-25 04:49:42 -05:00
|
|
|
this._grab = grab;
|
2011-04-20 12:41:22 -04:00
|
|
|
this._notebook.selectIndex(0);
|
2019-07-16 05:24:13 -04:00
|
|
|
this.show();
|
2009-08-02 03:46:01 -04:00
|
|
|
this._open = true;
|
2011-02-13 11:43:32 -05:00
|
|
|
this._history.lastItem();
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2019-07-16 05:24:13 -04:00
|
|
|
this.remove_all_transitions();
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2010-11-09 14:37:32 -05:00
|
|
|
// We inverse compensate for the slow-down so you can change the factor
|
|
|
|
// through LookingGlass without long waits.
|
2018-07-20 15:46:19 -04:00
|
|
|
let duration = LG_ANIMATION_TIME / St.Settings.get().slow_down_factor;
|
2019-07-16 05:24:13 -04:00
|
|
|
this.ease({
|
2018-07-20 15:46:19 -04:00
|
|
|
y: this._targetY,
|
|
|
|
duration,
|
2019-08-20 17:43:54 -04:00
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
2018-07-20 15:46:19 -04:00
|
|
|
});
|
2019-09-12 14:45:04 -04:00
|
|
|
|
|
|
|
this._windowList.update();
|
2021-11-17 18:38:11 -05:00
|
|
|
this._entry.grab_key_focus();
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
close() {
|
2009-08-02 03:46:01 -04:00
|
|
|
if (!this._open)
|
|
|
|
return;
|
|
|
|
|
2019-07-16 05:24:13 -04:00
|
|
|
this._objInspector.hide();
|
2010-05-15 12:43:56 -04:00
|
|
|
|
2009-08-02 03:46:01 -04:00
|
|
|
this._open = false;
|
2019-07-16 05:24:13 -04:00
|
|
|
this.remove_all_transitions();
|
2009-08-02 03:46:01 -04:00
|
|
|
|
2012-07-14 19:30:47 -04:00
|
|
|
this.setBorderPaintTarget(null);
|
2009-11-11 13:12:55 -05:00
|
|
|
|
2019-07-25 06:50:26 -04:00
|
|
|
let settings = St.Settings.get();
|
2023-08-06 19:45:22 -04:00
|
|
|
let duration = Math.min(
|
|
|
|
LG_ANIMATION_TIME / settings.slow_down_factor,
|
|
|
|
LG_ANIMATION_TIME);
|
2019-07-16 05:24:13 -04:00
|
|
|
this.ease({
|
2018-07-20 15:46:19 -04:00
|
|
|
y: this._hiddenY,
|
|
|
|
duration,
|
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
2021-06-09 19:55:31 -04:00
|
|
|
onComplete: () => {
|
2021-11-25 04:49:42 -05:00
|
|
|
Main.popModal(this._grab);
|
|
|
|
this._grab = null;
|
2021-06-09 19:55:31 -04:00
|
|
|
this.hide();
|
|
|
|
},
|
2018-07-20 15:46:19 -04:00
|
|
|
});
|
2009-08-02 03:46:01 -04:00
|
|
|
}
|
2019-09-12 14:45:04 -04:00
|
|
|
|
|
|
|
get isOpen() {
|
|
|
|
return this._open;
|
|
|
|
}
|
2019-07-16 05:24:13 -04:00
|
|
|
});
|