From e6b5f376a5f53d5fb82f5bc310627daba00b4dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Hedin=20Br=C3=B8nner?= Date: Sat, 15 Aug 2020 17:36:06 +0200 Subject: [PATCH 01/26] sticky center --- tiling.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tiling.js b/tiling.js index a0c25421e..c2ebb4290 100644 --- a/tiling.js +++ b/tiling.js @@ -2482,6 +2482,15 @@ function animateDown(metaWindow) { }); } +function isCentered(metaWindow, space) { + space = space || spaces.spaceOfWindow(metaWindow) + let workArea = space.workArea() + let clone = metaWindow.clone; + let f = metaWindow.get_frame_rect(); + let x = clone.targetX + space.targetX; + return x + (f.width)/2 === workArea.x + workArea.width/2 +} + function ensuredX(meta_window, space) { let index = space.indexOf(meta_window); let last = space.selectedWindow; @@ -2502,7 +2511,9 @@ function ensuredX(meta_window, space) { let workArea = space.workArea(); let min = workArea.x; let max = min + workArea.width; - if (meta_window.fullscreen) { + if (isCentered(last, space)) { + x = min + Math.round((workArea.width - frame.width)/2); + } else if (meta_window.fullscreen) { x = 0; } else if (index == 0 && x <= min) { // Always align the first window to the display's left edge From 2e9e312f38261a5c5c082d27443f342358e4b730 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 4 Mar 2023 00:17:19 +1100 Subject: [PATCH 02/26] Updated sticky-center branch to latest code (and latest centering approach). --- tiling.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tiling.js b/tiling.js index fb4b68800..1e0b95890 100644 --- a/tiling.js +++ b/tiling.js @@ -2666,13 +2666,16 @@ function animateDown(metaWindow) { }); } +/** + * Return true if current selected window is centered. + */ function isCentered(metaWindow, space) { space = space || spaces.spaceOfWindow(metaWindow) let workArea = space.workArea() let clone = metaWindow.clone; - let f = metaWindow.get_frame_rect(); - let x = clone.targetX + space.targetX; - return x + (f.width)/2 === workArea.x + workArea.width/2 + let frame = metaWindow.get_frame_rect(); + let x = clone.targetX + space.targetX; + return x === workArea.x + Math.round(workArea.width/2 - frame.width/2); } function ensuredX(meta_window, space) { @@ -2696,7 +2699,8 @@ function ensuredX(meta_window, space) { let min = workArea.x; let max = min + workArea.width; if (isCentered(last, space)) { - x = min + Math.round((workArea.width - frame.width)/2); + // current window is centered, continue centering + x = workArea.x + Math.round(workArea.width/2 - frame.width/2); } else if (meta_window.fullscreen) { x = 0; } else if (index == 0 && x <= min) { From 9df98aa0d52f892e9093c103ae3034121bda95c7 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 4 Mar 2023 00:54:17 +1100 Subject: [PATCH 03/26] Pressing the center-horizontally shortcut again results in unhorizontal-ling (gets of out center mode). --- tiling.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tiling.js b/tiling.js index 1e0b95890..a9b565e32 100644 --- a/tiling.js +++ b/tiling.js @@ -3262,12 +3262,24 @@ function activateWindowAfterRendered(actor, mw) { }); } +/** + * Centers the currently selected window. + */ function centerWindowHorizontally(metaWindow) { const frame = metaWindow.get_frame_rect(); const space = spaces.spaceOfWindow(metaWindow); + const index = space.indexOf(metaWindow); const monitor = space.monitor; const workArea = space.workArea(); - const targetX = workArea.x + Math.round(workArea.width/2 - frame.width/2); + + let targetX; + // if already centered, then uncenter by moving selected window to left edge + if (isCentered(metaWindow, space)) { + // check if is against left tiling edge + targetX = workArea.x + index == 0 ? 0 : prefs.horizontal_margin; + } else { + targetX = workArea.x + Math.round((workArea.width - frame.width)/2); + } const dx = targetX - (metaWindow.clone.targetX + space.targetX); let [pointerX, pointerY, mask] = global.get_pointer(); From 54afadbf0820e74fd63ce91dbfdac731148a18ed Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 5 Mar 2023 20:53:57 +1100 Subject: [PATCH 04/26] Added FocusModes and new bindsym "toggle-focus-mode". Updated schema. --- keybindings.js | 4 ++ prefsKeybinding.js | 1 + schemas/gschemas.compiled | Bin 6480 -> 6584 bytes ...gnome.shell.extensions.paperwm.gschema.xml | 4 ++ tiling.js | 54 +++++++++--------- 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/keybindings.js b/keybindings.js index bb756a21c..52f4a1fde 100644 --- a/keybindings.js +++ b/keybindings.js @@ -199,6 +199,10 @@ function init() { Tiling), Meta.KeyBindingFlags.PER_WINDOW); + registerPaperAction("toggle-center-mode", + dynamic_function_ref("toggleCentreFocusMode", + Tiling)); + registerPaperAction('new-window', dynamic_function_ref('duplicateWindow', App), diff --git a/prefsKeybinding.js b/prefsKeybinding.js index 94b635246..0b66f76d2 100644 --- a/prefsKeybinding.js +++ b/prefsKeybinding.js @@ -44,6 +44,7 @@ const actions = { 'slurp-in', 'barf-out', 'center-horizontally', + 'toggle-center-mode', 'paper-toggle-fullscreen', 'toggle-maximize-width', 'resize-h-inc', diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 4cfa6a878ffbf7a3773da937e0bd488d97a16657..375e93b18c4a0deb0e2b622d885d42851854a5e6 100644 GIT binary patch literal 6584 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 literal 6480 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 HO45G;;W+Be diff --git a/schemas/org.gnome.shell.extensions.paperwm.gschema.xml b/schemas/org.gnome.shell.extensions.paperwm.gschema.xml index 8fde372fa..f4aebb877 100644 --- a/schemas/org.gnome.shell.extensions.paperwm.gschema.xml +++ b/schemas/org.gnome.shell.extensions.paperwm.gschema.xml @@ -204,6 +204,10 @@ c']]]> Center window horizontally + + c']]]> + Toggle "center" mode (automatically centers window on select) + f']]]> diff --git a/tiling.js b/tiling.js index a9b565e32..6355d7caa 100644 --- a/tiling.js +++ b/tiling.js @@ -63,6 +63,9 @@ var sizeSlack = 30; var PreviewMode = {NONE: 0, STACK: 1, SEQUENTIAL: 2}; var inPreview = PreviewMode.NONE; +// DEFAULT mode is normal/original PaperWM window focus behaviour +var FocusModes = {DEFAULT: 0, CENTRE: 1}; + var signals, oldSpaces, backgroundGroup, oldMonitors, WindowCloneLayout, grabSignals; function init() { @@ -138,11 +141,14 @@ var Space = class Space extends Array { this.workspace = workspace; this.signals = new utils.Signals(); - // The windows that should be represented by their WindowActor + // windows that should be represented by their WindowActor this.visible = []; this._floating = []; this._populated = false; + // default focusMode (can be overriden by saved user pref in Space.init method) + this.focusMode = FocusModes.DEFAULT; + let clip = new Clutter.Actor({name: "clip"}); this.clip = clip; let actor = new Clutter.Actor({name: "space-actor"}); @@ -1446,7 +1452,7 @@ var Spaces = class Spaces extends Map { this.switchWorkspace.bind(this)); this.signals.connect(this.overrideSettings, 'changed::workspaces-only-on-primary', - this.monitorsChanged.bind(this)); + this.monitorsChanged.bind(this)); // Clone and hook up existing windows display.get_tab_list(Meta.TabList.NORMAL_ALL, null) @@ -2666,18 +2672,6 @@ function animateDown(metaWindow) { }); } -/** - * Return true if current selected window is centered. - */ -function isCentered(metaWindow, space) { - space = space || spaces.spaceOfWindow(metaWindow) - let workArea = space.workArea() - let clone = metaWindow.clone; - let frame = metaWindow.get_frame_rect(); - let x = clone.targetX + space.targetX; - return x === workArea.x + Math.round(workArea.width/2 - frame.width/2); -} - function ensuredX(meta_window, space) { let index = space.indexOf(meta_window); let last = space.selectedWindow; @@ -2698,8 +2692,8 @@ function ensuredX(meta_window, space) { let workArea = space.workArea(); let min = workArea.x; let max = min + workArea.width; - if (isCentered(last, space)) { - // current window is centered, continue centering + if (space.focusMode == FocusModes.CENTRE) { + // window switching should centre focus x = workArea.x + Math.round(workArea.width/2 - frame.width/2); } else if (meta_window.fullscreen) { x = 0; @@ -2731,7 +2725,6 @@ function ensuredX(meta_window, space) { return x; } - /** Make sure that `meta_window` is in view, scrolling the space if needed. */ @@ -3272,14 +3265,7 @@ function centerWindowHorizontally(metaWindow) { const monitor = space.monitor; const workArea = space.workArea(); - let targetX; - // if already centered, then uncenter by moving selected window to left edge - if (isCentered(metaWindow, space)) { - // check if is against left tiling edge - targetX = workArea.x + index == 0 ? 0 : prefs.horizontal_margin; - } else { - targetX = workArea.x + Math.round((workArea.width - frame.width)/2); - } + const targetX = workArea.x + Math.round((workArea.width - frame.width)/2); const dx = targetX - (metaWindow.clone.targetX + space.targetX); let [pointerX, pointerY, mask] = global.get_pointer(); @@ -3296,6 +3282,22 @@ function centerWindowHorizontally(metaWindow) { } } +/** + * Enables CENTRE focusMode of if not currently enabled, otherwise switches back to DEFAULT mode. + * NOTE: if more FocusModes are added in the future (e.g. zenmode etc.) then + * will likely need to track/store the mode before switching to center mode. + * Not needed at the moment though. + */ +function toggleCentreFocusMode(space) { + space = space ?? spaces.spaceOf(workspaceManager.get_active_workspace()); + + if (space.focusMode == FocusModes.CENTRE) { + space.focusMode = FocusModes.DEFAULT; + } else { + space.focusMode = FocusModes.CENTRE; + } +} + /** * "Fit" values such that they sum to `targetSum` */ @@ -3459,7 +3461,6 @@ function moveUpSpace(mw, space) { spaces.selectSequenceSpace(Meta.MotionDirection.UP, true); } - /** Detach the @metaWindow, storing it at the bottom right corner while navigating. When done, insert all the detached windows again. @@ -3563,7 +3564,6 @@ function cycleWorkspaceSettings(dir=1) { return space; } - // Backward compatibility function defwinprop(...args) { return Settings.defwinprop(...args); From a74ecd90ff4ab7ac5202eb51099e7552b2230db5 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 5 Mar 2023 21:50:43 +1100 Subject: [PATCH 05/26] Entering center mode now also centers selectedWindow as well. --- tiling.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tiling.js b/tiling.js index 6355d7caa..731c3c22b 100644 --- a/tiling.js +++ b/tiling.js @@ -3283,18 +3283,22 @@ function centerWindowHorizontally(metaWindow) { } /** - * Enables CENTRE focusMode of if not currently enabled, otherwise switches back to DEFAULT mode. + * Enables CENTRE focusMode if not currently enabled, otherwise switches back to DEFAULT mode. * NOTE: if more FocusModes are added in the future (e.g. zenmode etc.) then * will likely need to track/store the mode before switching to center mode. * Not needed at the moment though. */ function toggleCentreFocusMode(space) { space = space ?? spaces.spaceOf(workspaceManager.get_active_workspace()); - if (space.focusMode == FocusModes.CENTRE) { space.focusMode = FocusModes.DEFAULT; - } else { + } + else { space.focusMode = FocusModes.CENTRE; + // center current active window + if (space.selectedWindow) { + centerWindowHorizontally(space.selectedWindow); + } } } From 1d82adfddda1feb497f2c0a58af5429d84b821b1 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 5 Mar 2023 23:17:02 +1100 Subject: [PATCH 06/26] Added simple "focus mode" icon in topbar (which shows current focus mode). --- tiling.js | 30 +++++++++++++++++++++++------- topbar.js | 29 ++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/tiling.js b/tiling.js index 731c3c22b..b68d825ac 100644 --- a/tiling.js +++ b/tiling.js @@ -3282,23 +3282,39 @@ function centerWindowHorizontally(metaWindow) { } } +/** + * Sets the focus mode for a space. + * @param {Space} space + * @param {FocusModes} mode + */ +function setFocusMode(space, mode) { + space = space ?? spaces.spaceOf(workspaceManager.get_active_workspace()); + space.focusMode = mode; + if (mode === FocusModes.DEFAULT) { + TopBar.focusMenu.setIconDefault(); + } + else if (mode === FocusModes.CENTRE) { + TopBar.focusMenu.setIconCenter(); + if (space.selectedWindow) { + centerWindowHorizontally(space.selectedWindow); + } + } +} + /** * Enables CENTRE focusMode if not currently enabled, otherwise switches back to DEFAULT mode. * NOTE: if more FocusModes are added in the future (e.g. zenmode etc.) then * will likely need to track/store the mode before switching to center mode. * Not needed at the moment though. + * @param {Space} space */ function toggleCentreFocusMode(space) { space = space ?? spaces.spaceOf(workspaceManager.get_active_workspace()); - if (space.focusMode == FocusModes.CENTRE) { - space.focusMode = FocusModes.DEFAULT; + if (space.focusMode === FocusModes.CENTRE) { + setFocusMode(space, FocusModes.DEFAULT); } else { - space.focusMode = FocusModes.CENTRE; - // center current active window - if (space.selectedWindow) { - centerWindowHorizontally(space.selectedWindow); - } + setFocusMode(space, FocusModes.CENTRE); } } diff --git a/topbar.js b/topbar.js index 4e0f5ed95..e45d6745a 100644 --- a/topbar.js +++ b/topbar.js @@ -197,6 +197,29 @@ class ColorEntry { } } +var FocusMenu = Utils.registerClass( +class FocusMenu extends PanelMenu.Button { + _init() { + super._init(0.0, 'FocusMode'); + + this._icon = new St.Icon({ + style_class: 'system-status-icon', + }); + + this.setIconDefault(); + this.add_child(this._icon); + } + + setIconDefault() { + this._icon.icon_name = 'sidebar-show-right-symbolic'; + } + + setIconCenter() { + this._icon.icon_name = 'preferences-desktop-multitasking-symbolic'; + } +} +); + var WorkspaceMenu = Utils.registerClass( class WorkspaceMenu extends PanelMenu.Button { _init() { @@ -487,6 +510,7 @@ class WorkspaceMenu extends PanelMenu.Button { } }); +var focusMenu; var menu; var orginalActivitiesText; var screenSignals, signals; @@ -501,6 +525,9 @@ var panelBoxShowId, panelBoxHideId; function enable () { Main.panel.statusArea.activities.hide(); + focusMenu = new FocusMenu(); + Main.panel.addToStatusArea('FocusMode', focusMenu, 0, 'left'); + menu = new WorkspaceMenu(); // Work around 'actor' warnings let panel = Main.panel; @@ -514,7 +541,7 @@ function enable () { space.label.clutter_text.set_font_description(fontDescription); } } - Main.panel.addToStatusArea('WorkspaceMenu', menu, 0, 'left'); + Main.panel.addToStatusArea('WorkspaceMenu', menu, 1, 'left'); menu.show(); // Force transparency From 75c48a950df7d7a6c5436259335a16b01250c7b5 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 6 Mar 2023 01:28:05 +1100 Subject: [PATCH 07/26] Focus mode icon is now clickable and cycles through focus modes when clicked. --- tiling.js | 20 ++++++++++---------- topbar.js | 54 ++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/tiling.js b/tiling.js index b68d825ac..5268e17fb 100644 --- a/tiling.js +++ b/tiling.js @@ -3284,17 +3284,17 @@ function centerWindowHorizontally(metaWindow) { /** * Sets the focus mode for a space. - * @param {Space} space * @param {FocusModes} mode + * @param {Space} space + * @param {boolean} push: if true also pushes change to Topbar.focusMenu */ -function setFocusMode(space, mode) { +function setFocusMode(mode, space, push=true) { space = space ?? spaces.spaceOf(workspaceManager.get_active_workspace()); space.focusMode = mode; - if (mode === FocusModes.DEFAULT) { - TopBar.focusMenu.setIconDefault(); - } - else if (mode === FocusModes.CENTRE) { - TopBar.focusMenu.setIconCenter(); + push && TopBar.focusMenu.setFocusMode(mode); + + // if centre also center selectedWindow + if (mode === FocusModes.CENTRE) { if (space.selectedWindow) { centerWindowHorizontally(space.selectedWindow); } @@ -3306,15 +3306,15 @@ function setFocusMode(space, mode) { * NOTE: if more FocusModes are added in the future (e.g. zenmode etc.) then * will likely need to track/store the mode before switching to center mode. * Not needed at the moment though. - * @param {Space} space + * @param {Space} space */ function toggleCentreFocusMode(space) { space = space ?? spaces.spaceOf(workspaceManager.get_active_workspace()); if (space.focusMode === FocusModes.CENTRE) { - setFocusMode(space, FocusModes.DEFAULT); + setFocusMode(FocusModes.DEFAULT, space); } else { - setFocusMode(space, FocusModes.CENTRE); + setFocusMode(FocusModes.CENTRE, space); } } diff --git a/topbar.js b/topbar.js index e45d6745a..6ed414d7b 100644 --- a/topbar.js +++ b/topbar.js @@ -203,19 +203,49 @@ class FocusMenu extends PanelMenu.Button { super._init(0.0, 'FocusMode'); this._icon = new St.Icon({ - style_class: 'system-status-icon', - }); + style_class: 'system-status-icon', + }); - this.setIconDefault(); + this.setFocusMode(Tiling.FocusModes.DEFAULT); this.add_child(this._icon); + + this.connect('event', this._onClicked.bind(this)); } - setIconDefault() { - this._icon.icon_name = 'sidebar-show-right-symbolic'; + /** + * Sets the focus mode with this button. + * @param {*} mode + * @param {Boolean} push: if true also calls the Tiling.setFocusMode method + */ + setFocusMode(mode, push=false) { + this.focusMode = mode; + if (mode === Tiling.FocusModes.DEFAULT) { + this._icon.icon_name = 'sidebar-show-right-symbolic'; + } + else if (mode === Tiling.FocusModes.CENTRE) { + this._icon.icon_name = 'preferences-desktop-multitasking-symbolic'; + } + + // if push, call Tiling.setFocusMode + push && Tiling.setFocusMode(mode, undefined, false); } - setIconCenter() { - this._icon.icon_name = 'preferences-desktop-multitasking-symbolic'; + switchToNextFocusMode() { + const numModes = Object.keys(Tiling.FocusModes).length; + // for currMode we switch to 1-based to use it validly in remainder operation + const currMode = Object.values(Tiling.FocusModes).indexOf(this.focusMode) + 1; + const nextMode = (currMode % numModes); + this.setFocusMode(nextMode, true); + } + + _onClicked(actor, event) { + if (event.type() !== Clutter.EventType.TOUCH_BEGIN && + event.type() !== Clutter.EventType.BUTTON_PRESS) { + return Clutter.EVENT_PROPAGATE; + } + + this.switchToNextFocusMode(); + return Clutter.EVENT_PROPAGATE; } } ); @@ -265,7 +295,6 @@ class WorkspaceMenu extends PanelMenu.Button { this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - this._prefItem = new PopupMenu.PopupImageMenuItem('Workspace preference', 'preferences-system-symbolic'); this.menu.addMenuItem(this._prefItem); @@ -279,7 +308,6 @@ class WorkspaceMenu extends PanelMenu.Button { let temp_file = Gio.File.new_for_path(GLib.get_tmp_dir()).get_child('paperwm.workspace') temp_file.replace_contents(wi.toString(), null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null) imports.misc.extensionUtils.openPrefs() - }); @@ -589,6 +617,8 @@ function enable () { function disable() { signals.destroy(); + focusMenu.destroy(); + focusMenu = null; menu.destroy(); menu = null; Main.panel.statusArea.activities.actor.show(); @@ -635,8 +665,12 @@ function updateWorkspaceIndicator (index) { let space = spaces && spaces.spaceOf(workspaceManager.get_workspace_by_index(index)); let onMonitor = space && space.monitor === panelMonitor; let nav = Navigator.navigator - if (onMonitor || (Tiling.inPreview && nav && nav.from.monitor === panelMonitor)) + if (onMonitor || (Tiling.inPreview && nav && nav.from.monitor === panelMonitor)) { setWorkspaceName(space.name); + + // also update focus mode + focusMenu.setFocusMode(space.focusMode); + } }; function setWorkspaceName (name) { From 2f565f4d2af840b4410f4e09a945fdd123490768 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Tue, 7 Mar 2023 22:13:46 +1100 Subject: [PATCH 08/26] Now using a FocusIcon class to encapsulate icon logic. Added icon to space so shows up in Preview modes. --- stylesheet.css | 5 +++++ tiling.js | 6 ++++-- topbar.js | 38 +++++++++++++++++++++++++++----------- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/stylesheet.css b/stylesheet.css index 79826c9e1..dfd0c4ee9 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,3 +1,8 @@ +.focus-mode-icon { + icon-size: 16px; + padding: 8px 0 0 22px; +} + .workspace-icon-button { -st-icon-style: symbolic; border: none; diff --git a/tiling.js b/tiling.js index 5268e17fb..60bc42d7b 100644 --- a/tiling.js +++ b/tiling.js @@ -148,6 +148,8 @@ var Space = class Space extends Array { // default focusMode (can be overriden by saved user pref in Space.init method) this.focusMode = FocusModes.DEFAULT; + this.focusModeIcon = new TopBar.FocusIcon('focus-mode-icon'); + this.focusModeIcon.setMode(FocusModes.DEFAULT); let clip = new Clutter.Actor({name: "clip"}); this.clip = clip; @@ -188,6 +190,7 @@ var Space = class Space extends Array { container.add_actor(clip); clip.add_actor(actor); + actor.add_child(this.focusModeIcon); actor.add_actor(labelParent); actor.add_actor(cloneClip); cloneClip.add_actor(cloneContainer); @@ -1847,7 +1850,6 @@ var Spaces = class Spaces extends Map { } selectSequenceSpace(direction, move) { - // if in stack preview do not run sequence preview if (inPreview === PreviewMode.STACK) { return; @@ -2001,7 +2003,6 @@ var Spaces = class Spaces extends Map { } selectStackSpace(direction, move) { - // if in sequence preview do not run stack preview if (inPreview === PreviewMode.SEQUENTIAL) { return; @@ -3291,6 +3292,7 @@ function centerWindowHorizontally(metaWindow) { function setFocusMode(mode, space, push=true) { space = space ?? spaces.spaceOf(workspaceManager.get_active_workspace()); space.focusMode = mode; + space.focusModeIcon.setMode(mode); push && TopBar.focusMenu.setFocusMode(mode); // if centre also center selectedWindow diff --git a/topbar.js b/topbar.js index 6ed414d7b..188141d51 100644 --- a/topbar.js +++ b/topbar.js @@ -69,8 +69,7 @@ var PopupMenuEntryHelper = function constructor(text) { this.label.set_style(` width: 232px; -`); - + `); this.prevIcon = createButton('go-previous-symbolic', 'previous workspace setting'); this.nextIcon = createButton('go-next-symbolic', 'next workspace setting'); @@ -197,14 +196,32 @@ class ColorEntry { } } +/** + * FocusMode icon class. + */ +var FocusIcon = Utils.registerClass( +class FocusIcon extends St.Icon { + _init(styleClass='') { + super._init({style_class: styleClass}); + } + + setMode(mode) { + if (mode === Tiling.FocusModes.DEFAULT) { + this.icon_name = 'sidebar-show-right-symbolic'; + } + else if (mode === Tiling.FocusModes.CENTRE) { + this.icon_name = 'preferences-desktop-multitasking-symbolic'; + } + } +} +); + var FocusMenu = Utils.registerClass( class FocusMenu extends PanelMenu.Button { _init() { super._init(0.0, 'FocusMode'); - this._icon = new St.Icon({ - style_class: 'system-status-icon', - }); + this._icon = new FocusIcon('system-status-icon'); this.setFocusMode(Tiling.FocusModes.DEFAULT); this.add_child(this._icon); @@ -219,12 +236,7 @@ class FocusMenu extends PanelMenu.Button { */ setFocusMode(mode, push=false) { this.focusMode = mode; - if (mode === Tiling.FocusModes.DEFAULT) { - this._icon.icon_name = 'sidebar-show-right-symbolic'; - } - else if (mode === Tiling.FocusModes.CENTRE) { - this._icon.icon_name = 'preferences-desktop-multitasking-symbolic'; - } + this._icon.setMode(mode); // if push, call Tiling.setFocusMode push && Tiling.setFocusMode(mode, undefined, false); @@ -239,6 +251,10 @@ class FocusMenu extends PanelMenu.Button { } _onClicked(actor, event) { + if (Tiling.inPreview != Tiling.PreviewMode.NONE || Main.overview.visible) { + return Clutter.EVENT_PROPAGATE; + } + if (event.type() !== Clutter.EventType.TOUCH_BEGIN && event.type() !== Clutter.EventType.BUTTON_PRESS) { return Clutter.EVENT_PROPAGATE; From 066b779975879d45645c577e9b32122988e01aa3 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Tue, 7 Mar 2023 22:52:18 +1100 Subject: [PATCH 09/26] Hides space icons during normal view (designed to be shown during workspace switch previewing. --- tiling.js | 19 ++++++++++++++----- topbar.js | 13 +++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/tiling.js b/tiling.js index 60bc42d7b..087ae8552 100644 --- a/tiling.js +++ b/tiling.js @@ -149,7 +149,7 @@ var Space = class Space extends Array { // default focusMode (can be overriden by saved user pref in Space.init method) this.focusMode = FocusModes.DEFAULT; this.focusModeIcon = new TopBar.FocusIcon('focus-mode-icon'); - this.focusModeIcon.setMode(FocusModes.DEFAULT); + this.focusModeIcon.setVisible(false); // hide by default let clip = new Clutter.Actor({name: "clip"}); this.clip = clip; @@ -1767,6 +1767,7 @@ var Spaces = class Spaces extends Map { } inPreview = PreviewMode.NONE; + this.showSpaceFocusIcons(false); } _getOrderedSpaces(monitor) { @@ -1786,6 +1787,7 @@ var Spaces = class Spaces extends Map { return; } inPreview = PreviewMode.SEQUENTIAL; + this.showSpaceFocusIcons(); if (Main.panel.statusArea.appMenu) { Main.panel.statusArea.appMenu.container.hide(); @@ -1920,11 +1922,11 @@ var Spaces = class Spaces extends Map { } _initWorkspaceStack() { - - if (inPreview) + if (inPreview) { return; - + } inPreview = PreviewMode.STACK; + this.showSpaceFocusIcons(); // Always show the topbar when using the workspace stack TopBar.fixTopBar(); @@ -2081,7 +2083,6 @@ var Spaces = class Spaces extends Map { } animateToSpace(to, from, callback) { - let currentPreviewMode = inPreview; inPreview = PreviewMode.NONE; @@ -2283,6 +2284,14 @@ var Spaces = class Spaces extends Map { insertWindow(metaWindow, {existing: false}); }); }; + + /** + * Shows or hides focus icons in spaces. + * @param {boolean} show + */ + showSpaceFocusIcons(show = true) { + this.forEach(s => s.focusModeIcon.setVisible(show)); + } } Signals.addSignalMethods(Spaces.prototype); diff --git a/topbar.js b/topbar.js index 188141d51..2fff24dd9 100644 --- a/topbar.js +++ b/topbar.js @@ -203,8 +203,13 @@ var FocusIcon = Utils.registerClass( class FocusIcon extends St.Icon { _init(styleClass='') { super._init({style_class: styleClass}); + this.setMode(Tiling.FocusModes.DEFAULT); } + /** + * Set the mode that this icon will display. + * @param {Tiling.FocusModes} mode + */ setMode(mode) { if (mode === Tiling.FocusModes.DEFAULT) { this.icon_name = 'sidebar-show-right-symbolic'; @@ -213,6 +218,14 @@ class FocusIcon extends St.Icon { this.icon_name = 'preferences-desktop-multitasking-symbolic'; } } + + /** + * Sets visibility of icon. + * @param {boolean} visible + */ + setVisible(visible = true) { + this.visible = visible; + } } ); From 215a72274148c339da041a49adeac2e2d8af4192 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Wed, 8 Mar 2023 01:45:35 +1100 Subject: [PATCH 10/26] Refactor naming to refer to "focus modes" in shortcuts and internally. --- keybindings.js | 8 ++++---- prefsKeybinding.js | 2 +- schemas/gschemas.compiled | Bin 6584 -> 6560 bytes ...gnome.shell.extensions.paperwm.gschema.xml | 9 +++++---- tiling.js | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/keybindings.js b/keybindings.js index 52f4a1fde..a057c5641 100644 --- a/keybindings.js +++ b/keybindings.js @@ -160,6 +160,10 @@ function init() { Scratch), Meta.KeyBindingFlags.PER_WINDOW); + registerPaperAction("switch-focus-mode", + dynamic_function_ref("switchFocusMode", + Tiling)); + registerPaperAction("develop-set-globals", dynamic_function_ref("setDevGlobals", Utils)); @@ -199,10 +203,6 @@ function init() { Tiling), Meta.KeyBindingFlags.PER_WINDOW); - registerPaperAction("toggle-center-mode", - dynamic_function_ref("toggleCentreFocusMode", - Tiling)); - registerPaperAction('new-window', dynamic_function_ref('duplicateWindow', App), diff --git a/prefsKeybinding.js b/prefsKeybinding.js index 0b66f76d2..55ad66f3b 100644 --- a/prefsKeybinding.js +++ b/prefsKeybinding.js @@ -37,6 +37,7 @@ const actions = { 'switch-last', 'live-alt-tab', 'live-alt-tab-backward', + 'switch-focus-mode', 'move-left', 'move-right', 'move-up', @@ -44,7 +45,6 @@ const actions = { 'slurp-in', 'barf-out', 'center-horizontally', - 'toggle-center-mode', 'paper-toggle-fullscreen', 'toggle-maximize-width', 'resize-h-inc', diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 375e93b18c4a0deb0e2b622d885d42851854a5e6..28b95b28fa6c554058664a55db53ea8794675a58 100644 GIT binary patch delta 2938 zcmZveeN0tl0LEVo1o`k1@|i(sA{X^4X@6LH)l3=|rt_m=S&DG+-gV)!doQ3)xmeR! zWl^V+OdFa7SuV_+ZCT-0np5K+6U!E}FKa7lvSnGb-*befTX*~IdCv2`=Y7vP@7Mis zQtPDVg%6!_7&Foon_jdl#h92hW3KWm%rN{)jC2Mp=?%R%h(vxI_5JANOk*Z~GP*F!YDk~>!nxF}!IZ@IGXzcOC&{`ec~~TwE4nnP*O89Tf?MEL$nGZx&4rPW zcO3=zG5^C@vT^;m&Se}SQ| z96hc2^0DNXmBkxV<~#g^a(M@NE;c~&m%Ijj39_$7 z=P8%h1GS?^VDxVzl9kKr3-zE^;G?Hf_bZpzgT^uYbKrPg$faDKp^unC%mc7~?hlKsj zHG%OT;!b~B1y>0)8Iu!PFfgzg$lIF%+6U)O~o%V(&5k})ngbY|NuSdq(K^T(ccN+p{o5CMvu45_@ZSDbyCHcs)PWuZ|ELGM)sVctP#1b0N_SnW zFR%K&Xw*EzXMGP)2_KfN}G(gIkS{|mIDY!<1=W`yPTql@vT6sfu^h1(_f1_;TjL2%o4Ua3s|-(@ z?_1#wGc}!Mp@MMP;~rPNueu^o&)xm?!Yn)$miq&t>q@N$W3%oG)%(KbURPzHyf);j z3RHM*Y`fef+qYH)>O2%z`@(^sE2s|lG{!dE6l>?THP+hr?6gHSd<*px^n`q?Jua`S z!c%TJ5{9Rid#b~ppvxNw`c?<3!)1Q|Dq~eA?2O#TL+Tia1|17J2DJUN*|3-moohT8 zY+$_`#@*xs+p~RC=r}2WVW1;r6pRBMD-&Tj=r;y*6mk05M+FPPq*yUYi>>WR>6-BapMG|A$P)~6 ztG-MBxAuD~!vp0d@`=}%R{DaW@PGFg2dX?bmix<8JaB(ebp;bmjoTw(k4%)=)0Z?i zDrS65S=eheW{tA8IKGeQ^w%2cK`%gP-_aUr&gF%H_3LWTLsS!~N?g z%H=c3C!=oIpHw_Xxx99%dFUco=Q)<5T%M&CF?bwkj-AfQ~He`AadW)VEIDY{z)^4g8O=&O+TtTUoqK8d^?{Qx!(dZ|gd zyynU=^dt-%Ao4mux={V2ytVX-Tccb)n!E+wD$?Gz>&sI=$FyTQV0}iz3f&;D tRndtavF2oc>t4u3$g0EKU%r7fK{5i>b1fc4#Mb8E2-82AHC< z1VO5!*r=GIECoVXDxpRKWl;SXn6i{WZc^GO?L+)wl=KP`f%Xn!Lt~zUhcKcK^nDH<#?Y{#Q8NGr21!L< zfFUsKIqdk%XJkFS7*04M$VfCRNH+SEz?P6C|6r0@p4n!q%{p`|bWJi#mCHwx??>;$ zrk}T$DVL8TH{rYnJp5o$hI07?ayvR1>h^AYSGl~}&qqt(^7iTHl;iy-o`O2UMp%<= zPgjAw8frn?A!F9GC-iF=?RP|b(;wxO{bkw*iiYsdwT7kV>`$|}9xw+3c}r=*luRy!T#l@%^urN`m1 zYN|caijM6P|&`weLfw+fw8mBh<<1Yu+uPTPtF0IGdc@&UhqwVkm ziQXEQuc*{fR_OJS=@%S|X%)pZtI_SQ;#_J~36@XSr7iGI^ngHp^nf8tT^_G5Sd>>; z?&N)SuQhts2WYm%%nTXlt1Kxgb2^Hg6+WkjFI4P&)?;w+i+B^=n&mF^m0C~Kyf`)@ z#IGaYS|S=TUeJ5^wA&gayp~!rnhO6s*!j0|d2JTi=y=$c^Vd=3^2y}+=v+7woi|*$ zye4odS`Mq6ZSl(GS!sS#huHwOVQITnAm5K0n$Z37-<`arTwY736@37|=Euh>mro^+ z<5MQWPdg`0RW7dwwWB%kcJ7!e^8fbi2J{$I zx1W2U8|1Z?ucFuC@Q%r;%H`GZBQ%l4u=DsqYlP&j6Aev+LH6Y#sxPmR7>~{cPtNR0 zP U@(jPWVtGB{_h?Jtjg*=H1JFkquK)l5 diff --git a/schemas/org.gnome.shell.extensions.paperwm.gschema.xml b/schemas/org.gnome.shell.extensions.paperwm.gschema.xml index f4aebb877..ecd6add34 100644 --- a/schemas/org.gnome.shell.extensions.paperwm.gschema.xml +++ b/schemas/org.gnome.shell.extensions.paperwm.gschema.xml @@ -108,6 +108,11 @@ t']]]> Take the window, dropping it when finished navigating + + + c']]]> + Switch between focus modes (default or center-window focus mode) + period']]]> @@ -204,10 +209,6 @@ c']]]> Center window horizontally - - c']]]> - Toggle "center" mode (automatically centers window on select) - f']]]> diff --git a/tiling.js b/tiling.js index 087ae8552..b92b32bb4 100644 --- a/tiling.js +++ b/tiling.js @@ -3319,7 +3319,7 @@ function setFocusMode(mode, space, push=true) { * Not needed at the moment though. * @param {Space} space */ -function toggleCentreFocusMode(space) { +function switchFocusMode(space) { space = space ?? spaces.spaceOf(workspaceManager.get_active_workspace()); if (space.focusMode === FocusModes.CENTRE) { setFocusMode(FocusModes.DEFAULT, space); From 4ddd68b8040a0adf3e959b36607d399da3e26b1a Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 12 Mar 2023 10:01:56 +1100 Subject: [PATCH 11/26] Switching back normal focus mode (from centering mode) will move the current centered window back in the direction it was original centered from. E.g. if centering causes the window to center from left-to-right, then uncentering will cause windows to move from right-to-left to an edge. --- tiling.js | 54 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/tiling.js b/tiling.js index 3105e8037..ff0bdbc34 100644 --- a/tiling.js +++ b/tiling.js @@ -149,6 +149,7 @@ var Space = class Space extends Array { this.focusMode = FocusModes.DEFAULT; this.focusModeIcon = new TopBar.FocusIcon('focus-mode-icon'); this.focusModeIcon.setVisible(false); // hide by default + let unfocusXPosition = null; let clip = new Clutter.Actor({name: "clip"}); this.clip = clip; @@ -595,7 +596,7 @@ var Space = class Space extends Array { isFullyVisible(metaWindow) { let clone = metaWindow.clone; - let x = clone.targetX + this.targetX; + let x = this.visibleX(metaWindow); let workArea = this.workArea(); let min = workArea.x; @@ -603,9 +604,8 @@ var Space = class Space extends Array { } visibleRatio(metaWindow) { - let clone = metaWindow.clone; - let x = clone.targetX + this.targetX; + let x = this.visibleX(metaWindow); let workArea = this.workArea(); let min = workArea.x; @@ -617,7 +617,7 @@ var Space = class Space extends Array { isPlaceable(metaWindow) { let clone = metaWindow.clone; - let x = clone.targetX + this.targetX; + let x = this.visibleX(metaWindow); let workArea = Main.layoutManager.getWorkAreaForMonitor(this.monitor.index); let min = workArea.x - this.monitor.x; @@ -686,7 +686,7 @@ var Space = class Space extends Array { return let f = w.get_frame_rect(); let clone = w.clone; - let x = clone.targetX + this.targetX; + let x = this.visibleX(w); let y = this.monitor.y + clone.targetY; x = Math.min(this.width - stack_margin, Math.max(stack_margin - f.width, x)); x += this.monitor.x; @@ -882,6 +882,20 @@ var Space = class Space extends Array { ensureViewport(metaWindow, space); } + /** + * Return the x position of the visible element of this window. + */ + visibleX(metaWindow) { + return metaWindow.clone.targetX + this.targetX; + } + + /** + * Return the y position of the visible element of this window. + */ + visibleY(metaWindow) { + return metaWindow.clone.targetY + this.monitor.y; + } + positionOf(metaWindow) { metaWindow = metaWindow || this.selectedWindow; let index, row; @@ -956,10 +970,9 @@ var Space = class Space extends Array { if (unMovable) return; - let clone = w.clone; let f = w.get_frame_rect(); - let x = clone.targetX + this.targetX; - let y = monitor.y + clone.targetY; + let x = this.visibleX(w); + let y = this.visibleY(w); x = Math.max(stack_margin - f.width, x); x = Math.min(this.width - stack_margin, x); x += monitor.x; @@ -2898,6 +2911,7 @@ function ensuredX(meta_window, space) { let workArea = space.workArea(); let min = workArea.x; let max = min + workArea.width; + if (space.focusMode == FocusModes.CENTRE) { // window switching should centre focus x = workArea.x + Math.round(workArea.width/2 - frame.width/2); @@ -2912,7 +2926,6 @@ function ensuredX(meta_window, space) { } else if (frame.width > workArea.width*0.9 - 2*(prefs.horizontal_margin + prefs.window_gap)) { // Consider the window to be wide and center it x = min + Math.round((workArea.width - frame.width)/2); - } else if (x + frame.width > max) { // Align to the right prefs.horizontal_margin x = max - prefs.horizontal_margin - frame.width; @@ -3501,10 +3514,29 @@ function setFocusMode(mode, space, push=true) { // if centre also center selectedWindow if (mode === FocusModes.CENTRE) { - if (space.selectedWindow) { - centerWindowHorizontally(space.selectedWindow); + const selwin = space.selectedWindow; + if (selwin) { + // check it closer to min or max of workArea + const workArea = space.workArea(); + const frame = selwin.get_frame_rect(); + const winMidpoint = space.visibleX(selwin) + frame.width/2; + const monMidpoint = workArea.width/2; + if (winMidpoint <= monMidpoint) { + space.unfocusXPosition = 0; + } else { + space.unfocusXPosition = workArea.width; + } + centerWindowHorizontally(selwin); } } + + // if normal and has saved x position from previous + if (mode === FocusModes.DEFAULT && space.unfocusXPosition != null) { + move_to(space, space.selectedWindow, { + x:space.unfocusXPosition}); + ensureViewport(space.selectedWindow, space, true); + space.unfocusXPosition = null; + } } /** From a8577a14c38d4152ad8c618670cd5585840de5ae Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 12 Mar 2023 20:01:07 +1100 Subject: [PATCH 12/26] Now uncentering treats the first or last window specially, lines up with left/right edge. --- tiling.js | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/tiling.js b/tiling.js index ff0bdbc34..3360ff3ae 100644 --- a/tiling.js +++ b/tiling.js @@ -3512,28 +3512,40 @@ function setFocusMode(mode, space, push=true) { space.focusModeIcon.setMode(mode); push && TopBar.focusMenu.setFocusMode(mode); + const workArea = space.workArea(); + const selectedWin = space.selectedWindow; // if centre also center selectedWindow if (mode === FocusModes.CENTRE) { - const selwin = space.selectedWindow; - if (selwin) { + if (selectedWin) { // check it closer to min or max of workArea - const workArea = space.workArea(); - const frame = selwin.get_frame_rect(); - const winMidpoint = space.visibleX(selwin) + frame.width/2; - const monMidpoint = workArea.width/2; - if (winMidpoint <= monMidpoint) { + const frame = selectedWin.get_frame_rect(); + const winMidpoint = space.visibleX(selectedWin) + frame.width/2; + const workAreaMidpoint = workArea.width/2; + if (winMidpoint <= workAreaMidpoint) { space.unfocusXPosition = 0; } else { space.unfocusXPosition = workArea.width; } - centerWindowHorizontally(selwin); + centerWindowHorizontally(selectedWin); } } // if normal and has saved x position from previous if (mode === FocusModes.DEFAULT && space.unfocusXPosition != null) { - move_to(space, space.selectedWindow, { - x:space.unfocusXPosition}); + // if window is first, move to left edge + let position; + if (space.indexOf(selectedWin) == 0) { + position = 0; + } + // if windows is last, move to right edge + else if (space.indexOf(selectedWin) == space.length - 1) { + position = workArea.width; + } + else { + position = space.unfocusXPosition; + } + // do the move + move_to(space, space.selectedWindow, {x:position}); ensureViewport(space.selectedWindow, space, true); space.unfocusXPosition = null; } From 04aa77aa2897cd49c5de13f8dc6fb0df7580fa56 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 13 Mar 2023 02:15:55 +1100 Subject: [PATCH 13/26] Refactor topbar.focusButton. Moved to after workspace name. Now the space's focusModeIcon gets position from panel focusButton. --- stylesheet.css | 2 +- tiling.js | 27 ++++++++++++++++++++------- topbar.js | 38 +++++++++++++++++++++++--------------- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/stylesheet.css b/stylesheet.css index e2a42f161..432e8ae39 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,6 +1,6 @@ .focus-mode-icon { icon-size: 16px; - padding: 8px 0 0 22px; + padding: 8px 0 0 21px; } .topbar-clear { diff --git a/tiling.js b/tiling.js index 3360ff3ae..ff9c810a3 100644 --- a/tiling.js +++ b/tiling.js @@ -148,8 +148,9 @@ var Space = class Space extends Array { // default focusMode (can be overriden by saved user pref in Space.init method) this.focusMode = FocusModes.DEFAULT; this.focusModeIcon = new TopBar.FocusIcon('focus-mode-icon'); + this.focusModeIcon.setMode(this.focusMode); this.focusModeIcon.setVisible(false); // hide by default - let unfocusXPosition = null; + this.unfocusXPosition = null; // init let clip = new Clutter.Actor({name: "clip"}); this.clip = clip; @@ -188,8 +189,8 @@ var Space = class Space extends Array { container.add_actor(clip); clip.add_actor(actor); - actor.add_child(this.focusModeIcon); actor.add_actor(labelParent); + actor.add_child(this.focusModeIcon); actor.add_actor(cloneClip); cloneClip.add_actor(cloneContainer); @@ -248,7 +249,7 @@ var Space = class Space extends Array { this.targetX = oldSpace.targetX; } this.cloneContainer.x = this.targetX; - + // init window position bar and space topbar elements this.windowPositionBarBackdrop.width = this.monitor.width; this.windowPositionBarBackdrop.height = TopBar.panelBox.height; @@ -1305,10 +1306,11 @@ border-radius: ${borderWidth}px; } if (visible) { - this.focusModeIcon.raise_top(); this.labelParent.raise_top(); - this.focusModeIcon.show(); this.label.show(); + + this.focusModeIcon.raise_top(); + this.focusModeIcon.show(); } else { this.focusModeIcon.hide(); @@ -1966,6 +1968,17 @@ var Spaces = class Spaces extends Map { }); } + /** + * Sets the focusIconPosition for all spaces. + * @param {int} x + * @param {int} y + */ + setFocusIconPosition(x=0, y=0) { + this.forEach(s => { + s.focusModeIcon.set_position(x, y); + }); + } + _getOrderedSpaces(monitor) { let nWorkspaces = workspaceManager.n_workspaces; let out = []; @@ -3504,13 +3517,13 @@ function centerWindowHorizontally(metaWindow) { * Sets the focus mode for a space. * @param {FocusModes} mode * @param {Space} space - * @param {boolean} push: if true also pushes change to Topbar.focusMenu + * @param {boolean} push: if true also pushes change to Topbar.focusButton */ function setFocusMode(mode, space, push=true) { space = space ?? spaces.spaceOf(workspaceManager.get_active_workspace()); space.focusMode = mode; space.focusModeIcon.setMode(mode); - push && TopBar.focusMenu.setFocusMode(mode); + push && TopBar.focusButton.setFocusMode(mode); const workArea = space.workArea(); const selectedWin = space.selectedWindow; diff --git a/topbar.js b/topbar.js index ceb0155b7..dd14573de 100644 --- a/topbar.js +++ b/topbar.js @@ -203,14 +203,13 @@ var FocusIcon = Utils.registerClass( class FocusIcon extends St.Icon { _init(styleClass='') { super._init({style_class: styleClass}); - this.setMode(Tiling.FocusModes.DEFAULT); } /** * Set the mode that this icon will display. - * @param {Tiling.FocusModes} mode + * @param {Tiling.FocusModes} mode */ - setMode(mode) { + setMode(mode=Tiling.FocusModes.DEFAULT) { if (mode === Tiling.FocusModes.DEFAULT) { this.icon_name = 'sidebar-show-right-symbolic'; } @@ -229,14 +228,19 @@ class FocusIcon extends St.Icon { } ); -var FocusMenu = Utils.registerClass( -class FocusMenu extends PanelMenu.Button { +var FocusButton = Utils.registerClass({ + Signals: { + 'focus-button-added': {}, + } +}, +class FocusButton extends PanelMenu.Button { _init() { super._init(0.0, 'FocusMode'); + this.focusMode = Tiling.FocusModes.DEFAULT; this._icon = new FocusIcon('system-status-icon'); + this.setFocusMode(this.focusMode); - this.setFocusMode(Tiling.FocusModes.DEFAULT); this.add_child(this._icon); this.connect('event', this._onClicked.bind(this)); @@ -339,7 +343,6 @@ class WorkspaceMenu extends PanelMenu.Button { imports.misc.extensionUtils.openPrefs() }); - // this.iconBox = new St.BoxLayout(); // this.menu.box.add(this.iconBox); @@ -567,8 +570,8 @@ class WorkspaceMenu extends PanelMenu.Button { } }); -var focusMenu; var menu; +var focusButton; var orginalActivitiesText; var screenSignals, signals; function init () { @@ -582,9 +585,6 @@ var panelBoxShowId, panelBoxHideId; function enable () { Main.panel.statusArea.activities.hide(); - focusMenu = new FocusMenu(); - Main.panel.addToStatusArea('FocusMode', focusMenu, 0, 'left'); - menu = new WorkspaceMenu(); // Work around 'actor' warnings let panel = Main.panel; @@ -598,9 +598,17 @@ function enable () { space.label.clutter_text.set_font_description(fontDescription); } } - Main.panel.addToStatusArea('WorkspaceMenu', menu, 1, 'left'); + Main.panel.addToStatusArea('WorkspaceMenu', menu, 0, 'left'); menu.show(); + focusButton = new FocusButton(); + Main.panel.addToStatusArea('FocusButton', focusButton, 1, 'left'); + signals.connect(focusButton, 'notify::allocation', () => { + const pos = focusButton.apply_relative_transform_to_point(panel, + new Clutter.Vertex({ x: 0, y: 0 })); + Tiling.spaces.setFocusIconPosition(pos.x, pos.y); + }); + fixStyle(); screenSignals.push( @@ -659,8 +667,8 @@ function enable () { function disable() { signals.destroy(); - focusMenu.destroy(); - focusMenu = null; + focusButton.destroy(); + focusButton = null; menu.destroy(); menu = null; Main.panel.statusArea.activities.actor.show(); @@ -726,7 +734,7 @@ function updateWorkspaceIndicator (index) { setWorkspaceName(space.name); // also update focus mode - focusMenu.setFocusMode(space.focusMode); + focusButton.setFocusMode(space.focusMode); } }; From 8e1f449dca97600204e344fd810390646d1bc475 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 13 Mar 2023 02:31:49 +1100 Subject: [PATCH 14/26] Small improvements to setters in FocusModeIcon. --- tiling.js | 6 +++--- topbar.js | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tiling.js b/tiling.js index ff9c810a3..4c3bd4268 100644 --- a/tiling.js +++ b/tiling.js @@ -147,9 +147,9 @@ var Space = class Space extends Array { // default focusMode (can be overriden by saved user pref in Space.init method) this.focusMode = FocusModes.DEFAULT; - this.focusModeIcon = new TopBar.FocusIcon('focus-mode-icon'); - this.focusModeIcon.setMode(this.focusMode); - this.focusModeIcon.setVisible(false); // hide by default + this.focusModeIcon = new TopBar.FocusIcon('focus-mode-icon') + .setMode(this.focusMode) + .setVisible(false); // hide by default this.unfocusXPosition = null; // init let clip = new Clutter.Actor({name: "clip"}); diff --git a/topbar.js b/topbar.js index dd14573de..147ed9e54 100644 --- a/topbar.js +++ b/topbar.js @@ -216,6 +216,7 @@ class FocusIcon extends St.Icon { else if (mode === Tiling.FocusModes.CENTRE) { this.icon_name = 'preferences-desktop-multitasking-symbolic'; } + return this; } /** @@ -224,6 +225,7 @@ class FocusIcon extends St.Icon { */ setVisible(visible = true) { this.visible = visible; + return this; } } ); @@ -257,6 +259,7 @@ class FocusButton extends PanelMenu.Button { // if push, call Tiling.setFocusMode push && Tiling.setFocusMode(mode, undefined, false); + return this; } switchToNextFocusMode() { From bab268dae2af49eeda27c56cf56e66b81b821420 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 13 Mar 2023 04:30:58 +1100 Subject: [PATCH 15/26] Refactor of space focus mode elements to allow clickability (on secondary monitors etc.). Added much needed helper methods for Spaces (getActiveSpace(), isActiveSpace()). --- keybindings.js | 2 +- navigator.js | 2 +- tiling.js | 62 +++++++++++++++++++++++++++++++------------------- topbar.js | 47 ++++++++++++++++++++++---------------- 4 files changed, 68 insertions(+), 45 deletions(-) diff --git a/keybindings.js b/keybindings.js index a057c5641..e5f9de721 100644 --- a/keybindings.js +++ b/keybindings.js @@ -161,7 +161,7 @@ function init() { Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction("switch-focus-mode", - dynamic_function_ref("switchFocusMode", + dynamic_function_ref("switchToNextFocusMode", Tiling)); registerPaperAction("develop-set-globals", diff --git a/navigator.js b/navigator.js index 200515fb8..94811d44b 100644 --- a/navigator.js +++ b/navigator.js @@ -261,7 +261,7 @@ class NavigatorClass { this._block = Main.wm._blockAnimations; Main.wm._blockAnimations = true; // Meta.disable_unredirect_for_screen(screen); - this.space = Tiling.spaces.spaceOf(workspaceManager.get_active_workspace()); + this.space = Tiling.spaces.getActiveSpace(); this._startWindow = this.space.selectedWindow; this.from = this.space; diff --git a/tiling.js b/tiling.js index 4c3bd4268..f7e30473d 100644 --- a/tiling.js +++ b/tiling.js @@ -149,6 +149,9 @@ var Space = class Space extends Array { this.focusMode = FocusModes.DEFAULT; this.focusModeIcon = new TopBar.FocusIcon('focus-mode-icon') .setMode(this.focusMode) + .setClickFunction(() => { + switchToNextFocusMode(this); + }) .setVisible(false); // hide by default this.unfocusXPosition = null; // init @@ -2066,7 +2069,7 @@ var Spaces = class Spaces extends Map { return; } - let currentSpace = this.spaceOf(workspaceManager.get_active_workspace()); + let currentSpace = this.getActiveSpace(); let monitorSpaces = this._getOrderedSpaces(currentSpace.monitor); if (!inPreview) { @@ -2141,7 +2144,7 @@ var Spaces = class Spaces extends Map { // Always show the topbar when using the workspace stack TopBar.fixTopBar(); const scale = 0.9; - let space = this.spaceOf(workspaceManager.get_active_workspace()); + let space = this.getActiveSpace(); let mru = [...this.stack]; this.monitors.forEach(space => mru.splice(mru.indexOf(space), 1)); mru = [space, ...mru]; @@ -2221,7 +2224,7 @@ var Spaces = class Spaces extends Map { } const scale = 0.9; - let space = this.spaceOf(workspaceManager.get_active_workspace()); + let space = this.getActiveSpace(); let mru = [...this.stack]; this.monitors.forEach(space => mru.splice(mru.indexOf(space), 1)); @@ -2420,6 +2423,22 @@ var Spaces = class Spaces extends Map { return this.get(workspace); }; + /** + * Returns the currently active space. + */ + getActiveSpace() { + return this.spaceOf(workspaceManager.get_active_workspace()); + } + + /** + * Returns true if the space is the currently active space. + * @param {Space} space + * @returns + */ + isActiveSpace(space) { + return space === this.getActiveSpace(); + } + /** Return an array of Space's ordered in most recently used order. */ @@ -3458,18 +3477,18 @@ function cycleWindowHeight(metaWindow) { } function activateNthWindow(n, space) { - space = space || spaces.spaceOf(workspaceManager.get_active_workspace()); + space = space || spaces.getActiveSpace(); let nth = space[n][0]; ensureViewport(nth, space); } function activateFirstWindow(mw, space) { - space = space || spaces.spaceOf(workspaceManager.get_active_workspace()); + space = space || spaces.getActiveSpace(); activateNthWindow(0, space); } function activateLastWindow(mw, space) { - space = space || spaces.spaceOf(workspaceManager.get_active_workspace()); + space = space || spaces.getActiveSpace(); activateNthWindow(space.length - 1, space); } @@ -3517,13 +3536,14 @@ function centerWindowHorizontally(metaWindow) { * Sets the focus mode for a space. * @param {FocusModes} mode * @param {Space} space - * @param {boolean} push: if true also pushes change to Topbar.focusButton */ -function setFocusMode(mode, space, push=true) { - space = space ?? spaces.spaceOf(workspaceManager.get_active_workspace()); +function setFocusMode(mode, space) { + space = space ?? spaces.getActiveSpace(); space.focusMode = mode; space.focusModeIcon.setMode(mode); - push && TopBar.focusButton.setFocusMode(mode); + if (space.hasTopBar()) { + TopBar.focusButton.setFocusMode(mode); + } const workArea = space.workArea(); const selectedWin = space.selectedWindow; @@ -3565,20 +3585,16 @@ function setFocusMode(mode, space, push=true) { } /** - * Enables CENTRE focusMode if not currently enabled, otherwise switches back to DEFAULT mode. - * NOTE: if more FocusModes are added in the future (e.g. zenmode etc.) then - * will likely need to track/store the mode before switching to center mode. - * Not needed at the moment though. - * @param {Space} space + * Switches to the next focus mode for a space. + * @param {Space} space */ -function switchFocusMode(space) { - space = space ?? spaces.spaceOf(workspaceManager.get_active_workspace()); - if (space.focusMode === FocusModes.CENTRE) { - setFocusMode(FocusModes.DEFAULT, space); - } - else { - setFocusMode(FocusModes.CENTRE, space); - } +function switchToNextFocusMode(space) { + space = space ?? spaces.getActiveSpace(); + const numModes = Object.keys(FocusModes).length; + // for currMode we switch to 1-based to use it validly in remainder operation + const currMode = Object.values(FocusModes).indexOf(space.focusMode) + 1; + const nextMode = (currMode % numModes); + setFocusMode(nextMode, space); } /** diff --git a/topbar.js b/topbar.js index 147ed9e54..c4f8c3893 100644 --- a/topbar.js +++ b/topbar.js @@ -190,7 +190,7 @@ class ColorEntry { } clicked() { - let space = Tiling.spaces.spaceOf(workspaceManager.get_active_workspace()); + let space = Tiling.spaces.getActiveSpace(); let color = this.entry.actor.text; space.settings.set_string('color', color); } @@ -201,10 +201,29 @@ class ColorEntry { */ var FocusIcon = Utils.registerClass( class FocusIcon extends St.Icon { - _init(styleClass='') { - super._init({style_class: styleClass}); - } + _init(styleClass = '') { + super._init({ + reactive: true, + style_class: styleClass + }); + + this.connect('button-press-event', () => { + if (this.clickFunction) { + this.clickFunction(); + } + }); + } + /** + * Sets a function to be executed on click. + * @param {Function} clickFunction + * @returns + */ + setClickFunction(clickFunction) { + this.clickFunction = clickFunction; + return this; + } + /** * Set the mode that this icon will display. * @param {Tiling.FocusModes} mode @@ -251,25 +270,13 @@ class FocusButton extends PanelMenu.Button { /** * Sets the focus mode with this button. * @param {*} mode - * @param {Boolean} push: if true also calls the Tiling.setFocusMode method */ - setFocusMode(mode, push=false) { + setFocusMode(mode) { this.focusMode = mode; this._icon.setMode(mode); - - // if push, call Tiling.setFocusMode - push && Tiling.setFocusMode(mode, undefined, false); return this; } - switchToNextFocusMode() { - const numModes = Object.keys(Tiling.FocusModes).length; - // for currMode we switch to 1-based to use it validly in remainder operation - const currMode = Object.values(Tiling.FocusModes).indexOf(this.focusMode) + 1; - const nextMode = (currMode % numModes); - this.setFocusMode(nextMode, true); - } - _onClicked(actor, event) { if (Tiling.inPreview != Tiling.PreviewMode.NONE || Main.overview.visible) { return Clutter.EVENT_PROPAGATE; @@ -280,7 +287,7 @@ class FocusButton extends PanelMenu.Button { return Clutter.EVENT_PROPAGATE; } - this.switchToNextFocusMode(); + Tiling.switchToNextFocusMode(); return Clutter.EVENT_PROPAGATE; } } @@ -437,7 +444,7 @@ class WorkspaceMenu extends PanelMenu.Button { && event.get_scroll_direction() === Clutter.ScrollDirection.SMOOTH) { let spaces = Tiling.spaces; - let active = spaces.spaceOf(workspaceManager.get_active_workspace()); + let active = spaces.getActiveSpace(); let [dx, dy] = event.get_scroll_delta(); dy *= active.height*0.05; @@ -549,7 +556,7 @@ class WorkspaceMenu extends PanelMenu.Button { if (!open) return; - let space = Tiling.spaces.spaceOf(workspaceManager.get_active_workspace()); + let space = Tiling.spaces.getActiveSpace(); this.entry.label.text = space.name; GLib.idle_add(GLib.PRIORITY_DEFAULT, this.entry.activate.bind(this.entry)); From 96afb749235a45555d69e927459b21aadd09f740 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 13 Mar 2023 04:37:42 +1100 Subject: [PATCH 16/26] Workspace names on other monitors (e.g. secondary monitor etc.) is now clickable (and opens overview). --- tiling.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tiling.js b/tiling.js index f7e30473d..402941553 100644 --- a/tiling.js +++ b/tiling.js @@ -176,7 +176,8 @@ var Space = class Space extends Array { border: none; `; this.labelParent = labelParent; - let label = new St.Label(); + let label = new St.Label({reactive: true}); + label.connect('button-press-event', () => Main.overview.toggle()); labelParent.add_actor(label); this.label = label; label.hide(); From 98409c1af88a81a6a3e3cc07a835054d62bbc079 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 13 Mar 2023 12:08:51 +1100 Subject: [PATCH 17/26] Improved click detection of space elements. Refactor and moved hard-coded css styles to stylesheet.css (now user overridable and more maintainable etc.). --- stylesheet.css | 13 +++++++++++-- tiling.js | 33 ++++++++++++++++++--------------- topbar.js | 15 ++++----------- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/stylesheet.css b/stylesheet.css index 432e8ae39..94db81de1 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,6 +1,15 @@ -.focus-mode-icon { +.space-label-wrapper { + padding: 0 12px 0 0; + background-color: transparent; + border-image: none; + background-image: none; + border: none; +} + +.space-focus-mode-icon { icon-size: 16px; - padding: 8px 0 0 21px; + padding: 0px 21px 0 21px; + background-color: transparent; } .topbar-clear { diff --git a/tiling.js b/tiling.js index 402941553..9c4d05da8 100644 --- a/tiling.js +++ b/tiling.js @@ -147,12 +147,17 @@ var Space = class Space extends Array { // default focusMode (can be overriden by saved user pref in Space.init method) this.focusMode = FocusModes.DEFAULT; - this.focusModeIcon = new TopBar.FocusIcon('focus-mode-icon') + this.focusModeIcon = new TopBar.FocusIcon({ + reactive: true, + name: 'panel', + style_class: 'space-focus-mode-icon', + }) .setMode(this.focusMode) .setClickFunction(() => { switchToNextFocusMode(this); }) .setVisible(false); // hide by default + this.focusModeIcon.name = 'panel'; this.unfocusXPosition = null; // init let clip = new Clutter.Actor({name: "clip"}); @@ -168,17 +173,15 @@ var Space = class Space extends Array { let cloneContainer = new St.Widget({name: "clone-container"}); this.cloneContainer = cloneContainer; - let labelParent = new St.Widget({name: 'panel'}); - labelParent.style = ` - background-color: transparent; - border-image: none; - background-image: none; - border: none; - `; - this.labelParent = labelParent; - let label = new St.Label({reactive: true}); - label.connect('button-press-event', () => Main.overview.toggle()); - labelParent.add_actor(label); + let labelWrapper = new St.Widget({ + reactive: true, + name: 'panel', + style_class: 'space-label-wrapper', + }); + labelWrapper.connect('button-press-event', () => Main.overview.toggle()); + this.labelWrapper = labelWrapper; + let label = new St.Label(); + labelWrapper.add_actor(label); this.label = label; label.hide(); @@ -193,7 +196,7 @@ var Space = class Space extends Array { container.add_actor(clip); clip.add_actor(actor); - actor.add_actor(labelParent); + actor.add_actor(labelWrapper); actor.add_child(this.focusModeIcon); actor.add_actor(cloneClip); cloneClip.add_actor(cloneContainer); @@ -1266,7 +1269,7 @@ border-radius: ${borderWidth}px; // show space duplicate elements if not primary monitor if (!this.hasTopBar()) { - this.labelParent.raise_top(); + this.labelWrapper.raise_top(); this.label.show(); } @@ -1310,7 +1313,7 @@ border-radius: ${borderWidth}px; } if (visible) { - this.labelParent.raise_top(); + this.labelWrapper.raise_top(); this.label.show(); this.focusModeIcon.raise_top(); diff --git a/topbar.js b/topbar.js index c4f8c3893..deaccbca0 100644 --- a/topbar.js +++ b/topbar.js @@ -201,11 +201,8 @@ class ColorEntry { */ var FocusIcon = Utils.registerClass( class FocusIcon extends St.Icon { - _init(styleClass = '') { - super._init({ - reactive: true, - style_class: styleClass - }); + _init(properties = {}) { + super._init(properties); this.connect('button-press-event', () => { if (this.clickFunction) { @@ -249,17 +246,13 @@ class FocusIcon extends St.Icon { } ); -var FocusButton = Utils.registerClass({ - Signals: { - 'focus-button-added': {}, - } -}, +var FocusButton = Utils.registerClass( class FocusButton extends PanelMenu.Button { _init() { super._init(0.0, 'FocusMode'); this.focusMode = Tiling.FocusModes.DEFAULT; - this._icon = new FocusIcon('system-status-icon'); + this._icon = new FocusIcon({style_class: 'system-status-icon'}); this.setFocusMode(this.focusMode); this.add_child(this._icon); From 4ff5a1562036bc899878405967ec0a25821910b2 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 13 Mar 2023 17:07:03 +1100 Subject: [PATCH 18/26] Added dconf settable setting to show/hide the new focus mode icon (in the topbar). To disable run `dconf write /org/gnome/shell/extensions/paperwm/show-focus-mode-icon false`. --- schemas/gschemas.compiled | Bin 6616 -> 6672 bytes ...gnome.shell.extensions.paperwm.gschema.xml | 7 ++++++- settings.js | 2 +- tiling.js | 19 ++++++++++++++---- topbar.js | 10 +++++++++ 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index a692e8655d3a7cd7bca7755028b5771013a444af..51ab5202bb5e4ab98b6e7738e3604f3454447816 100644 GIT binary patch delta 1624 zcmYjRU1%It7`=&!Zj((m-T&-%>sE~HYNrV%f<7dzQX~&iDy1meg1a-5oguq3 zK+~-cg`fquT#G>|2#VQON*nu7A5^NX7$2JUB@jg4>w^%8VpU2#XOhJZoIPjG{r1jx zzk9#CKH3~>zBv_$2+%Vb;x)=TkSOxywQ+b6xbrk;F;CbM$i6dqD z)M5Bd@L8Z;C2Ce_k&KK!>il4V@zfE-C!-A^GI;rCbLnpmQ19f2!OsF$KYt-ZpPC;y z1g-$V$A>P^r{)3{z)j$@@!!9tPo0F{0$&7vSlWM(J~ijR23`YZ8@Fz5a)2*s3~Ye^ z1m4kC!t|;8;RmqqQDEqFu0fx=4}K0j2E6xS*E)UbAp8U1w}4G;@C~p7xZ{Uy#OM7NuKgs;Q-F8%M~4$p^As$C*-!F*BqdYP=Nq13 z*Oh5ot$9kt)^x>GZA)~BTrscd(}h~OsuTj6PR1EzPt_-Y~C^GpqdxuWq|Do>NeDMYYSe zyOn{EuSQy#cCGwsR&57GbNy*qN%?+!kc;xG>eWq0SEgN4t(vwazlf$HHBVRmpW7-_ zbRk=DMUKbQfx2lquI+fTIXH&udRuj!&1TV>n~6W$JITr=ITtt zHFa0WpJKbXQL>yc8oVoa;4FLv{su7IKYr!zP_v(IgV%ue%|gwaWgWZ$9DI5_#CU2R z+PmO;z>C3;kJG2_f*-(c_5tT&=lytU#P1VHh%9g_aiYXOQ1dj8fO&aqrmL$}+nvLh okn_n~6THSbEF$TIh=q!GaLQDwKN8xMI-@XV2Ml z@7$m7-tTKXwLaFEIq-9@5V3wC?xPh`0_}hx&jUw(@z1uyp?+NK7fo=W3!y)Aa)kap z=u!BiX(1MY@Y(*+m798^KEQce?ICbS3lD?00G&V_=mNT1NPxFLfIjF4q2WLFDUtxz zjj#jEwSJ#CROEa-Os}Zcqc3Cly8X~VogLKML{;>Fb>PCWrYgQPZTY`R!<~K4 zPuY%dWsB1EbIJ;G1=A^;ZdIzPBWuwT*-XhPJ0;7*2&*XR2{9J6OZ$XjXZ)JuN%N?3 za)INPMfh5BM|egvQl65&Ur`drP|A@i`q0RRZ)*d5Uq&{AUnU@v7Retq9*aqiFht49 zM12Hc!ZX3Q0SIeU1h#^i{45SV0FECOgf=kpSg>%!0GuXpuy?a$sXUICb;G*W-NER+ zqYZ`&DSZzE^l#+KR!NFB?l3o(Lud-p$rl3C52WX#Mx}-x^OOsTW>|jaKl9V(vY0;{ zNv1GVntD!+HAD9q`w{ z*MU?0pGD)TF@CqW4Y2_%q>ktL0X6I3T`;S+?I@WGTs0Sdsb8I74d-+X@O!{NRg#*^ WFM)rcZf%#E+r0)}Plp%NFZ~7aLQQG_ diff --git a/schemas/org.gnome.shell.extensions.paperwm.gschema.xml b/schemas/org.gnome.shell.extensions.paperwm.gschema.xml index 3a993acdb..7bbea9dde 100644 --- a/schemas/org.gnome.shell.extensions.paperwm.gschema.xml +++ b/schemas/org.gnome.shell.extensions.paperwm.gschema.xml @@ -248,7 +248,7 @@ true - Wether to hide the top bar or not + Show the topbar '' @@ -379,6 +379,11 @@ Show the window position bar in the topbar + + true + Show the focus mode icon in the topbar + + 0.25 Duration of animations in seconds diff --git a/settings.js b/settings.js index 59afe6d7a..8cbf86ad1 100644 --- a/settings.js +++ b/settings.js @@ -35,7 +35,7 @@ var prefs = {}; 'workspace-colors', 'default-background', 'animation-time', 'use-workspace-name', 'pressure-barrier', 'default-show-top-bar', 'swipe-sensitivity', 'swipe-friction', 'cycle-width-steps', 'cycle-height-steps', 'topbar-follow-focus', 'minimap-scale', - 'winprops', 'show-window-position-bar'] + 'winprops', 'show-window-position-bar', 'show-focus-mode-icon'] .forEach((k) => setState(null, k)); prefs.__defineGetter__("minimum_margin", function() { return Math.min(15, this.horizontal_margin) }); diff --git a/tiling.js b/tiling.js index 9c4d05da8..6d60959a0 100644 --- a/tiling.js +++ b/tiling.js @@ -157,7 +157,7 @@ var Space = class Space extends Array { switchToNextFocusMode(this); }) .setVisible(false); // hide by default - this.focusModeIcon.name = 'panel'; + this.showFocusModeIcon(); this.unfocusXPosition = null; // init let clip = new Clutter.Actor({name: "clip"}); @@ -1315,13 +1315,24 @@ border-radius: ${borderWidth}px; if (visible) { this.labelWrapper.raise_top(); this.label.show(); + this.showFocusModeIcon(true); + } + else { + this.label.hide(); + this.showFocusModeIcon(false); + } + } + /** + * Shows the focusModeIcon space element. + * @param {boolean} show + */ + showFocusModeIcon(show=true) { + if (show && prefs.show_focus_mode_icon) { this.focusModeIcon.raise_top(); this.focusModeIcon.show(); - } - else { + } else { this.focusModeIcon.hide(); - this.label.hide(); } } diff --git a/topbar.js b/topbar.js index deaccbca0..43fb6f8d8 100644 --- a/topbar.js +++ b/topbar.js @@ -611,6 +611,7 @@ function enable () { new Clutter.Vertex({ x: 0, y: 0 })); Tiling.spaces.setFocusIconPosition(pos.x, pos.y); }); + fixFocusModeIcon(); fixStyle(); @@ -645,6 +646,10 @@ function enable () { spaces.showWindowPositionBarChanged(); }); + signals.connect(Settings.settings, 'changed::show-focus-mode-icon', (settings, key) => { + fixFocusModeIcon(); + }); + signals.connect(panelBox, 'show', () => { fixTopBar(); }); @@ -724,6 +729,11 @@ function fixTopBar() { } } +function fixFocusModeIcon() { + prefs.show_focus_mode_icon ? focusButton.show() : focusButton.hide(); + Tiling.spaces.forEach(s => s.showFocusModeIcon()); +} + /** Override the activities label with the workspace name. let workspaceIndex = 0 From 367f4b0443018a4303204403312c25fc0d9eafba Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 13 Mar 2023 18:27:36 +1100 Subject: [PATCH 19/26] Now packaging focus mode icons instead of relying on system icons (which can change with gnome ver or theme. Added improvement to space init - ensures correct layout with multimonitors and if gnome-shell resetting. --- resources/focus-mode-center-symbolic.svg | 4 +++ resources/focus-mode-default-symbolic.svg | 8 +++++ tiling.js | 20 ++++++++++--- topbar.js | 36 +++++++++++++++-------- 4 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 resources/focus-mode-center-symbolic.svg create mode 100644 resources/focus-mode-default-symbolic.svg diff --git a/resources/focus-mode-center-symbolic.svg b/resources/focus-mode-center-symbolic.svg new file mode 100644 index 000000000..50b8a84b6 --- /dev/null +++ b/resources/focus-mode-center-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/focus-mode-default-symbolic.svg b/resources/focus-mode-default-symbolic.svg new file mode 100644 index 000000000..7a2224df4 --- /dev/null +++ b/resources/focus-mode-default-symbolic.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tiling.js b/tiling.js index 6d60959a0..782fe1050 100644 --- a/tiling.js +++ b/tiling.js @@ -63,7 +63,7 @@ var PreviewMode = {NONE: 0, STACK: 1, SEQUENTIAL: 2}; var inPreview = PreviewMode.NONE; // DEFAULT mode is normal/original PaperWM window focus behaviour -var FocusModes = {DEFAULT: 0, CENTRE: 1}; +var FocusModes = {DEFAULT: 0, CENTER: 1}; var signals, oldSpaces, backgroundGroup, oldMonitors, WindowCloneLayout, grabSignals; @@ -265,7 +265,6 @@ var Space = class Space extends Array { this.getWindows().forEach(w => { animateWindow(w); }); - this.layout(false); let selected = this.selectedWindow; if (selected) { @@ -1679,6 +1678,19 @@ var Spaces = class Spaces extends Map { // Initialize spaces _after_ monitors are set up this.forEach(space => space.init()); + /** + * After spaces have init, do a final layout on active space and activate selected window. + * Ensures correct window layout with multi-monitors, and if windows already exist on init, + * (e.g. resetting gnome-shell) then will ensure selectedWindow is activated. + */ + imports.mainloop.timeout_add(0, () => { + const space = spaces.getActiveSpace(); + if (space.selectedWindow) { + space.layout(false); + Main.activateWindow(space.selectedWindow); + } + }); + this.stack = this.mru(); } @@ -2959,7 +2971,7 @@ function ensuredX(meta_window, space) { let min = workArea.x; let max = min + workArea.width; - if (space.focusMode == FocusModes.CENTRE) { + if (space.focusMode == FocusModes.CENTER) { // window switching should centre focus x = workArea.x + Math.round(workArea.width/2 - frame.width/2); } else if (meta_window.fullscreen) { @@ -3563,7 +3575,7 @@ function setFocusMode(mode, space) { const workArea = space.workArea(); const selectedWin = space.selectedWindow; // if centre also center selectedWindow - if (mode === FocusModes.CENTRE) { + if (mode === FocusModes.CENTER) { if (selectedWin) { // check it closer to min or max of workArea const frame = selectedWin.get_frame_rect(); diff --git a/topbar.js b/topbar.js index 43fb6f8d8..d3fd6d463 100644 --- a/topbar.js +++ b/topbar.js @@ -18,6 +18,7 @@ var PopupMenu = imports.ui.popupMenu; var Clutter = imports.gi.Clutter; var Main = imports.ui.main; var Tweener = Extension.imports.utils.tweener; +var Path = imports.misc.extensionUtils.getCurrentExtension().dir.get_path(); var Tiling = Extension.imports.tiling; var Navigator = Extension.imports.navigator; @@ -108,7 +109,6 @@ if (Utils.version[1] === 32) { PopupMenuEntryHelper.call(this, text); } - activate(event) { this.label.grab_key_focus(); } @@ -201,15 +201,19 @@ class ColorEntry { */ var FocusIcon = Utils.registerClass( class FocusIcon extends St.Icon { - _init(properties = {}) { - super._init(properties); + // read in focus icons from resources folder + static gIconDefault = Gio.icon_new_for_string(`${Path}/resources/focus-mode-default-symbolic.svg`); + static gIconCenter = Gio.icon_new_for_string(`${Path}/resources/focus-mode-center-symbolic.svg`); - this.connect('button-press-event', () => { - if (this.clickFunction) { - this.clickFunction(); - } - }); - } + _init(properties = {}) { + super._init(properties); + + this.connect('button-press-event', () => { + if (this.clickFunction) { + this.clickFunction(); + } + }); + } /** * Sets a function to be executed on click. @@ -225,12 +229,13 @@ class FocusIcon extends St.Icon { * Set the mode that this icon will display. * @param {Tiling.FocusModes} mode */ - setMode(mode=Tiling.FocusModes.DEFAULT) { + setMode(mode) { + mode = mode ?? Tiling.FocusModes.DEFAULT; if (mode === Tiling.FocusModes.DEFAULT) { - this.icon_name = 'sidebar-show-right-symbolic'; + this.gicon = FocusIcon.gIconDefault; } - else if (mode === Tiling.FocusModes.CENTRE) { - this.icon_name = 'preferences-desktop-multitasking-symbolic'; + else if (mode === Tiling.FocusModes.CENTER) { + this.gicon = FocusIcon.gIconCenter; } return this; } @@ -582,6 +587,11 @@ function init () { orginalActivitiesText = label.text; screenSignals = []; signals = new Utils.Signals(); + + // load focus icons + const path = imports.misc.extensionUtils.getCurrentExtension().dir.get_path(); + this.gIconFocusDefault = Gio.icon_new_for_string(`${path}/resources/focus-mode-default-symbolic.svg`); + this.gIconFocusCenter = Gio.icon_new_for_string(`${path}/resources/focus-mode-center-symbolic.svg`); } var panelBoxShowId, panelBoxHideId; From 50c8ca0408b46745b89ff6a72e37d6391f9e79d2 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Tue, 14 Mar 2023 00:21:21 +1100 Subject: [PATCH 20/26] Cleanup and removal of unneeded code (from icon loading test). --- topbar.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/topbar.js b/topbar.js index d3fd6d463..d04a3f8c7 100644 --- a/topbar.js +++ b/topbar.js @@ -587,11 +587,6 @@ function init () { orginalActivitiesText = label.text; screenSignals = []; signals = new Utils.Signals(); - - // load focus icons - const path = imports.misc.extensionUtils.getCurrentExtension().dir.get_path(); - this.gIconFocusDefault = Gio.icon_new_for_string(`${path}/resources/focus-mode-default-symbolic.svg`); - this.gIconFocusCenter = Gio.icon_new_for_string(`${path}/resources/focus-mode-center-symbolic.svg`); } var panelBoxShowId, panelBoxHideId; From a686b09c69860b3711f78ecade211a6a6d03bdff Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Tue, 14 Mar 2023 23:45:45 +1100 Subject: [PATCH 21/26] Added a focus mode icon "tooltip" (my version of one anyway). --- ...gnome.shell.extensions.paperwm.gschema.xml | 2 +- stylesheet.css | 7 +++ topbar.js | 63 ++++++++++++++++--- 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/schemas/org.gnome.shell.extensions.paperwm.gschema.xml b/schemas/org.gnome.shell.extensions.paperwm.gschema.xml index 7bbea9dde..ef69bcc2e 100644 --- a/schemas/org.gnome.shell.extensions.paperwm.gschema.xml +++ b/schemas/org.gnome.shell.extensions.paperwm.gschema.xml @@ -111,7 +111,7 @@ c']]]> - Switch between focus modes (default or center-window focus mode) + Switch between Window Focus Modes (e.g. default, center) diff --git a/stylesheet.css b/stylesheet.css index 94db81de1..cb1eb5773 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -12,6 +12,13 @@ background-color: transparent; } +.focus-button-tooltip { + background-color: rgba(0, 0, 0, 0.35); + padding: 8px; + border-radius: 8px; + font-weight: 600; +} + .topbar-clear { background-color: rgba(0, 0, 0, 0); } diff --git a/topbar.js b/topbar.js index d04a3f8c7..9dfcbaf09 100644 --- a/topbar.js +++ b/topbar.js @@ -201,13 +201,13 @@ class ColorEntry { */ var FocusIcon = Utils.registerClass( class FocusIcon extends St.Icon { - // read in focus icons from resources folder - static gIconDefault = Gio.icon_new_for_string(`${Path}/resources/focus-mode-default-symbolic.svg`); - static gIconCenter = Gio.icon_new_for_string(`${Path}/resources/focus-mode-center-symbolic.svg`); - _init(properties = {}) { super._init(properties); + // read in focus icons from resources folder + this.gIconDefault = Gio.icon_new_for_string(`${Path}/resources/focus-mode-default-symbolic.svg`); + this.gIconCenter = Gio.icon_new_for_string(`${Path}/resources/focus-mode-center-symbolic.svg`); + this.connect('button-press-event', () => { if (this.clickFunction) { this.clickFunction(); @@ -232,10 +232,10 @@ class FocusIcon extends St.Icon { setMode(mode) { mode = mode ?? Tiling.FocusModes.DEFAULT; if (mode === Tiling.FocusModes.DEFAULT) { - this.gicon = FocusIcon.gIconDefault; + this.gicon = this.gIconDefault; } else if (mode === Tiling.FocusModes.CENTER) { - this.gicon = FocusIcon.gIconCenter; + this.gicon = this.gIconCenter; } return this; } @@ -257,12 +257,55 @@ class FocusButton extends PanelMenu.Button { super._init(0.0, 'FocusMode'); this.focusMode = Tiling.FocusModes.DEFAULT; - this._icon = new FocusIcon({style_class: 'system-status-icon'}); + this._icon = new FocusIcon({ + reactive: true, + style_class: 'system-status-icon' + }); + this._initToolTip(); + this.setFocusMode(this.focusMode); - this.add_child(this._icon); - this.connect('event', this._onClicked.bind(this)); + this.connect('notify::allocation', () => { + let point = this._icon.apply_transform_to_point(new Clutter.Vertex({x: 0, y: 0})); + let pos = this.get_position(); + log('position', pos.x, pos.y); + }); + } + + _initToolTip() { + const tt = new St.Label({style_class: 'focus-button-tooltip'}); + tt.hide(); + global.stage.add_child(tt); + this._icon.connect('enter-event', icon => { + this._setTooltipText(); + tt.show(); + }); + this._icon.connect('leave-event', icon => { + tt.hide(); + }); + this.tooltip = tt; + } + + setTooltipPosition(x, y) { + this.tooltip.set_position(x, y); + } + + _setTooltipText() { + const markup = (color, mode) => { + this.tooltip.clutter_text + .set_markup( +` Window focus mode +Current mode: ${mode}`); + }; + if (this.focusMode == Tiling.FocusModes.DEFAULT) { + markup('#6be67b', 'DEFAULT'); + } + else if (this.focusMode == Tiling.FocusModes.CENTER) { + markup('#6be6cb', 'CENTER'); + } else { + this.tooltip.set_text(''); + } } /** @@ -272,6 +315,7 @@ class FocusButton extends PanelMenu.Button { setFocusMode(mode) { this.focusMode = mode; this._icon.setMode(mode); + this._setTooltipText() return this; } @@ -615,6 +659,7 @@ function enable () { const pos = focusButton.apply_relative_transform_to_point(panel, new Clutter.Vertex({ x: 0, y: 0 })); Tiling.spaces.setFocusIconPosition(pos.x, pos.y); + focusButton.setTooltipPosition(Math.max(0, pos.x - 56), pos.y + 34); }); fixFocusModeIcon(); From 0776e878c74221ac3f4d661d8cef3d8f6b6ee482 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Wed, 15 Mar 2023 10:07:49 +1100 Subject: [PATCH 22/26] FIX: focus mode icon tooltip now showing on correct monitor (in multi-monitor setup). --- stylesheet.css | 2 +- tiling.js | 2 +- topbar.js | 23 ++++++++++++----------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/stylesheet.css b/stylesheet.css index cb1eb5773..3dba14ac8 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -13,7 +13,7 @@ } .focus-button-tooltip { - background-color: rgba(0, 0, 0, 0.35); + background-color: rgba(0, 0, 0, 0.7); padding: 8px; border-radius: 8px; font-weight: 600; diff --git a/tiling.js b/tiling.js index 782fe1050..e32f5291f 100644 --- a/tiling.js +++ b/tiling.js @@ -1683,7 +1683,7 @@ var Spaces = class Spaces extends Map { * Ensures correct window layout with multi-monitors, and if windows already exist on init, * (e.g. resetting gnome-shell) then will ensure selectedWindow is activated. */ - imports.mainloop.timeout_add(0, () => { + imports.mainloop.timeout_add(200, () => { const space = spaces.getActiveSpace(); if (space.selectedWindow) { space.layout(false); diff --git a/topbar.js b/topbar.js index 9dfcbaf09..3ceab5364 100644 --- a/topbar.js +++ b/topbar.js @@ -266,11 +266,6 @@ class FocusButton extends PanelMenu.Button { this.setFocusMode(this.focusMode); this.add_child(this._icon); this.connect('event', this._onClicked.bind(this)); - this.connect('notify::allocation', () => { - let point = this._icon.apply_transform_to_point(new Clutter.Vertex({x: 0, y: 0})); - let pos = this.get_position(); - log('position', pos.x, pos.y); - }); } _initToolTip() { @@ -278,7 +273,8 @@ class FocusButton extends PanelMenu.Button { tt.hide(); global.stage.add_child(tt); this._icon.connect('enter-event', icon => { - this._setTooltipText(); + this._updateTooltipPosition(); + this._updateTooltipText(); tt.show(); }); this._icon.connect('leave-event', icon => { @@ -287,11 +283,17 @@ class FocusButton extends PanelMenu.Button { this.tooltip = tt; } - setTooltipPosition(x, y) { - this.tooltip.set_position(x, y); + /** + * Updates tooltip position relative to this button. + */ + _updateTooltipPosition() { + //const offset = Tiling.spaces.getActiveSpace().width; + let point = this.apply_transform_to_point( + new Clutter.Vertex({x: 0, y: 0})); + this.tooltip.set_position(Math.max(0, point.x - 56), point.y + 34); } - _setTooltipText() { + _updateTooltipText() { const markup = (color, mode) => { this.tooltip.clutter_text .set_markup( @@ -315,7 +317,7 @@ Current mode: ${mode}`); setFocusMode(mode) { this.focusMode = mode; this._icon.setMode(mode); - this._setTooltipText() + this._updateTooltipText() return this; } @@ -659,7 +661,6 @@ function enable () { const pos = focusButton.apply_relative_transform_to_point(panel, new Clutter.Vertex({ x: 0, y: 0 })); Tiling.spaces.setFocusIconPosition(pos.x, pos.y); - focusButton.setTooltipPosition(Math.max(0, pos.x - 56), pos.y + 34); }); fixFocusModeIcon(); From 06f505a957d55db81997b175da7fafff66a37907 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Wed, 15 Mar 2023 21:30:16 +1100 Subject: [PATCH 23/26] Moved tooltip to FocusIcon. Now shows for other monitors too. Added icon information (with reference Gnome Project copying terms). --- minimap.js | 4 +- resources/ICONS.info | 5 ++ stylesheet.css | 5 +- tiling.js | 1 - topbar.js | 108 +++++++++++++++++++++++-------------------- 5 files changed, 68 insertions(+), 55 deletions(-) create mode 100644 resources/ICONS.info diff --git a/minimap.js b/minimap.js index b235a9251..29975301d 100644 --- a/minimap.js +++ b/minimap.js @@ -122,7 +122,7 @@ var Minimap = class Minimap extends Array { } this.layout(); - let time = animate ? 0.25 : 0; + let time = animate ? prefs.animation_time : 0; this.actor.show(); Tweener.addTween(this.actor, {opacity: 255, time, mode: Clutter.AnimationMode.EASE_OUT_EXPO}); @@ -131,7 +131,7 @@ var Minimap = class Minimap extends Array { hide(animate) { if (this.destroyed) return; - let time = animate ? 0.25 : 0; + let time = animate ? prefs.animation_time : 0; Tweener.addTween(this.actor, {opacity: 0, time, mode: Clutter.AnimationMode.EASE_OUT_EXPO, onComplete: () => this.actor.hide() }); diff --git a/resources/ICONS.info b/resources/ICONS.info new file mode 100644 index 000000000..a789d6cff --- /dev/null +++ b/resources/ICONS.info @@ -0,0 +1,5 @@ +SVG icons adapted from "GNOME Project" adwaita-icon-theme (https://github.com/GNOME/adwaita-icon-theme). + +See http://www.gnome.org for more information. + +Please see terms, under which these icons have been copied, at https://github.com/GNOME/adwaita-icon-theme/blob/master/COPYING. \ No newline at end of file diff --git a/stylesheet.css b/stylesheet.css index 3dba14ac8..190ca5bbe 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,5 +1,5 @@ .space-label-wrapper { - padding: 0 12px 0 0; + padding: 0 10px 0 0; background-color: transparent; border-image: none; background-image: none; @@ -8,7 +8,8 @@ .space-focus-mode-icon { icon-size: 16px; - padding: 0px 21px 0 21px; + padding: 0 18px 0 18px; + margin-left: 3px; background-color: transparent; } diff --git a/tiling.js b/tiling.js index e32f5291f..70edab6bc 100644 --- a/tiling.js +++ b/tiling.js @@ -148,7 +148,6 @@ var Space = class Space extends Array { // default focusMode (can be overriden by saved user pref in Space.init method) this.focusMode = FocusModes.DEFAULT; this.focusModeIcon = new TopBar.FocusIcon({ - reactive: true, name: 'panel', style_class: 'space-focus-mode-icon', }) diff --git a/topbar.js b/topbar.js index 3ceab5364..48dbe8dd2 100644 --- a/topbar.js +++ b/topbar.js @@ -201,13 +201,20 @@ class ColorEntry { */ var FocusIcon = Utils.registerClass( class FocusIcon extends St.Icon { - _init(properties = {}) { + _init(properties = {}, tooltip_x_point=0) { super._init(properties); + this.reactive = true; + + // allow custom x position for tooltip + this.tooltip_x_point = tooltip_x_point; // read in focus icons from resources folder this.gIconDefault = Gio.icon_new_for_string(`${Path}/resources/focus-mode-default-symbolic.svg`); this.gIconCenter = Gio.icon_new_for_string(`${Path}/resources/focus-mode-center-symbolic.svg`); + this._initToolTip(); + this.setMode(); + this.connect('button-press-event', () => { if (this.clickFunction) { this.clickFunction(); @@ -224,6 +231,50 @@ class FocusIcon extends St.Icon { this.clickFunction = clickFunction; return this; } + + _initToolTip() { + const tt = new St.Label({style_class: 'focus-button-tooltip'}); + tt.hide(); + global.stage.add_child(tt); + this.connect('enter-event', icon => { + this._updateTooltipPosition(this.tooltip_x_point); + this._updateTooltipText(); + tt.show(); + }); + this.connect('leave-event', (icon, event) => { + if (!this.has_pointer) { + tt.hide(); + } + }); + this.tooltip = tt; + } + + /** + * Updates tooltip position relative to this button. + */ + _updateTooltipPosition(xpoint=0) { + //const offset = Tiling.spaces.getActiveSpace().width; + let point = this.apply_transform_to_point( + new Clutter.Vertex({x: xpoint, y: 0})); + this.tooltip.set_position(Math.max(0, point.x - 62), point.y + 34); + } + + _updateTooltipText() { + const markup = (color, mode) => { + this.tooltip.clutter_text + .set_markup( +` Window focus mode +Current mode: ${mode}`); + }; + if (this.mode === Tiling.FocusModes.DEFAULT) { + markup('#6be67b', 'DEFAULT'); + } + else if (this.mode === Tiling.FocusModes.CENTER) { + markup('#6be6cb', 'CENTER'); + } else { + this.tooltip.set_text(''); + } + } /** * Set the mode that this icon will display. @@ -231,12 +282,14 @@ class FocusIcon extends St.Icon { */ setMode(mode) { mode = mode ?? Tiling.FocusModes.DEFAULT; + this.mode = mode; if (mode === Tiling.FocusModes.DEFAULT) { this.gicon = this.gIconDefault; } else if (mode === Tiling.FocusModes.CENTER) { this.gicon = this.gIconCenter; } + this._updateTooltipText() return this; } @@ -256,68 +309,23 @@ class FocusButton extends PanelMenu.Button { _init() { super._init(0.0, 'FocusMode'); - this.focusMode = Tiling.FocusModes.DEFAULT; this._icon = new FocusIcon({ - reactive: true, - style_class: 'system-status-icon' - }); - this._initToolTip(); + style_class: 'system-status-icon focus-mode-button' + }, -10); - this.setFocusMode(this.focusMode); + this.setFocusMode(); this.add_child(this._icon); this.connect('event', this._onClicked.bind(this)); } - _initToolTip() { - const tt = new St.Label({style_class: 'focus-button-tooltip'}); - tt.hide(); - global.stage.add_child(tt); - this._icon.connect('enter-event', icon => { - this._updateTooltipPosition(); - this._updateTooltipText(); - tt.show(); - }); - this._icon.connect('leave-event', icon => { - tt.hide(); - }); - this.tooltip = tt; - } - - /** - * Updates tooltip position relative to this button. - */ - _updateTooltipPosition() { - //const offset = Tiling.spaces.getActiveSpace().width; - let point = this.apply_transform_to_point( - new Clutter.Vertex({x: 0, y: 0})); - this.tooltip.set_position(Math.max(0, point.x - 56), point.y + 34); - } - - _updateTooltipText() { - const markup = (color, mode) => { - this.tooltip.clutter_text - .set_markup( -` Window focus mode -Current mode: ${mode}`); - }; - if (this.focusMode == Tiling.FocusModes.DEFAULT) { - markup('#6be67b', 'DEFAULT'); - } - else if (this.focusMode == Tiling.FocusModes.CENTER) { - markup('#6be6cb', 'CENTER'); - } else { - this.tooltip.set_text(''); - } - } - /** * Sets the focus mode with this button. * @param {*} mode */ setFocusMode(mode) { + mode = mode ?? Tiling.FocusModes.DEFAULT; this.focusMode = mode; this._icon.setMode(mode); - this._updateTooltipText() return this; } From efbb81b6b9d4989617a629edd5a5b9bf8fc760d5 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala <30424662+jtaala@users.noreply.github.com> Date: Thu, 16 Mar 2023 19:42:28 +1100 Subject: [PATCH 24/26] Update resources/ICONS.info Co-authored-by: Matthias Seiffert --- resources/ICONS.info | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/ICONS.info b/resources/ICONS.info index a789d6cff..a206d0a7f 100644 --- a/resources/ICONS.info +++ b/resources/ICONS.info @@ -2,4 +2,8 @@ SVG icons adapted from "GNOME Project" adwaita-icon-theme (https://github.com/GN See http://www.gnome.org for more information. -Please see terms, under which these icons have been copied, at https://github.com/GNOME/adwaita-icon-theme/blob/master/COPYING. \ No newline at end of file +The icons are licensed under Creative Commons Attribution-Share Alike 3.0 United States License. + +To view a copy of the CC-BY-SA licence, visit +http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative +Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA. \ No newline at end of file From a67439f3e3ac784894ba1d0d265082a14fa8cf77 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Thu, 16 Mar 2023 22:20:14 +1100 Subject: [PATCH 25/26] Updated README.md with a section on focus modes (with picture). Added reference to original names of icons used. --- README.md | 19 +++++++++++++++++-- media/focus-mode-button.png | Bin 0 -> 15136 bytes resources/ICONS.info | 2 +- tiling.js | 5 ++--- 4 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 media/focus-mode-button.png diff --git a/README.md b/README.md index ef9946175..b586a25cf 100644 --- a/README.md +++ b/README.md @@ -273,7 +273,7 @@ Keybindings.bindkey("j", "my-favorite-width", See `examples/keybindings.js` for more examples. -### Window Position Bar (colored bar segment added to Gnome Top Bar) +## Window Position Bar (colored bar segment added to Gnome Top Bar) @@ -281,7 +281,7 @@ See `examples/keybindings.js` for more examples. https://user-images.githubusercontent.com/30424662/221416159-464d7512-5174-451b-9035-0ee84f9eb4ec.mp4 -The the window position bar can be _disabled_ from `PaperWM extension settings` or via `dconf`, e.g. by executing the following command a terminal: +The the window position bar can be _disabled_ from `PaperWM extension settings` or via `dconf`, e.g. by executing the following command in a terminal: ``` dconf write /org/gnome/shell/extensions/paperwm/show-window-position-bar false @@ -291,6 +291,21 @@ You can style both the coloured position bar and the dimmed "position bar backdr _Note: PaperWM overrides the default Gnome Top Bar style to be completely transparent so that the dimmed `window-position-bar-backdrop` and`window-position-bar` elements are visible._ +## Window Focus Mode ## + +[#482](https://github.com/paperwm/PaperWM/pull/482) added the concept of `window focus modes` to PaperWM. A `focus mode` controls how windows are "focused". For example, the `CENTER` focus mode causes all windows to be centered horizontally on selection, whereas the `DEFAULT` focus mode is the traditional PaperWM behaviour. + +Focus modes can be toggled by user-settable keybinding (default is `Super`+`Shift`+`c`), or by clicking the new focus-mode button in the topbar: + +![Focus mode button](media/focus-mode-button.png) + +You may prefer to hide the focus mode icon. You can do so by executing the following command in a terminal: + +``` +dconf write /org/gnome/shell/extensions/paperwm/show-focus-mode-icon false +``` + + ## Fixed Window Size ## See the [Winprops](#winprops) section for a way to set the default _width_ of windows identified by their `wm_class` window property. diff --git a/media/focus-mode-button.png b/media/focus-mode-button.png new file mode 100644 index 0000000000000000000000000000000000000000..f7405fc8695d26766e8e42f2c5a6e4f8d54c8d9f GIT binary patch literal 15136 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 I5yRmB0~k17kN^Mx literal 0 HcmV?d00001 diff --git a/resources/ICONS.info b/resources/ICONS.info index a206d0a7f..8cb9afe63 100644 --- a/resources/ICONS.info +++ b/resources/ICONS.info @@ -1,4 +1,4 @@ -SVG icons adapted from "GNOME Project" adwaita-icon-theme (https://github.com/GNOME/adwaita-icon-theme). +SVG icons adapted from `sidebar-show-right-symbolic.svg` and `preferences-desktop-multitasking-symbolic.svg` icons from "GNOME Project" adwaita-icon-theme (https://github.com/GNOME/adwaita-icon-theme). See http://www.gnome.org for more information. diff --git a/tiling.js b/tiling.js index 70edab6bc..69e15d3fe 100644 --- a/tiling.js +++ b/tiling.js @@ -2578,10 +2578,9 @@ function registerWindow(metaWindow) { } if (metaWindow.clone) { - // Should no longer be possible, but leave a trace just to be sure + // Can now happen when setting session-modes to "unlock-dialog" or + // resetting gnome-shell in-place (e.g. on X11) utils.warn("window already registered", metaWindow.title); - utils.print_stacktrace(); - // Can now happen when setting session-modes to "unlock-dialog" return false } From 0153216ff5407d5b660801c4fb228f5b59520957 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Thu, 16 Mar 2023 22:44:11 +1100 Subject: [PATCH 26/26] Small change to README.md. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 571d898e2..6626fad0e 100644 --- a/README.md +++ b/README.md @@ -274,7 +274,7 @@ Keybindings.bindkey("j", "my-favorite-width", See `examples/keybindings.js` for more examples. -## Window Position Bar (colored bar segment added to Gnome Top Bar) +## Window Position Bar (colored bar segment in Top Bar)