9c74e22313
If the source actor is sized 0x0, the grabHelper will close the menu on button release if the menu ends up flipped because in that case the release event happens when the pointer is neither over the source actor (since it's 0x0) or over the menu actor. A zero sized source actor works for the non-flipped menu case because the menu's actor itself ends up underneath the pointer. https://bugzilla.gnome.org/show_bug.cgi?id=756605
233 lines
8.7 KiB
JavaScript
233 lines
8.7 KiB
JavaScript
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*
|
|
|
|
const Gtk = imports.gi.Gtk;
|
|
const Lang = imports.lang;
|
|
const Meta = imports.gi.Meta;
|
|
const St = imports.gi.St;
|
|
const Shell = imports.gi.Shell;
|
|
|
|
const BoxPointer = imports.ui.boxpointer;
|
|
const Main = imports.ui.main;
|
|
const PopupMenu = imports.ui.popupMenu;
|
|
const RemoteMenu = imports.ui.remoteMenu;
|
|
|
|
const WindowMenu = new Lang.Class({
|
|
Name: 'WindowMenu',
|
|
Extends: PopupMenu.PopupMenu,
|
|
|
|
_init: function(window, sourceActor) {
|
|
this.parent(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: function(window) {
|
|
let type = window.get_window_type();
|
|
|
|
let item;
|
|
|
|
item = this.addAction(_("Minimize"), Lang.bind(this, function(event) {
|
|
window.minimize();
|
|
}));
|
|
if (!window.can_minimize())
|
|
item.setSensitive(false);
|
|
|
|
if (window.get_maximized()) {
|
|
item = this.addAction(_("Unmaximize"), Lang.bind(this, function() {
|
|
window.unmaximize(Meta.MaximizeFlags.BOTH);
|
|
}));
|
|
} else {
|
|
item = this.addAction(_("Maximize"), Lang.bind(this, function() {
|
|
window.maximize(Meta.MaximizeFlags.BOTH);
|
|
}));
|
|
}
|
|
if (!window.can_maximize())
|
|
item.setSensitive(false);
|
|
|
|
item = this.addAction(_("Move"), Lang.bind(this, function(event) {
|
|
window.begin_grab_op(Meta.GrabOp.KEYBOARD_MOVING, true, event.get_time());
|
|
}));
|
|
if (!window.allows_move())
|
|
item.setSensitive(false);
|
|
|
|
item = this.addAction(_("Resize"), Lang.bind(this, function(event) {
|
|
window.begin_grab_op(Meta.GrabOp.KEYBOARD_RESIZING_UNKNOWN, true, 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"), Lang.bind(this, function(event) {
|
|
window.shove_titlebar_onscreen();
|
|
}));
|
|
}
|
|
|
|
item = this.addAction(_("Always on Top"), Lang.bind(this, function() {
|
|
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"), Lang.bind(this, function() {
|
|
if (isSticky)
|
|
window.unstick();
|
|
else
|
|
window.stick();
|
|
}));
|
|
if (isSticky)
|
|
item.setOrnament(PopupMenu.Ornament.CHECK);
|
|
if (window.is_always_on_all_workspaces())
|
|
item.setSensitive(false);
|
|
|
|
let nWorkspaces = global.screen.n_workspaces;
|
|
|
|
if (!isSticky) {
|
|
let workspace = window.get_workspace();
|
|
if (workspace != workspace.get_neighbor(Meta.MotionDirection.LEFT)) {
|
|
this.addAction(_("Move to Workspace Left"), Lang.bind(this, function(event) {
|
|
window.change_workspace(workspace.get_neighbor(Meta.MotionDirection.LEFT));
|
|
}));
|
|
}
|
|
if (workspace != workspace.get_neighbor(Meta.MotionDirection.RIGHT)) {
|
|
this.addAction(_("Move to Workspace Right"), Lang.bind(this, function(event) {
|
|
window.change_workspace(workspace.get_neighbor(Meta.MotionDirection.RIGHT));
|
|
}));
|
|
}
|
|
if (workspace != workspace.get_neighbor(Meta.MotionDirection.UP)) {
|
|
this.addAction(_("Move to Workspace Up"), Lang.bind(this, function(event) {
|
|
window.change_workspace(workspace.get_neighbor(Meta.MotionDirection.UP));
|
|
}));
|
|
}
|
|
if (workspace != workspace.get_neighbor(Meta.MotionDirection.DOWN)) {
|
|
this.addAction(_("Move to Workspace Down"), Lang.bind(this, function(event) {
|
|
window.change_workspace(workspace.get_neighbor(Meta.MotionDirection.DOWN));
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
|
|
let screen = global.screen;
|
|
let nMonitors = screen.get_n_monitors();
|
|
if (nMonitors > 1) {
|
|
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
|
|
let monitorIndex = window.get_monitor();
|
|
|
|
let upMonitorIndex = screen.get_monitor_neighbor_index(monitorIndex, Meta.ScreenDirection.UP);
|
|
if (upMonitorIndex != -1) {
|
|
this.addAction(_("Move to Monitor Up"), Lang.bind(this, function(event) {
|
|
window.move_to_monitor(upMonitorIndex);
|
|
}));
|
|
}
|
|
let downMonitorIndex = screen.get_monitor_neighbor_index(monitorIndex, Meta.ScreenDirection.DOWN);
|
|
if (downMonitorIndex != -1) {
|
|
this.addAction(_("Move to Monitor Down"), Lang.bind(this, function(event) {
|
|
window.move_to_monitor(downMonitorIndex);
|
|
}));
|
|
}
|
|
let leftMonitorIndex = screen.get_monitor_neighbor_index(monitorIndex, Meta.ScreenDirection.LEFT);
|
|
if (leftMonitorIndex != -1) {
|
|
this.addAction(_("Move to Monitor Left"), Lang.bind(this, function(event) {
|
|
window.move_to_monitor(leftMonitorIndex);
|
|
}));
|
|
}
|
|
let rightMonitorIndex = screen.get_monitor_neighbor_index(monitorIndex, Meta.ScreenDirection.RIGHT);
|
|
if (rightMonitorIndex != -1) {
|
|
this.addAction(_("Move to Monitor Right"), Lang.bind(this, function(event) {
|
|
window.move_to_monitor(rightMonitorIndex);
|
|
}));
|
|
}
|
|
}
|
|
|
|
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
|
|
item = this.addAction(_("Close"), Lang.bind(this, function(event) {
|
|
window.delete(event.get_time());
|
|
}));
|
|
if (!window.can_close())
|
|
item.setSensitive(false);
|
|
}
|
|
});
|
|
|
|
const AppMenu = new Lang.Class({
|
|
Name: 'AppMenu',
|
|
Extends: RemoteMenu.RemoteMenu,
|
|
|
|
_init: function(window, sourceActor) {
|
|
let app = Shell.WindowTracker.get_default().get_window_app(window);
|
|
|
|
this.parent(sourceActor, app.menu, app.action_group);
|
|
|
|
this.actor.add_style_class_name('fallback-app-menu');
|
|
let variant = window.get_gtk_theme_variant();
|
|
if (variant)
|
|
this.actor.add_style_class_name(variant);
|
|
|
|
Main.layoutManager.uiGroup.add_actor(this.actor);
|
|
this.actor.hide();
|
|
}
|
|
});
|
|
|
|
const WindowMenuManager = new Lang.Class({
|
|
Name: 'WindowMenuManager',
|
|
|
|
_init: function() {
|
|
this._manager = new PopupMenu.PopupMenuManager({ actor: Main.layoutManager.dummyCursor });
|
|
|
|
this._sourceActor = new St.Widget({ reactive: true, visible: false });
|
|
this._sourceActor.connect('button-press-event', Lang.bind(this,
|
|
function() {
|
|
this._manager.activeMenu.toggle();
|
|
}));
|
|
Main.uiGroup.add_actor(this._sourceActor);
|
|
},
|
|
|
|
showWindowMenuForWindow: function(window, type, rect) {
|
|
let menuType = (type == Meta.WindowMenuType.WM) ? WindowMenu : AppMenu;
|
|
let menu = new menuType(window, this._sourceActor);
|
|
|
|
this._manager.addMenu(menu);
|
|
|
|
menu.connect('activate', function() {
|
|
window.check_alive(global.get_current_time());
|
|
});
|
|
let destroyId = window.connect('unmanaged',
|
|
function() {
|
|
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.NONE);
|
|
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
|
menu.connect('open-state-changed', Lang.bind(this, function(menu_, isOpen) {
|
|
if (isOpen)
|
|
return;
|
|
|
|
this._sourceActor.hide();
|
|
menu.destroy();
|
|
window.disconnect(destroyId);
|
|
}));
|
|
}
|
|
});
|