diff options
Diffstat (limited to '')
-rw-r--r-- | js/ui/windowMenu.js | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/js/ui/windowMenu.js b/js/ui/windowMenu.js new file mode 100644 index 0000000..081645f --- /dev/null +++ b/js/ui/windowMenu.js @@ -0,0 +1,252 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -* +/* exported WindowMenuManager */ + +const { GLib, Meta, St } = imports.gi; + +const BoxPointer = imports.ui.boxpointer; +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Screenshot = imports.ui.screenshot; + +var WindowMenu = class extends PopupMenu.PopupMenu { + constructor(window, sourceActor) { + super(sourceActor, 0, St.Side.TOP); + + this.actor.add_style_class_name('window-menu'); + + Main.layoutManager.uiGroup.add_actor(this.actor); + this.actor.hide(); + + this._buildMenu(window); + } + + _buildMenu(window) { + let type = window.get_window_type(); + + let item; + + // Translators: entry in the window right click menu. + item = this.addAction(_('Take Screenshot'), async () => { + try { + const actor = window.get_compositor_private(); + const content = actor.paint_to_content(null); + const texture = content.get_texture(); + + await Screenshot.captureScreenshot(texture, null, 1, null); + } catch (e) { + logError(e, 'Error capturing screenshot'); + } + }); + + item = this.addAction(_('Hide'), () => { + window.minimize(); + }); + if (!window.can_minimize()) + item.setSensitive(false); + + if (window.get_maximized()) { + item = this.addAction(_('Restore'), () => { + window.unmaximize(Meta.MaximizeFlags.BOTH); + }); + } else { + item = this.addAction(_("Maximize"), () => { + window.maximize(Meta.MaximizeFlags.BOTH); + }); + } + if (!window.can_maximize()) + item.setSensitive(false); + + item = this.addAction(_("Move"), event => { + this._grabAction(window, Meta.GrabOp.KEYBOARD_MOVING, event.get_time()); + }); + if (!window.allows_move()) + item.setSensitive(false); + + item = this.addAction(_("Resize"), event => { + this._grabAction(window, Meta.GrabOp.KEYBOARD_RESIZING_UNKNOWN, event.get_time()); + }); + if (!window.allows_resize()) + item.setSensitive(false); + + if (!window.titlebar_is_onscreen() && type != Meta.WindowType.DOCK && type != Meta.WindowType.DESKTOP) { + this.addAction(_("Move Titlebar Onscreen"), () => { + window.shove_titlebar_onscreen(); + }); + } + + item = this.addAction(_("Always on Top"), () => { + if (window.is_above()) + window.unmake_above(); + else + window.make_above(); + }); + if (window.is_above()) + item.setOrnament(PopupMenu.Ornament.CHECK); + if (window.get_maximized() == Meta.MaximizeFlags.BOTH || + type == Meta.WindowType.DOCK || + type == Meta.WindowType.DESKTOP || + type == Meta.WindowType.SPLASHSCREEN) + item.setSensitive(false); + + if (Main.sessionMode.hasWorkspaces && + (!Meta.prefs_get_workspaces_only_on_primary() || + window.is_on_primary_monitor())) { + let isSticky = window.is_on_all_workspaces(); + + item = this.addAction(_("Always on Visible Workspace"), () => { + if (isSticky) + window.unstick(); + else + window.stick(); + }); + if (isSticky) + item.setOrnament(PopupMenu.Ornament.CHECK); + if (window.is_always_on_all_workspaces()) + item.setSensitive(false); + + if (!isSticky) { + let workspace = window.get_workspace(); + if (workspace != workspace.get_neighbor(Meta.MotionDirection.LEFT)) { + this.addAction(_("Move to Workspace Left"), () => { + let dir = Meta.MotionDirection.LEFT; + window.change_workspace(workspace.get_neighbor(dir)); + }); + } + if (workspace != workspace.get_neighbor(Meta.MotionDirection.RIGHT)) { + this.addAction(_("Move to Workspace Right"), () => { + let dir = Meta.MotionDirection.RIGHT; + window.change_workspace(workspace.get_neighbor(dir)); + }); + } + if (workspace != workspace.get_neighbor(Meta.MotionDirection.UP)) { + this.addAction(_("Move to Workspace Up"), () => { + let dir = Meta.MotionDirection.UP; + window.change_workspace(workspace.get_neighbor(dir)); + }); + } + if (workspace != workspace.get_neighbor(Meta.MotionDirection.DOWN)) { + this.addAction(_("Move to Workspace Down"), () => { + let dir = Meta.MotionDirection.DOWN; + window.change_workspace(workspace.get_neighbor(dir)); + }); + } + } + } + + let display = global.display; + let nMonitors = display.get_n_monitors(); + let monitorIndex = window.get_monitor(); + if (nMonitors > 1 && monitorIndex >= 0) { + this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + + let dir = Meta.DisplayDirection.UP; + let upMonitorIndex = + display.get_monitor_neighbor_index(monitorIndex, dir); + if (upMonitorIndex != -1) { + this.addAction(_("Move to Monitor Up"), () => { + window.move_to_monitor(upMonitorIndex); + }); + } + + dir = Meta.DisplayDirection.DOWN; + let downMonitorIndex = + display.get_monitor_neighbor_index(monitorIndex, dir); + if (downMonitorIndex != -1) { + this.addAction(_("Move to Monitor Down"), () => { + window.move_to_monitor(downMonitorIndex); + }); + } + + dir = Meta.DisplayDirection.LEFT; + let leftMonitorIndex = + display.get_monitor_neighbor_index(monitorIndex, dir); + if (leftMonitorIndex != -1) { + this.addAction(_("Move to Monitor Left"), () => { + window.move_to_monitor(leftMonitorIndex); + }); + } + + dir = Meta.DisplayDirection.RIGHT; + let rightMonitorIndex = + display.get_monitor_neighbor_index(monitorIndex, dir); + if (rightMonitorIndex != -1) { + this.addAction(_("Move to Monitor Right"), () => { + window.move_to_monitor(rightMonitorIndex); + }); + } + } + + this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + + item = this.addAction(_("Close"), event => { + window.delete(event.get_time()); + }); + if (!window.can_close()) + item.setSensitive(false); + } + + _grabAction(window, grabOp, time) { + if (global.display.get_grab_op() == Meta.GrabOp.NONE) { + window.begin_grab_op(grabOp, true, time); + return; + } + + let waitId = 0; + let id = global.display.connect('grab-op-end', display => { + display.disconnect(id); + GLib.source_remove(waitId); + + window.begin_grab_op(grabOp, true, time); + }); + + waitId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, () => { + global.display.disconnect(id); + return GLib.SOURCE_REMOVE; + }); + } +}; + +var WindowMenuManager = class { + constructor() { + this._manager = new PopupMenu.PopupMenuManager(Main.layoutManager.dummyCursor); + + this._sourceActor = new St.Widget({ reactive: true, visible: false }); + this._sourceActor.connect('button-press-event', () => { + this._manager.activeMenu.toggle(); + }); + Main.uiGroup.add_actor(this._sourceActor); + } + + showWindowMenuForWindow(window, type, rect) { + if (!Main.sessionMode.hasWmMenus) + return; + + if (type != Meta.WindowMenuType.WM) + throw new Error('Unsupported window menu type'); + let menu = new WindowMenu(window, this._sourceActor); + + this._manager.addMenu(menu); + + menu.connect('activate', () => { + window.check_alive(global.get_current_time()); + }); + let destroyId = window.connect('unmanaged', () => { + menu.close(); + }); + + this._sourceActor.set_size(Math.max(1, rect.width), Math.max(1, rect.height)); + this._sourceActor.set_position(rect.x, rect.y); + this._sourceActor.show(); + + menu.open(BoxPointer.PopupAnimation.FADE); + menu.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + menu.connect('open-state-changed', (menu_, isOpen) => { + if (isOpen) + return; + + this._sourceActor.hide(); + menu.destroy(); + window.disconnect(destroyId); + }); + } +}; |