/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const Clutter = imports.gi.Clutter; const Gio = imports.gi.Gio; const Pango = imports.gi.Pango; const St = imports.gi.St; const Shell = imports.gi.Shell; const Signals = imports.signals; const Lang = imports.lang; const Mainloop = imports.mainloop; const Gettext = imports.gettext.domain('gnome-shell'); const _ = Gettext.gettext; const ExtensionSystem = imports.ui.extensionSystem; const Link = imports.ui.link; const Tweener = imports.ui.tweener; const Main = imports.ui.main; /* Imports...feel free to add here as needed */ var commandHeader = "const Clutter = imports.gi.Clutter; " + "const GLib = imports.gi.GLib; " + "const Gtk = imports.gi.Gtk; " + "const Mainloop = imports.mainloop; " + "const Meta = imports.gi.Meta; " + "const Shell = imports.gi.Shell; " + "const Main = imports.ui.main; " + "const Lang = imports.lang; " + "const Tweener = imports.ui.tweener; " + /* Utility functions...we should probably be able to use these * in the shell core code too. */ "const stage = global.stage; " + "const color = function(pixel) { let c= new Clutter.Color(); c.from_pixel(pixel); return c; }; " + /* Special lookingGlass functions */ "const it = Main.lookingGlass.getIt(); " + "const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); "; function Notebook() { this._init(); } Notebook.prototype = { _init: function() { this.actor = new St.BoxLayout({ vertical: true }); this.tabControls = new St.BoxLayout({ style_class: "labels" }); this._selectedIndex = -1; this._tabs = []; }, appendPage: function(name, child) { let labelBox = new St.BoxLayout({ style_class: "notebook-tab" }); let label = new St.Button({ label: name }); label.connect('clicked', Lang.bind(this, function () { this.selectChild(child); return true; })); labelBox.add(label, { expand: true }); this.tabControls.add(labelBox); let scrollview = new St.ScrollView({ x_fill: true, y_fill: true }); scrollview.get_hscroll_bar().hide(); scrollview.add_actor(child); let tabData = { child: child, labelBox: labelBox, label: label, scrollView: scrollview, _scrollToBottom: false }; this._tabs.push(tabData); scrollview.hide(); this.actor.add(scrollview, { expand: true }); let vAdjust = scrollview.vscroll.adjustment; vAdjust.connect('changed', Lang.bind(this, function () { this._onAdjustScopeChanged(tabData); })); vAdjust.connect('notify::value', Lang.bind(this, function() { this._onAdjustValueChanged(tabData); })); if (this._selectedIndex == -1) this.selectIndex(0); }, _unselect: function() { if (this._selectedIndex < 0) return; let tabData = this._tabs[this._selectedIndex]; tabData.labelBox.remove_style_pseudo_class('selected'); tabData.scrollView.hide(); this._selectedIndex = -1; }, selectIndex: function(index) { if (index == this._selectedIndex) return; this._unselect(); if (index < 0) { this.emit('selection', null); return; } let tabData = this._tabs[index]; tabData.labelBox.add_style_pseudo_class('selected'); tabData.scrollView.show(); this._selectedIndex = index; this.emit('selection', tabData.child); }, selectChild: function(child) { if (child == null) this.selectIndex(-1); else { for (let i = 0; i < this._tabs.length; i++) { let tabData = this._tabs[i]; if (tabData.child == child) { this.selectIndex(i); return; } } } }, scrollToBottom: function(index) { let tabData = this._tabs[index]; tabData._scrollToBottom = true; }, _onAdjustValueChanged: function (tabData) { let vAdjust = tabData.scrollView.vscroll.adjustment; if (vAdjust.value < (vAdjust.upper - vAdjust.lower - 0.5)) tabData._scrolltoBottom = false; }, _onAdjustScopeChanged: function (tabData) { if (!tabData._scrollToBottom) return; let vAdjust = tabData.scrollView.vscroll.adjustment; vAdjust.value = vAdjust.upper - vAdjust.page_size; } }; Signals.addSignalMethods(Notebook.prototype); function Result(command, o, index) { this._init(command, o, index); } Result.prototype = { _init : function(command, o, index) { this.index = index; this.o = o; this.actor = new St.BoxLayout({ vertical: true }); let cmdTxt = new St.Label({ text: command }); cmdTxt.ellipsize = Pango.EllipsizeMode.END; this.actor.add(cmdTxt); let resultTxt = new St.Label({ text: "r(" + index + ") = " + o }); resultTxt.ellipsize = Pango.EllipsizeMode.END; this.actor.add(resultTxt); let line = new Clutter.Rectangle({ name: "Separator", height: 1 }); let padBin = new St.Bin({ name: "Separator", x_fill: true, y_fill: true }); padBin.add_actor(line); this.actor.add(padBin); } }; function ActorHierarchy() { this._init(); } ActorHierarchy.prototype = { _init : function () { this._previousTarget = null; this._target = null; this._parentList = []; this.actor = new St.BoxLayout({ name: "ActorHierarchy", vertical: true }); }, setTarget: function(actor) { this._previousTarget = this._target; this.target = actor; this.actor.get_children().forEach(function (child) { child.destroy(); }); if (!(actor instanceof Clutter.Actor)) return; if (this.target == null) return; this._parentList = []; let parent = actor; while ((parent = parent.get_parent()) != null) { this._parentList.push(parent); let link = new St.Label({ reactive: true, text: "" + parent }); this.actor.add_actor(link); let parentTarget = parent; link.connect('button-press-event', Lang.bind(this, function () { this._selectByActor(parentTarget); return true; })); } this.emit('selection', actor); }, _selectByActor: function(actor) { let idx = this._parentList.indexOf(actor); let children = this.actor.get_children(); let link = children[idx]; this.emit('selection', actor); } }; Signals.addSignalMethods(ActorHierarchy.prototype); function PropertyInspector() { this._init(); } PropertyInspector.prototype = { _init : function () { this._target = null; this._parentList = []; this.actor = new St.BoxLayout({ name: "PropertyInspector", vertical: true }); }, setTarget: function(actor) { this.target = actor; this.actor.get_children().forEach(function (child) { child.destroy(); }); for (let propName in actor) { let valueStr; try { valueStr = "" + actor[propName]; } catch (e) { valueStr = ''; } let propText = propName + ": " + valueStr; let propDisplay = new St.Label({ reactive: true, text: propText }); this.actor.add_actor(propDisplay); } } }; function Inspector() { this._init(); } Inspector.prototype = { _init: function() { let width = 150; let primary = global.get_primary_monitor(); let eventHandler = new St.BoxLayout({ name: "LookingGlassDialog", vertical: false, y: primary.y + Math.floor(primary.height / 2), reactive: true }); eventHandler.connect('notify::allocation', Lang.bind(this, function () { eventHandler.x = primary.x + Math.floor((primary.width - eventHandler.width) / 2); })); global.stage.add_actor(eventHandler); let displayText = new St.Label(); eventHandler.add(displayText, { expand: true }); let borderPaintTarget = null; let borderPaintId = null; eventHandler.connect('destroy', Lang.bind(this, function() { if (borderPaintTarget != null) borderPaintTarget.disconnect(borderPaintId); })); eventHandler.connect('button-press-event', Lang.bind(this, function (actor, event) { Clutter.ungrab_pointer(eventHandler); let [stageX, stageY] = event.get_coords(); let target = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, stageX, stageY); this.emit('target', target, stageX, stageY); eventHandler.destroy(); this.emit('closed'); return true; })); eventHandler.connect('motion-event', Lang.bind(this, function (actor, event) { let [stageX, stageY] = event.get_coords(); let target = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, stageX, stageY); let id, style_class; if (target instanceof St.Widget) { id = target.get_theme_node().get_element_id(); style_class = target.get_theme_node().get_element_class(); } let position = ''; let style = '