/* -*- 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 WindowList() { this._init(); } WindowList.prototype = { _init : function () { this.actor = new St.BoxLayout({ name: 'Windows', vertical: true, style: 'spacing: 8px' }); let display = global.screen.get_display(); let tracker = Shell.WindowTracker.get_default(); this._updateId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._updateWindowList)); display.connect('window-created', Lang.bind(this, this._updateWindowList)); tracker.connect('tracked-windows-changed', Lang.bind(this, this._updateWindowList)); }, _updateWindowList: function() { this.actor.get_children().forEach(function (actor) { actor.destroy(); }); let windows = global.get_windows(); let tracker = Shell.WindowTracker.get_default(); for (let i = 0; i < windows.length; i++) { let metaWindow = windows[i].metaWindow; metaWindow.connect('unmanaged', Lang.bind(this, this._updateWindowList)); let box = new St.BoxLayout({ vertical: true }); this.actor.add(box); let label = new Link.Link({ label: metaWindow.title, x_align: St.Align.START }); label.actor.connect('clicked', Lang.bind(this, function () { this.emit('selected', metaWindow); })); box.add(label.actor); let propsBox = new St.BoxLayout({ vertical: true, style: 'padding-left: 6px;' }); box.add(propsBox); propsBox.add(new St.Label({ text: 'wmclass: ' + metaWindow.get_wm_class() })); let app = tracker.get_window_app(metaWindow); if (app != null && !app.is_transient()) { let icon = app.create_icon_texture(22); let propBox = new St.BoxLayout({ style: 'spacing: 6px; ' }); propsBox.add(propBox); propBox.add(new St.Label({ text: 'app: ' + app.get_id() }), { y_align: St.Align.MIDDLE }); propBox.add(icon, { y_align: St.Align.MIDDLE }); } else { propsBox.add(new St.Label({ text: '' })); } } } }; Signals.addSignalMethods(WindowList.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); })); Main.uiGroup.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 = '