lookingGlass: Add switches for debug flags
This adds a new "Flags" tab to looking glass where several debug flags can be toggled at run time. This includes: ClutterDebugFlags ClutterDrawDebugFlags MetaDebugPaintFlags MetaDebugTopics MetaContext::unsafe-mode Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3968 Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1994>
This commit is contained in:
parent
828da18b72
commit
ac4412e4aa
@ -106,4 +106,18 @@ $text_fg_color: #ccc;
|
|||||||
border: 1px solid $osd_borders_color;
|
border: 1px solid $osd_borders_color;
|
||||||
border-radius: $base_border_radius;
|
border-radius: $base_border_radius;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lg-debug-flag-button {
|
||||||
|
StLabel { padding: $base_spacing, 2 * $base_spacing; }
|
||||||
|
|
||||||
|
color: $text_fg_color;
|
||||||
|
&:hover { color: lighten($text_fg_color, 20%); }
|
||||||
|
&:active { color: darken($text_fg_color, 20%); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-debug-flags-header {
|
||||||
|
padding-top: 2 * $base_spacing;
|
||||||
|
font-size: 120%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
@ -8,6 +8,7 @@ const System = imports.system;
|
|||||||
|
|
||||||
const History = imports.misc.history;
|
const History = imports.misc.history;
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const JsParse = imports.misc.jsParse;
|
const JsParse = imports.misc.jsParse;
|
||||||
@ -35,6 +36,15 @@ var AUTO_COMPLETE_GLOBAL_KEYWORDS = _getAutoCompleteGlobalKeywords();
|
|||||||
|
|
||||||
const LG_ANIMATION_TIME = 500;
|
const LG_ANIMATION_TIME = 500;
|
||||||
|
|
||||||
|
const CLUTTER_DEBUG_FLAG_CATEGORIES = new Map([
|
||||||
|
// Paint debugging can easily result in a non-responsive session
|
||||||
|
['DebugFlag', { argPos: 0, exclude: ['PAINT'] }],
|
||||||
|
['DrawDebugFlag', { argPos: 1, exclude: [] }],
|
||||||
|
// Exluded due to the only current option likely to result in shooting ones
|
||||||
|
// foot
|
||||||
|
// ['PickDebugFlag', { argPos: 2, exclude: [] }],
|
||||||
|
]);
|
||||||
|
|
||||||
function _getAutoCompleteGlobalKeywords() {
|
function _getAutoCompleteGlobalKeywords() {
|
||||||
const keywords = ['true', 'false', 'null', 'new'];
|
const keywords = ['true', 'false', 'null', 'new'];
|
||||||
// Don't add the private properties of globalThis (i.e., ones starting with '_')
|
// Don't add the private properties of globalThis (i.e., ones starting with '_')
|
||||||
@ -1003,6 +1013,218 @@ class ActorTreeViewer extends St.BoxLayout {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var DebugFlag = GObject.registerClass({
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var ClutterDebugFlag = GObject.registerClass(
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var MutterPaintDebugFlag = GObject.registerClass(
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var MutterTopicDebugFlag = GObject.registerClass(
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var UnsafeModeDebugFlag = GObject.registerClass(
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var DebugFlags = GObject.registerClass(
|
||||||
|
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()) {
|
||||||
|
this._addHeader('Clutter%s'.format(categoryName));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
var LookingGlass = GObject.registerClass(
|
var LookingGlass = GObject.registerClass(
|
||||||
class LookingGlass extends St.BoxLayout {
|
class LookingGlass extends St.BoxLayout {
|
||||||
_init() {
|
_init() {
|
||||||
@ -1124,6 +1346,9 @@ class LookingGlass extends St.BoxLayout {
|
|||||||
this._actorTreeViewer = new ActorTreeViewer(this);
|
this._actorTreeViewer = new ActorTreeViewer(this);
|
||||||
notebook.appendPage('Actors', this._actorTreeViewer);
|
notebook.appendPage('Actors', this._actorTreeViewer);
|
||||||
|
|
||||||
|
this._debugFlags = new DebugFlags();
|
||||||
|
notebook.appendPage('Flags', this._debugFlags);
|
||||||
|
|
||||||
this._entry.clutter_text.connect('activate', (o, _e) => {
|
this._entry.clutter_text.connect('activate', (o, _e) => {
|
||||||
// Hide any completions we are currently showing
|
// Hide any completions we are currently showing
|
||||||
this._hideCompletions();
|
this._hideCompletions();
|
||||||
|
Loading…
Reference in New Issue
Block a user