173 lines
5.4 KiB
JavaScript
173 lines
5.4 KiB
JavaScript
|
const { Gtk, Clutter, GObject, Shell, St } = imports.gi;
|
||
|
|
||
|
const PopupMenu = imports.ui.popupMenu;
|
||
|
const Main = imports.ui.main;
|
||
|
|
||
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||
|
const Me = ExtensionUtils.getCurrentExtension();
|
||
|
const Util = Me.imports.util;
|
||
|
const Extension = Me.imports.extension;
|
||
|
const CreateNumberIcon = Me.imports.numberIcon.createNumberIcon;
|
||
|
const NUMBER_TO_CHAR = Me.imports.util.NUMBER_TO_CHAR;
|
||
|
|
||
|
|
||
|
const DIRECTION = 'floating-dock-direction';
|
||
|
|
||
|
const PREVIEW_MAX_WIDTH = 250;
|
||
|
const PREVIEW_MAX_HEIGHT = 150;
|
||
|
|
||
|
var WindowPreviewMenu = class WindowPreviewMenu extends PopupMenu.PopupMenu {
|
||
|
constructor(source, iconSize) {
|
||
|
let direction, style;
|
||
|
[direction, style] = getDirectionStyle(source);
|
||
|
super(source, 0.5, direction);
|
||
|
this.actor.set_style(style);
|
||
|
|
||
|
this.iconSize = iconSize;
|
||
|
this._source = source;
|
||
|
this._source.connect('destroy', () => {
|
||
|
this.destroy();
|
||
|
});
|
||
|
|
||
|
if (source.vimMode) {
|
||
|
this.sourceActor.disconnect(this._keyPressId);
|
||
|
this._keyPressId = 0;
|
||
|
}
|
||
|
|
||
|
this.actor.hide();
|
||
|
Main.uiGroup.add_actor(this.actor);
|
||
|
}
|
||
|
|
||
|
_redisplay() {
|
||
|
this.removeAll();
|
||
|
|
||
|
this._menuSection = new WindowPreviewMenuSection();
|
||
|
this.addMenuItem(this._menuSection);
|
||
|
|
||
|
let windows = this._source.app.get_windows();
|
||
|
windows = windows.filter( (window) => {
|
||
|
return Util.windowInActiveWorkspace(window);
|
||
|
});
|
||
|
let k = 0;
|
||
|
for (let i in windows) {
|
||
|
let menuItem = new WindowPreviewMenuItem(windows[i], this._source, k++, this.iconSize);
|
||
|
this._menuSection.addMenuItem(menuItem);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
popup() {
|
||
|
this._redisplay();
|
||
|
this.open();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var WindowPreviewMenuSection = class WindowPreviewMenuSection extends PopupMenu.PopupMenuSection {
|
||
|
constructor() {
|
||
|
super();
|
||
|
let scroll = new St.ScrollView({ hscrollbar_policy: Gtk.PolicyType.NEVER,
|
||
|
vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
|
||
|
enable_mouse_scrolling: true });
|
||
|
this.actor = scroll;
|
||
|
this.actor.add_actor(this.box);
|
||
|
this.actor._delegate = this;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var WindowPreviewMenuItem = GObject.registerClass(
|
||
|
class WindowPreviewMenuItem extends PopupMenu.PopupBaseMenuItem {
|
||
|
_init(window, button, number, iconSize) {
|
||
|
super._init({});
|
||
|
|
||
|
this._window = window;
|
||
|
this._button = button;
|
||
|
this._number = number;
|
||
|
this.iconSize = iconSize;
|
||
|
|
||
|
if (button.vimMode) {
|
||
|
this.setSensitive(false);
|
||
|
}
|
||
|
|
||
|
this._cloneBin = new St.Bin();
|
||
|
this._cloneBin.set_size(PREVIEW_MAX_WIDTH, PREVIEW_MAX_HEIGHT);
|
||
|
this.add_child(this._cloneBin);
|
||
|
|
||
|
this._cloneWindow(window);
|
||
|
|
||
|
this.connect('destroy', () => { this._onDestroy(); });
|
||
|
}
|
||
|
|
||
|
_cloneWindow(window) {
|
||
|
let mutterWindow = window.get_compositor_private();
|
||
|
|
||
|
let [width, height] = mutterWindow.get_size();
|
||
|
let scale = Math.min(1.0, PREVIEW_MAX_WIDTH/width, PREVIEW_MAX_HEIGHT/height);
|
||
|
let clone = new Clutter.Clone ({ source: mutterWindow,
|
||
|
reactive: true,
|
||
|
width: width * scale,
|
||
|
height: height * scale });
|
||
|
this._clone = clone;
|
||
|
|
||
|
this._cloneBox = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
||
|
this._cloneBox.destroy_all_children();
|
||
|
this._cloneBox.add_child(this._clone);
|
||
|
|
||
|
if (this._button.vimMode)
|
||
|
this._cloneBox.add_child(CreateNumberIcon(this._number, this.iconSize));
|
||
|
|
||
|
this._cloneBin.set_child(this._cloneBox);
|
||
|
|
||
|
this._mutterWindow = mutterWindow;
|
||
|
this._mutterWindowId = this._mutterWindow.connect('destroy', () => {
|
||
|
this.destroy();
|
||
|
this._mutterWindowId = 0;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
vfunc_button_press_event() {
|
||
|
this._getTopMenu().close();
|
||
|
this._button.activateWindow(this._window);
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
|
||
|
_onDestroy() {
|
||
|
if (this._mutterWindowId) {
|
||
|
this._mutterWindow.disconnect(this._mutterWindowId);
|
||
|
this._mutterWindowId = 0;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
function getDirectionStyle(source) {
|
||
|
let sourceAllocation = Shell.util_get_transformed_allocation(source);
|
||
|
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||
|
// -arrow-base + -arrow-border-radius*2 + -arrow-border-width*2
|
||
|
let arrowHeight = (24 + 9 * 2 + 2);
|
||
|
|
||
|
let style = '';
|
||
|
let direction;
|
||
|
switch (Util.getPosition(Extension.gsettings.get_string(DIRECTION))) {
|
||
|
case St.Side.TOP:
|
||
|
case St.Side.BOTTOM:
|
||
|
if (sourceAllocation.x1 > (workArea.x + workArea.width / 2)) {
|
||
|
direction = St.Side.RIGHT;
|
||
|
} else {
|
||
|
direction = St.Side.LEFT;
|
||
|
}
|
||
|
style = 'max-height: %spx;'.format(workArea.height - arrowHeight);
|
||
|
break;
|
||
|
case St.Side.LEFT:
|
||
|
case St.Side.RIGHT:
|
||
|
if (sourceAllocation.y1 > (workArea.y + workArea.height / 2)) {
|
||
|
direction = St.Side.BOTTOM;
|
||
|
style = 'max-height: %spx;'.format(sourceAllocation.y1 - workArea.y);
|
||
|
} else {
|
||
|
direction = St.Side.TOP;
|
||
|
style = 'max-height: %spx;'.format(workArea.y + workArea.height - sourceAllocation.y2);
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return [direction, style];
|
||
|
}
|