{"size": 5666, "ext": "js", "max_stars_repo_path": "floatingDock@sun.wxg@gmail.com/windowPreview.js", "max_stars_repo_name": "sunwxg/gnome-shell-extension-floatingDock", "max_stars_repo_stars_event_min_datetime": "2020-02-18T09:50:55.000Z", "max_stars_repo_stars_event_max_datetime": "2022-02-18T06:08:09.000Z", "max_issues_repo_path": "floatingDock@sun.wxg@gmail.com/windowPreview.js", "max_issues_repo_name": "sunwxg/gnome-shell-extension-floatingDock", "max_issues_repo_issues_event_min_datetime": "2020-02-14T08:19:18.000Z", "max_issues_repo_issues_event_max_datetime": "2022-03-02T03:03:30.000Z", "max_forks_repo_path": "floatingDock@sun.wxg@gmail.com/windowPreview.js", "max_forks_repo_name": "sunwxg/gnome-shell-extension-floatingDock", "max_forks_repo_forks_event_min_datetime": "2020-01-19T00:04:01.000Z", "max_forks_repo_forks_event_max_datetime": "2021-12-09T15:15:24.000Z"}
{"max_stars_count": 51, "max_issues_count": 27, "max_forks_count": 8, "avg_line_length": 32.3771428571, "max_line_length": 99, "alphanum_fraction": 0.6110130604}
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.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();
        if (this._source.currentWorkspace) {
            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_release_event() {
        this._getTopMenu().close();
        this._button.activateWindow(this._window);
        return Clutter.EVENT_PROPAGATE;
    }

    vfunc_touch_event(touchEvent) {
        if (touchEvent.type == Clutter.EventType.TOUCH_END) {
            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) {
    const sourceAllocation = source.get_transformed_extents();
    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];
}
