648 lines
22 KiB
JavaScript
648 lines
22 KiB
JavaScript
const Clutter = imports.gi.Clutter;
|
|
const Gtk = imports.gi.Gtk;
|
|
const Meta = imports.gi.Meta;
|
|
const Shell = imports.gi.Shell;
|
|
const St = imports.gi.St;
|
|
|
|
const Hash = imports.misc.hash;
|
|
const Lang = imports.lang;
|
|
const Main = imports.ui.main;
|
|
const MessageTray = imports.ui.messageTray;
|
|
const PopupMenu = imports.ui.popupMenu;
|
|
|
|
const ExtensionUtils = imports.misc.extensionUtils;
|
|
const Me = ExtensionUtils.getCurrentExtension();
|
|
const Convenience = Me.imports.convenience;
|
|
|
|
const GroupingMode = {
|
|
NEVER: 0,
|
|
ALWAYS: 1
|
|
};
|
|
|
|
|
|
function _minimizeOrActivateWindow(window) {
|
|
let focusWindow = global.display.focus_window;
|
|
if (focusWindow == window ||
|
|
focusWindow && focusWindow.get_transient_for() == window)
|
|
window.minimize();
|
|
else
|
|
window.activate(global.get_current_time());
|
|
}
|
|
|
|
|
|
const WindowTitle = new Lang.Class({
|
|
Name: 'WindowTitle',
|
|
|
|
_init: function(metaWindow) {
|
|
this._metaWindow = metaWindow;
|
|
this.actor = new St.BoxLayout();
|
|
|
|
let textureCache = St.TextureCache.get_default();
|
|
let icon = textureCache.bind_pixbuf_property(this._metaWindow, "icon");
|
|
this._icon = new St.Bin({ style_class: 'window-button-icon',
|
|
child: icon });
|
|
this.actor.add(this._icon);
|
|
this._label = new St.Label();
|
|
this.actor.add(this._label);
|
|
|
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
|
|
|
this._notifyTitleId =
|
|
this._metaWindow.connect('notify::title',
|
|
Lang.bind(this, this._updateTitle));
|
|
this._notifyMinimizedId =
|
|
this._metaWindow.connect('notify::minimized',
|
|
Lang.bind(this, this._minimizedChanged));
|
|
this._minimizedChanged();
|
|
},
|
|
|
|
_minimizedChanged: function() {
|
|
this._icon.opacity = this._metaWindow.minimized ? 128 : 255;
|
|
this._updateTitle();
|
|
},
|
|
|
|
_updateTitle: function() {
|
|
if (this._metaWindow.minimized)
|
|
this._label.text = '[%s]'.format(this._metaWindow.title);
|
|
else
|
|
this._label.text = this._metaWindow.title;
|
|
},
|
|
|
|
_onDestroy: function() {
|
|
this._metaWindow.disconnect(this._notifyTitleId);
|
|
this._metaWindow.disconnect(this._notifyMinimizedId);
|
|
}
|
|
});
|
|
|
|
|
|
const WindowButton = new Lang.Class({
|
|
Name: 'WindowButton',
|
|
|
|
_init: function(metaWindow) {
|
|
this.metaWindow = metaWindow;
|
|
|
|
this._windowTitle = new WindowTitle(this.metaWindow);
|
|
this.actor = new St.Button({ style_class: 'window-button',
|
|
x_fill: true,
|
|
can_focus: true,
|
|
child: this._windowTitle.actor });
|
|
this.actor._delegate = this;
|
|
|
|
this.actor.connect('allocation-changed',
|
|
Lang.bind(this, this._updateIconGeometry));
|
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
|
|
|
this._switchWorkspaceId =
|
|
global.window_manager.connect('switch-workspace',
|
|
Lang.bind(this, this._updateVisibility));
|
|
this._updateVisibility();
|
|
|
|
this._notifyFocusId =
|
|
global.display.connect('notify::focus-window',
|
|
Lang.bind(this, this._updateStyle));
|
|
this._updateStyle();
|
|
},
|
|
|
|
_onClicked: function() {
|
|
_minimizeOrActivateWindow(this.metaWindow);
|
|
},
|
|
|
|
_updateStyle: function() {
|
|
if (this.metaWindow.minimized)
|
|
this.actor.add_style_class_name('minimized');
|
|
else
|
|
this.actor.remove_style_class_name('minimized');
|
|
|
|
if (global.display.focus_window == this.metaWindow)
|
|
this.actor.add_style_class_name('focused');
|
|
else
|
|
this.actor.remove_style_class_name('focused');
|
|
},
|
|
|
|
_updateVisibility: function() {
|
|
let workspace = global.screen.get_active_workspace();
|
|
this.actor.visible = this.metaWindow.located_on_workspace(workspace);
|
|
},
|
|
|
|
_updateIconGeometry: function() {
|
|
let rect = new Meta.Rectangle();
|
|
|
|
[rect.x, rect.y] = this.actor.get_transformed_position();
|
|
[rect.width, rect.height] = this.actor.get_transformed_size();
|
|
|
|
this.metaWindow.set_icon_geometry(rect);
|
|
},
|
|
|
|
_onDestroy: function() {
|
|
global.window_manager.disconnect(this._switchWorkspaceId);
|
|
global.display.disconnect(this._notifyFocusId);
|
|
}
|
|
});
|
|
|
|
|
|
const AppButton = new Lang.Class({
|
|
Name: 'AppButton',
|
|
|
|
_init: function(app) {
|
|
this.app = app;
|
|
|
|
let stack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
|
this.actor = new St.Button({ style_class: 'window-button',
|
|
x_fill: true,
|
|
can_focus: true,
|
|
child: stack });
|
|
this.actor._delegate = this;
|
|
|
|
this.actor.connect('allocation-changed',
|
|
Lang.bind(this, this._updateIconGeometry));
|
|
|
|
this._singleWindowTitle = new St.Bin({ x_expand: true,
|
|
x_align: St.Align.START });
|
|
stack.add_actor(this._singleWindowTitle);
|
|
|
|
this._multiWindowTitle = new St.BoxLayout({ x_expand: true });
|
|
stack.add_actor(this._multiWindowTitle);
|
|
|
|
let icon = new St.Bin({ style_class: 'window-button-icon',
|
|
child: app.create_icon_texture(24) });
|
|
this._multiWindowTitle.add(icon);
|
|
this._multiWindowTitle.add(new St.Label({ text: app.get_name() }));
|
|
|
|
this._menuManager = new PopupMenu.PopupMenuManager(this);
|
|
this._menu = new PopupMenu.PopupMenu(this.actor, 0.5, St.Side.BOTTOM);
|
|
this._menu.actor.hide();
|
|
this._menu.connect('activate', Lang.bind(this, this._onMenuActivate));
|
|
this._menuManager.addMenu(this._menu);
|
|
Main.uiGroup.add_actor(this._menu.actor);
|
|
|
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
|
|
|
this._switchWorkspaceId =
|
|
global.window_manager.connect('switch-workspace',
|
|
Lang.bind(this, this._updateVisibility));
|
|
this._updateVisibility();
|
|
|
|
this._windowsChangedId =
|
|
this.app.connect('windows-changed',
|
|
Lang.bind(this, this._windowsChanged));
|
|
this._windowsChanged();
|
|
|
|
this._windowTracker = Shell.WindowTracker.get_default();
|
|
this._notifyFocusId =
|
|
this._windowTracker.connect('notify::focus-app',
|
|
Lang.bind(this, this._updateStyle));
|
|
this._updateStyle();
|
|
},
|
|
|
|
_updateVisibility: function() {
|
|
let workspace = global.screen.get_active_workspace();
|
|
this.actor.visible = this.app.is_on_workspace(workspace);
|
|
},
|
|
|
|
_updateStyle: function() {
|
|
if (this._windowTracker.focus_app == this.app)
|
|
this.actor.add_style_class_name('focused');
|
|
else
|
|
this.actor.remove_style_class_name('focused');
|
|
},
|
|
|
|
_updateIconGeometry: function() {
|
|
let rect = new Meta.Rectangle();
|
|
|
|
[rect.x, rect.y] = this.actor.get_transformed_position();
|
|
[rect.width, rect.height] = this.actor.get_transformed_size();
|
|
|
|
let windows = this.app.get_windows();
|
|
windows.forEach(function(w) {
|
|
w.set_icon_geometry(rect);
|
|
});
|
|
},
|
|
|
|
|
|
_getWindowList: function() {
|
|
let workspace = global.screen.get_active_workspace();
|
|
return this.app.get_windows().filter(function(win) {
|
|
return win.located_on_workspace(workspace);
|
|
});
|
|
},
|
|
|
|
_windowsChanged: function() {
|
|
let windows = this._getWindowList();
|
|
this._singleWindowTitle.visible = windows.length == 1;
|
|
this._multiWindowTitle.visible = !this._singleWindowTitle.visible;
|
|
|
|
if (this._singleWindowTitle.visible) {
|
|
if (!this._windowTitle) {
|
|
this._windowTitle = new WindowTitle(windows[0]);
|
|
this._singleWindowTitle.child = this._windowTitle.actor;
|
|
}
|
|
} else {
|
|
if (this._windowTitle) {
|
|
this._singleWindowTitle.child = null;
|
|
this._windowTitle = null;
|
|
}
|
|
}
|
|
},
|
|
|
|
_onClicked: function() {
|
|
if (this._menu.isOpen) {
|
|
this._menu.close();
|
|
return;
|
|
}
|
|
|
|
let windows = this._getWindowList();
|
|
if (windows.length == 1) {
|
|
_minimizeOrActivateWindow(windows[0]);
|
|
} else {
|
|
this._menu.removeAll();
|
|
|
|
for (let i = 0; i < windows.length; i++) {
|
|
let windowTitle = new WindowTitle(windows[i]);
|
|
let item = new PopupMenu.PopupBaseMenuItem();
|
|
item.addActor(windowTitle.actor);
|
|
item._window = windows[i];
|
|
this._menu.addMenuItem(item);
|
|
}
|
|
this._menu.open();
|
|
|
|
let event = Clutter.get_current_event();
|
|
if (event && event.type() == Clutter.EventType.KEY_RELEASE)
|
|
this._menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
|
}
|
|
},
|
|
|
|
_onMenuActivate: function(menu, child) {
|
|
child._window.activate(global.get_current_time());
|
|
},
|
|
|
|
_onDestroy: function() {
|
|
global.window_manager.disconnect(this._switchWorkspaceId);
|
|
this._windowTracker.disconnect(this._notifyFocusId);
|
|
this.app.disconnect(this._windowsChangedId);
|
|
this._menu.actor.destroy();
|
|
}
|
|
});
|
|
|
|
|
|
const TrayButton = new Lang.Class({
|
|
Name: 'TrayButton',
|
|
|
|
_init: function() {
|
|
this._counterLabel = new St.Label({ x_align: Clutter.ActorAlign.CENTER,
|
|
x_expand: true,
|
|
y_align: Clutter.ActorAlign.CENTER,
|
|
y_expand: true });
|
|
this.actor = new St.Button({ style_class: 'summary-source-counter',
|
|
child: this._counterLabel,
|
|
layoutManager: new Clutter.BinLayout() });
|
|
this.actor.set_x_align(Clutter.ActorAlign.END);
|
|
this.actor.set_x_expand(true);
|
|
this.actor.set_y_expand(true);
|
|
|
|
this.actor.connect('clicked', Lang.bind(this,
|
|
function() {
|
|
if (Main.messageTray._trayState == MessageTray.State.HIDDEN)
|
|
Main.messageTray.toggle();
|
|
}));
|
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
|
|
|
this._trayItemCount = 0;
|
|
Main.messageTray.getSources().forEach(Lang.bind(this,
|
|
function(source) {
|
|
this._sourceAdded(Main.messageTray, source);
|
|
}));
|
|
this._sourceAddedId =
|
|
Main.messageTray.connect('source-added',
|
|
Lang.bind(this, this._sourceAdded));
|
|
this._sourceRemovedId =
|
|
Main.messageTray.connect('source-removed',
|
|
Lang.bind(this, this._sourceRemoved));
|
|
this._updateVisibility();
|
|
},
|
|
|
|
_sourceAdded: function(tray, source) {
|
|
this._trayItemCount++;
|
|
this._updateVisibility();
|
|
},
|
|
|
|
_sourceRemoved: function(source) {
|
|
this._trayItemCount--;
|
|
this.actor.checked = false;
|
|
this._updateVisibility();
|
|
},
|
|
|
|
_updateVisibility: function() {
|
|
this._counterLabel.text = this._trayItemCount.toString();
|
|
this.actor.visible = this._trayItemCount > 0;
|
|
},
|
|
|
|
_onDestroy: function() {
|
|
Main.messageTray.getSources().forEach(Lang.bind(this,
|
|
function(source) {
|
|
if (!source._windowListDestroyId)
|
|
return;
|
|
source.disconnect(source._windowListDestroyId)
|
|
delete source._windowListDestroyId;
|
|
}));
|
|
Main.messageTray.disconnect(this._sourceAddedId);
|
|
Main.messageTray.disconnect(this._sourceRemovedId);
|
|
}
|
|
});
|
|
|
|
|
|
const WindowList = new Lang.Class({
|
|
Name: 'WindowList',
|
|
|
|
_init: function() {
|
|
this.actor = new St.Widget({ name: 'panel',
|
|
style_class: 'bottom-panel',
|
|
reactive: true,
|
|
track_hover: true,
|
|
layout_manager: new Clutter.BinLayout()});
|
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
|
|
|
let box = new St.BoxLayout({ x_expand: true, y_expand: true });
|
|
this.actor.add_actor(box);
|
|
|
|
let layout = new Clutter.BoxLayout({ homogeneous: true });
|
|
this._windowList = new St.Widget({ style_class: 'window-list',
|
|
layout_manager: layout,
|
|
x_align: Clutter.ActorAlign.START,
|
|
x_expand: true,
|
|
y_expand: true });
|
|
box.add(this._windowList, { expand: true });
|
|
|
|
this._windowList.connect('style-changed', Lang.bind(this,
|
|
function() {
|
|
let node = this._windowList.get_theme_node();
|
|
let spacing = node.get_length('spacing');
|
|
this._windowList.layout_manager.spacing = spacing;
|
|
}));
|
|
|
|
this._trayButton = new TrayButton();
|
|
box.add(this._trayButton.actor);
|
|
|
|
Main.layoutManager.addChrome(this.actor, { affectsStruts: true,
|
|
trackFullscreen: true });
|
|
Main.ctrlAltTabManager.addGroup(this.actor, _('Window List'), 'start-here-symbolic');
|
|
|
|
this._appSystem = Shell.AppSystem.get_default();
|
|
this._appStateChangedId =
|
|
this._appSystem.connect('app-state-changed',
|
|
Lang.bind(this, this._onAppStateChanged));
|
|
|
|
this._monitorsChangedId =
|
|
Main.layoutManager.connect('monitors-changed',
|
|
Lang.bind(this, this._updatePosition));
|
|
this._updatePosition();
|
|
|
|
this._keyboardVisiblechangedId =
|
|
Main.layoutManager.connect('keyboard-visible-changed',
|
|
Lang.bind(this, function(o, state) {
|
|
Main.layoutManager.keyboardBox.visible = state;
|
|
Main.uiGroup.set_child_above_sibling(windowList.actor,
|
|
Main.layoutManager.keyboardBox);
|
|
this._updateKeyboardAnchor();
|
|
}));
|
|
|
|
this._workspaceSignals = new Hash.Map();
|
|
this._nWorkspacesChangedId =
|
|
global.screen.connect('notify::n-workspaces',
|
|
Lang.bind(this, this._onWorkspacesChanged));
|
|
this._onWorkspacesChanged();
|
|
|
|
this._overviewShowingId =
|
|
Main.overview.connect('showing', Lang.bind(this, function() {
|
|
this.actor.hide();
|
|
this._updateKeyboardAnchor();
|
|
}));
|
|
|
|
this._overviewHidingId =
|
|
Main.overview.connect('hiding', Lang.bind(this, function() {
|
|
this.actor.show();
|
|
this._updateKeyboardAnchor();
|
|
}));
|
|
|
|
this._settings = Convenience.getSettings();
|
|
this._groupingModeChangedId =
|
|
this._settings.connect('changed::grouping-mode',
|
|
Lang.bind(this, this._groupingModeChanged));
|
|
this._groupingModeChanged();
|
|
},
|
|
|
|
_groupingModeChanged: function() {
|
|
this._groupingMode = this._settings.get_enum('grouping-mode');
|
|
this._populateWindowList();
|
|
},
|
|
|
|
_populateWindowList: function() {
|
|
this._windowList.destroy_all_children();
|
|
|
|
if (this._groupingMode == GroupingMode.NEVER) {
|
|
let windows = Meta.get_window_actors(global.screen);
|
|
for (let i = 0; i < windows.length; i++)
|
|
this._onWindowAdded(null, windows[i].metaWindow);
|
|
} else {
|
|
let apps = this._appSystem.get_running();
|
|
for (let i = 0; i < apps.length; i++)
|
|
this._addApp(apps[i]);
|
|
}
|
|
},
|
|
|
|
_updatePosition: function() {
|
|
let monitor = Main.layoutManager.primaryMonitor;
|
|
this.actor.width = monitor.width;
|
|
this.actor.set_position(monitor.x, monitor.y + monitor.height - this.actor.height);
|
|
},
|
|
|
|
_updateKeyboardAnchor: function() {
|
|
if (!Main.keyboard.actor)
|
|
return;
|
|
|
|
let anchorY = Main.overview.visible ? 0 : this.actor.height;
|
|
Main.keyboard.actor.anchor_y = anchorY;
|
|
},
|
|
|
|
_onAppStateChanged: function(appSys, app) {
|
|
if (this._groupingMode != GroupingMode.ALWAYS)
|
|
return;
|
|
|
|
if (app.state == Shell.AppState.RUNNING)
|
|
this._addApp(app);
|
|
else if (app.state == Shell.AppState.STOPPED)
|
|
this._removeApp(app);
|
|
},
|
|
|
|
_addApp: function(app) {
|
|
let button = new AppButton(app);
|
|
this._windowList.layout_manager.pack(button.actor,
|
|
true, true, true,
|
|
Clutter.BoxAlignment.START,
|
|
Clutter.BoxAlignment.START);
|
|
},
|
|
|
|
_removeApp: function(app) {
|
|
let children = this._windowList.get_children();
|
|
for (let i = 0; i < children.length; i++) {
|
|
if (children[i]._delegate.app == app) {
|
|
children[i].destroy();
|
|
return;
|
|
}
|
|
}
|
|
},
|
|
|
|
_onWindowAdded: function(ws, win) {
|
|
if (!Shell.WindowTracker.get_default().is_window_interesting(win))
|
|
return;
|
|
|
|
if (this._groupingMode != GroupingMode.NEVER)
|
|
return;
|
|
|
|
let button = new WindowButton(win);
|
|
this._windowList.layout_manager.pack(button.actor,
|
|
true, true, true,
|
|
Clutter.BoxAlignment.START,
|
|
Clutter.BoxAlignment.START);
|
|
},
|
|
|
|
_onWindowRemoved: function(ws, win) {
|
|
if (this._groupingMode != GroupingMode.NEVER)
|
|
return;
|
|
|
|
let children = this._windowList.get_children();
|
|
for (let i = 0; i < children.length; i++) {
|
|
if (children[i]._delegate.metaWindow == win) {
|
|
children[i].destroy();
|
|
return;
|
|
}
|
|
}
|
|
},
|
|
|
|
_onWorkspacesChanged: function() {
|
|
let numWorkspaces = global.screen.n_workspaces;
|
|
for (let i = 0; i < numWorkspaces; i++) {
|
|
let workspace = global.screen.get_workspace_by_index(i);
|
|
if (this._workspaceSignals.has(workspace))
|
|
continue;
|
|
|
|
let signals = { windowAddedId: 0, windowRemovedId: 0 };
|
|
signals._windowAddedId =
|
|
workspace.connect('window-added',
|
|
Lang.bind(this, this._onWindowAdded));
|
|
signals._windowRemovedId =
|
|
workspace.connect('window-removed',
|
|
Lang.bind(this, this._onWindowRemoved));
|
|
this._workspaceSignals.set(workspace, signals);
|
|
}
|
|
},
|
|
|
|
_disconnectWorkspaceSignals: function() {
|
|
let numWorkspaces = global.screen.n_workspaces;
|
|
for (let i = 0; i < numWorkspaces; i++) {
|
|
let workspace = global.screen.get_workspace_by_index(i);
|
|
let signals = this._workspaceSignals.delete(workspace)[1];
|
|
workspace.disconnect(signals._windowAddedId);
|
|
workspace.disconnect(signals._windowRemovedId);
|
|
}
|
|
},
|
|
|
|
_onDestroy: function() {
|
|
|
|
Main.ctrlAltTabManager.removeGroup(this.actor);
|
|
|
|
this._appSystem.disconnect(this._appStateChangedId);
|
|
this._appStateChangedId = 0;
|
|
|
|
Main.layoutManager.disconnect(this._monitorsChangedId);
|
|
this._monitorsChangedId = 0;
|
|
|
|
Main.layoutManager.disconnect(this._keyboardVisiblechangedId);
|
|
this._keyboardVisiblechangedId = 0;
|
|
|
|
Main.layoutManager.hideKeyboard();
|
|
|
|
this._disconnectWorkspaceSignals();
|
|
global.screen.disconnect(this._nWorkspacesChangedId);
|
|
this._nWorkspacesChangedId = 0;
|
|
|
|
Main.overview.disconnect(this._overviewShowingId);
|
|
Main.overview.disconnect(this._overviewHidingId);
|
|
|
|
this._settings.disconnect(this._groupingModeChangedId);
|
|
|
|
let windows = Meta.get_window_actors(global.screen);
|
|
for (let i = 0; i < windows.length; i++)
|
|
windows[i].metaWindow.set_icon_geometry(null);
|
|
}
|
|
});
|
|
|
|
let windowList;
|
|
let injections = {};
|
|
let notificationParent;
|
|
|
|
function init() {
|
|
}
|
|
|
|
function enable() {
|
|
windowList = new WindowList();
|
|
|
|
windowList.actor.connect('notify::hover', Lang.bind(Main.messageTray,
|
|
function() {
|
|
this._pointerInTray = windowList.actor.hover;
|
|
this._updateState();
|
|
}));
|
|
|
|
injections['_trayDwellTimeout'] = MessageTray.MessageTray.prototype._trayDwellTimeout;
|
|
MessageTray.MessageTray.prototype._trayDwellTimeout = function() {
|
|
return false;
|
|
};
|
|
|
|
injections['_tween'] = MessageTray.MessageTray.prototype._tween;
|
|
MessageTray.MessageTray.prototype._tween = function(actor, statevar, value, params) {
|
|
if (!Main.overview.visible) {
|
|
let anchorY;
|
|
if (statevar == '_trayState')
|
|
anchorY = windowList.actor.height;
|
|
else if (statevar == '_notificationState')
|
|
anchorY = -windowList.actor.height;
|
|
else
|
|
anchorY = 0;
|
|
actor.anchor_y = anchorY;
|
|
}
|
|
injections['_tween'].call(Main.messageTray, actor, statevar, value, params);
|
|
};
|
|
injections['_onTrayHidden'] = MessageTray.MessageTray.prototype._onTrayHidden;
|
|
MessageTray.MessageTray.prototype._onTrayHidden = function() {
|
|
this.actor.anchor_y = 0;
|
|
injections['_onTrayHidden'].call(Main.messageTray);
|
|
};
|
|
|
|
notificationParent = Main.messageTray._notificationWidget.get_parent();
|
|
Main.messageTray._notificationWidget.hide();
|
|
Main.messageTray._notificationWidget.reparent(windowList.actor);
|
|
Main.messageTray._notificationWidget.show();
|
|
}
|
|
|
|
function disable() {
|
|
if (!windowList)
|
|
return;
|
|
|
|
windowList.actor.hide();
|
|
|
|
if (notificationParent) {
|
|
Main.messageTray._notificationWidget.reparent(notificationParent);
|
|
notificationParent = null;
|
|
}
|
|
|
|
windowList.actor.destroy();
|
|
windowList = null;
|
|
|
|
for (prop in injections)
|
|
MessageTray.MessageTray.prototype[prop] = injections[prop];
|
|
|
|
Main.messageTray._notificationWidget.set_anchor_point(0, 0);
|
|
Main.messageTray.actor.set_anchor_point(0, 0);
|
|
}
|