mirror of
https://github.com/gosticks/PaperWM.git
synced 2026-07-04 16:10:01 +00:00
Merge pull request #179 from paperwm/workspace-menu
Modernize the workspace menu
This commit is contained in:
@@ -115,55 +115,13 @@ function cycleWorkspaceSettings(binding = "<Super>q") {
|
||||
var Settings = Extension.imports.settings;
|
||||
var Utils = Extension.imports.utils;
|
||||
|
||||
function rotated(list, dir=1) {
|
||||
return [].concat(
|
||||
list.slice(dir),
|
||||
list.slice(0, dir)
|
||||
);
|
||||
}
|
||||
|
||||
function cycle(mw, dir=1) {
|
||||
let n = global.workspace_manager.get_n_workspaces();
|
||||
let N = Settings.workspaceList.get_strv('list').length;
|
||||
let space = Tiling.spaces.selectedSpace;
|
||||
let wsI = space.workspace.index();
|
||||
|
||||
// 2 6 7 8 <-- indices
|
||||
// x a b c <-- settings
|
||||
// a b c x <-- rotated settings
|
||||
|
||||
let uuids = Settings.workspaceList.get_strv('list');
|
||||
// Work on tuples of [uuid, settings] since we need to uuid association
|
||||
// in the last step
|
||||
let settings = uuids.map(
|
||||
uuid => [uuid, Settings.getWorkspaceSettingsByUUID(uuid)]
|
||||
);
|
||||
settings.sort((a, b) => a[1].get_int('index') - b[1].get_int('index'));
|
||||
|
||||
let unbound = settings.slice(n);
|
||||
let strip = [settings[wsI]].concat(unbound);
|
||||
|
||||
strip = rotated(strip, dir);
|
||||
|
||||
let nextSettings = strip[0];
|
||||
unbound = strip.slice(1);
|
||||
|
||||
nextSettings[1].set_int('index', wsI);
|
||||
space.setSettings(nextSettings); // ASSUMPTION: ok that two settings have same index here
|
||||
|
||||
// Re-assign unbound indices:
|
||||
for (let i = n; i < N; i++) {
|
||||
unbound[i-n][1].set_int('index', i);
|
||||
}
|
||||
}
|
||||
|
||||
Keybindings.bindkey(
|
||||
binding, "next-space-setting",
|
||||
mw => cycle(mw, -1), { activeInNavigator: true }
|
||||
mw => Tiling.cycleWorkspaceSettings(-1), { activeInNavigator: true }
|
||||
);
|
||||
Keybindings.bindkey(
|
||||
"<Shift>"+binding, "prev-space-setting",
|
||||
mw => cycle(mw, 1), { activeInNavigator: true }
|
||||
mw => Tiling.cycleWorkspaceSettings(1), { activeInNavigator: true }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
43
tiling.js
43
tiling.js
@@ -2891,6 +2891,49 @@ function sortWindows(space, windows) {
|
||||
.map(c => c.meta_window);
|
||||
}
|
||||
|
||||
function rotated(list, dir=1) {
|
||||
return [].concat(
|
||||
list.slice(dir),
|
||||
list.slice(0, dir)
|
||||
);
|
||||
}
|
||||
|
||||
function cycleWorkspaceSettings(dir=1) {
|
||||
let n = workspaceManager.get_n_workspaces();
|
||||
let N = Settings.workspaceList.get_strv('list').length;
|
||||
let space = spaces.selectedSpace;
|
||||
let wsI = space.workspace.index();
|
||||
|
||||
// 2 6 7 8 <-- indices
|
||||
// x a b c <-- settings
|
||||
// a b c x <-- rotated settings
|
||||
|
||||
let uuids = Settings.workspaceList.get_strv('list');
|
||||
// Work on tuples of [uuid, settings] since we need to uuid association
|
||||
// in the last step
|
||||
let settings = uuids.map(
|
||||
uuid => [uuid, Settings.getWorkspaceSettingsByUUID(uuid)]
|
||||
);
|
||||
settings.sort((a, b) => a[1].get_int('index') - b[1].get_int('index'));
|
||||
|
||||
let unbound = settings.slice(n);
|
||||
let strip = [settings[wsI]].concat(unbound);
|
||||
|
||||
strip = rotated(strip, dir);
|
||||
|
||||
let nextSettings = strip[0];
|
||||
unbound = strip.slice(1);
|
||||
|
||||
nextSettings[1].set_int('index', wsI);
|
||||
space.setSettings(nextSettings); // ASSUMPTION: ok that two settings have same index here
|
||||
|
||||
// Re-assign unbound indices:
|
||||
for (let i = n; i < N; i++) {
|
||||
unbound[i-n][1].set_int('index', i);
|
||||
}
|
||||
return space;
|
||||
}
|
||||
|
||||
|
||||
// Backward compatibility
|
||||
function defwinprop(...args) {
|
||||
|
||||
186
topbar.js
186
topbar.js
@@ -43,27 +43,67 @@ var colors = [
|
||||
'#46A046', '#267726', '#ffffff', '#000000'
|
||||
];
|
||||
|
||||
class PopupMenuEntry {
|
||||
constructor (text, label) {
|
||||
this.actor = new St.Entry({hint_text: text});
|
||||
this.entry = this.actor;
|
||||
this.actor.set_style('margin: 4px 0 4px 0');
|
||||
|
||||
// 3.32 crashes when an entry with text is first shown...
|
||||
let id = this.entry.clutter_text.connect('key-focus-in', () => {
|
||||
this.entry.clutter_text.disconnect(id);
|
||||
this.entry.text = this.entry.hint_text;
|
||||
var PopupMenuEntryHelper = function constructor(text) {
|
||||
this.label = new St.Entry({
|
||||
text,
|
||||
// While not a search entry, this looks much better
|
||||
style_class:'search-entry',
|
||||
name: 'workspace-name-entry',
|
||||
track_hover: true,
|
||||
reactive: true,
|
||||
can_focus: true
|
||||
});
|
||||
this.actor.add(this.label, {expand: true});
|
||||
this.actor.label_actor = this.label;
|
||||
this.label.clutter_text.connect('activate', this.emit.bind(this, 'activate'));
|
||||
}
|
||||
|
||||
this.button = new St.Button({label,
|
||||
style_class: 'modal-dialog-button button'});
|
||||
this.actor.set_secondary_icon(this.button);
|
||||
var PopupMenuEntry;
|
||||
// 3.32 uses `class` to define `PopupBaseMenuItem`, but doesn't use
|
||||
// registerClass, breaking our somewhat lame registerClass polyfill.
|
||||
if (Utils.version[1] === 32) {
|
||||
PopupMenuEntry = class PopupMenuEntry extends PopupMenu.PopupBaseMenuItem {
|
||||
constructor(text) {
|
||||
super({
|
||||
activate: false,
|
||||
reactive: true,
|
||||
hover: false,
|
||||
can_focus: false
|
||||
});
|
||||
|
||||
this.entry.clutter_text.set_activatable(true);
|
||||
this.entry.clutter_text.connect('activate', () => {
|
||||
this.button.emit('clicked', null);
|
||||
});
|
||||
}
|
||||
PopupMenuEntryHelper.call(this, text);
|
||||
}
|
||||
|
||||
activate(event) {
|
||||
this.label.grab_key_focus();
|
||||
}
|
||||
|
||||
_onKeyFocusIn(actor) {
|
||||
this.activate();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
PopupMenuEntry = Utils.registerClass(
|
||||
class PopupMenuEntry extends PopupMenu.PopupBaseMenuItem {
|
||||
_init(text) {
|
||||
super._init({
|
||||
activate: false,
|
||||
reactive: true,
|
||||
hover: false,
|
||||
can_focus: false
|
||||
});
|
||||
|
||||
PopupMenuEntryHelper.call(this, text);
|
||||
}
|
||||
|
||||
activate(event) {
|
||||
this.label.grab_key_focus();
|
||||
}
|
||||
|
||||
_onKeyFocusIn(actor) {
|
||||
this.activate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class Color {
|
||||
@@ -128,8 +168,13 @@ class WorkspaceMenu extends PanelMenu.Button {
|
||||
|
||||
this.actor.name = 'workspace-button';
|
||||
|
||||
let scale = display.get_monitor_scale(Main.layoutManager.primaryIndex);
|
||||
this._label = new St.Label({
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
// Avoid moving the menu on short names
|
||||
// TODO: update on scale changes
|
||||
min_width: 60*scale
|
||||
});
|
||||
|
||||
this.setName(Meta.prefs_get_workspace_name(workspaceManager.get_active_workspace_index()));
|
||||
|
||||
@@ -140,41 +185,59 @@ class WorkspaceMenu extends PanelMenu.Button {
|
||||
'switch-workspace',
|
||||
this.workspaceSwitched.bind(this));
|
||||
|
||||
this.entry = new PopupMenuEntry(this._label.text, 'Set name');
|
||||
let clicked = () => {
|
||||
let name = this.entry.entry.text;
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem(_('Workspace Settings')));
|
||||
|
||||
this.entry = new PopupMenuEntry(this._label.text);
|
||||
this.menu.addMenuItem(this.entry);
|
||||
let changed = () => {
|
||||
let name = this.entry.label.text;
|
||||
let space = Tiling.spaces.spaceOf(workspaceManager.get_active_workspace());
|
||||
space.settings.set_string('name', name);
|
||||
this.setName(name);
|
||||
};
|
||||
this.signals.connect(this.entry.button, 'clicked',
|
||||
clicked.bind(this.entry));
|
||||
this.signals.connect(this.entry.label.clutter_text, 'text-changed',
|
||||
changed);
|
||||
// let clicked = () => {
|
||||
// let name = this.entry.entry.text;
|
||||
// let space = Tiling.spaces.spaceOf(workspaceManager.get_active_workspace());
|
||||
// space.settings.set_string('name', name);
|
||||
// this.setName(name);
|
||||
// };
|
||||
// this.signals.connect(this.entry.button, 'clicked',
|
||||
// clicked.bind(this.entry));
|
||||
|
||||
let space = Tiling.spaces.spaceOf(workspaceManager.get_active_workspace());
|
||||
// let space = Tiling.spaces.spaceOf(workspaceManager.get_active_workspace());
|
||||
// this.entry.actor.text = space.name;
|
||||
// this.colors.entry.actor.text = space.color;
|
||||
|
||||
this.colors = new ColorEntry(space.color);
|
||||
// this.colors = new ColorEntry(space.color);
|
||||
|
||||
this._contentBox = new St.BoxLayout({vertical: true});
|
||||
this._contentBox.layout_manager.spacing = 10;
|
||||
this._contentBox.set_style('margin: 10px 20px;');
|
||||
this._contentBox.add_actor(this.entry.actor);
|
||||
this._contentBox.add_actor(this.colors.actor);
|
||||
this.menu.box.add_actor(this._contentBox);
|
||||
// this._contentBox = new St.BoxLayout({vertical: true});
|
||||
// this._contentBox.layout_manager.spacing = 10;
|
||||
// this._contentBox.set_style('margin: 10px 20px;');
|
||||
// this._contentBox.add_actor(this.entry.actor);
|
||||
// this._contentBox.add_actor(this.colors.actor);
|
||||
// this.menu.box.add_actor(this._contentBox);
|
||||
|
||||
this._zenItem = new PopupMenu.PopupSwitchMenuItem('show top bar', true);
|
||||
this._zenItem = new PopupMenu.PopupSwitchMenuItem('Hide top bar', false);
|
||||
this.menu.addMenuItem(this._zenItem);
|
||||
this._zenItem.connect('toggled', item => {
|
||||
Tiling.spaces.selectedSpace.settings.set_boolean('show-top-bar', item.state);
|
||||
Tiling.spaces.selectedSpace.settings.set_boolean('show-top-bar', !item.state);
|
||||
});
|
||||
|
||||
this.prefsIcon = new St.Button({ reactive: true,
|
||||
can_focus: true,
|
||||
track_hover: true,
|
||||
accessible_name: 'workspace preference',
|
||||
style_class: 'system-menu-action' });
|
||||
this.prefsIcon.child = new St.Icon({ icon_name: 'gtk-preferences' });
|
||||
function createButton(icon_name, accessible_name) {
|
||||
return new St.Button({reactive: true,
|
||||
can_focus: true,
|
||||
track_hover: true,
|
||||
accessible_name,
|
||||
style_class: 'system-menu-action',
|
||||
child: new St.Icon({icon_name})
|
||||
});
|
||||
}
|
||||
|
||||
this.prefsIcon = createButton('gtk-preferences', 'workspace preference');
|
||||
this.prevIcon = createButton('go-previous-symbolic', 'previous workspace setting');
|
||||
this.nextIcon = createButton('go-next-symbolic', 'next workspace setting');
|
||||
|
||||
this.prefsIcon.connect('clicked', () => {
|
||||
this.menu.close(true);
|
||||
@@ -188,10 +251,28 @@ class WorkspaceMenu extends PanelMenu.Button {
|
||||
}
|
||||
});
|
||||
|
||||
this.menu.box.add(this.prefsIcon, { expand: true, x_fill: false });
|
||||
this.nextIcon.connect('clicked', () => {
|
||||
let space = Tiling.cycleWorkspaceSettings(-1);
|
||||
this.entry.label.text = space.name;
|
||||
menu.nextIcon.grab_key_focus();
|
||||
});
|
||||
this.prevIcon.connect('clicked', () => {
|
||||
let space = Tiling.cycleWorkspaceSettings(1);
|
||||
this.entry.label.text = space.name;
|
||||
menu.prevIcon.grab_key_focus();
|
||||
});
|
||||
|
||||
this.entry.actor.width = this.colors.actor.width;
|
||||
this.colors.entry.actor.width = this.colors.actor.width;
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this.iconBox = new St.BoxLayout();
|
||||
this.menu.box.add(this.iconBox);
|
||||
|
||||
this.iconBox.add(this.prevIcon, { expand: true, x_fill: false });
|
||||
this.iconBox.add(this.prefsIcon, { expand: true, x_fill: false });
|
||||
this.iconBox.add(this.nextIcon, { expand: true, x_fill: false });
|
||||
|
||||
// this.entry.actor.width = this.colors.actor.width;
|
||||
// this.colors.entry.actor.width = this.colors.actor.width;
|
||||
this.state = "NORMAL";
|
||||
}
|
||||
|
||||
@@ -372,27 +453,16 @@ class WorkspaceMenu extends PanelMenu.Button {
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
// WorkspaceMenu.prototype._onOpenStateChanged = function
|
||||
_onOpenStateChanged(menu, open) {
|
||||
if (!open)
|
||||
return;
|
||||
|
||||
// FIXME: 3.32: An StEntry cannot have `text` when shown the first time,
|
||||
// as it will crash the shell. We handle this by setting the text when
|
||||
// the entry first gains focus, only then can we start updating the text
|
||||
// property safely.
|
||||
let space = Tiling.spaces.spaceOf(workspaceManager.get_active_workspace());
|
||||
if (this.entry.actor.text != '') {
|
||||
this.entry.actor.text = space.name;
|
||||
} else {
|
||||
this.entry.actor.hint_text = space.name;
|
||||
}
|
||||
if (this.entry.actor.text != '') {
|
||||
this.colors.entry.actor.text = space.color;
|
||||
} else {
|
||||
this.colors.actor.hint_text = space.name;
|
||||
}
|
||||
this.entry.label.text = space.name;
|
||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, this.entry.activate.bind(this.entry));
|
||||
|
||||
this._zenItem._switch.setToggleState(space.showTopBar);
|
||||
this._zenItem._switch.setToggleState(!space.showTopBar);
|
||||
}
|
||||
|
||||
workspaceSwitched(wm, fromIndex, toIndex) {
|
||||
|
||||
3
utils.js
3
utils.js
@@ -19,9 +19,8 @@ var version = imports.misc.config.PACKAGE_VERSION.split('.').map(Number);
|
||||
if (version[0] >= 3 && version[1] > 30) {
|
||||
registerClass = GObject.registerClass;
|
||||
} else {
|
||||
registerClass = (x => x);
|
||||
registerClass = (x, y) => y ? y : x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var debug_all = false; // Turn off by default
|
||||
|
||||
Reference in New Issue
Block a user