Skip to content

Commit

Permalink
Dim tiled windows when a non-tiled window (including transient window…
Browse files Browse the repository at this point in the history
…s) is focused (#546)

Resolves #99. 

PaperWM makes it easy to see the selected (tiled) window by giving it a
coloured border. However, the same can't be said for non-tiled windows,
i.e. scratch windows, floating windows, and transient windows (a
transient window is a floating window that takes focus from the parent -
e.g. when you open an extension settings from the `extensions` app).

This PR improves this by dimming the current selected (but not focused)
tiled window's border - which makes it easier to tell that a scratch,
floating, or transient window is currently focused.

It also intelligently handles transient windows (checks if a windows has
transient windows that are focused etc.).

In short, it provides a visual indicator that makes it easier to tell
when non-tiled windows are focused.
  • Loading branch information
jtaala authored Jun 13, 2023
2 parents 027fe40 + 3ef6e7d commit d7b53f3
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 19 deletions.
2 changes: 1 addition & 1 deletion grab.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ var MoveGrab = class MoveGrab {
}

begin({center} = {}) {
Utils.debug("#grab", "begin")
Utils.debug("#grab", "begin");

this.center = center;
if (this.grabbed)
Expand Down
7 changes: 7 additions & 0 deletions navigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ function getModLock(mods) {
nav.accept();
!this._destroy && nav.destroy();
dismissDispatcher(Clutter.GrabState.KEYBOARD)
let space = Tiling.spaces.selectedSpace;
let metaWindow = space.selectedWindow;
if (metaWindow) {
if (!metaWindow.appears_focused) {
space.setSelectionInactive();
}
}
}

destroy() {
Expand Down
118 changes: 100 additions & 18 deletions tiling.js
Original file line number Diff line number Diff line change
Expand Up @@ -2583,6 +2583,81 @@ var Spaces = class Spaces extends Map {

Signals.addSignalMethods(Spaces.prototype);

/**
* Return true if a window is tiled (e.g. not floating, not scratch, not transient).
* @param metaWindow
*/
function isTiled(metaWindow) {
if (!metaWindow) {
return false;
}

if (!isFloating(metaWindow) &&
!isScratch(metaWindow) &&
!isTransient(metaWindow)) {
return true;
}
else {
return false;
}
}

/**
* Transient windows are connected to a parent window and take focus.
* On Wayland it takes entire focus (can't focus parent window while it's open).
* @param metaWindow
* @returns
*/
function isTransient(metaWindow) {
if (!metaWindow) {
return false;
}
if (metaWindow.get_transient_for()) {
return true;
}
else {
return false;
}
}

/**
* Returns true if a metaWindow has at least one transient window.
* @param metaWindow
* @returns
*/
function hasTransient(metaWindow) {
if (!metaWindow) {
return false;
}
let hasTransient = false;
metaWindow.foreach_transient(t => {
hasTransient = true;
});

return hasTransient;
}

/**
* Conveniece method for checking if a window is floating.
* Will determine what space this window is on.
* @param metaWindow
* @returns
*/
function isFloating(metaWindow) {
if (!metaWindow) {
return false;
}
let space = spaces.spaceOfWindow(metaWindow);
return space.isFloating?.(metaWindow) ?? false;
}

function isScratch(metaWindow) {
if (!metaWindow) {
return false;
}
return Scratch.isScratchWindow(metaWindow);
}

function is_override_redirect(metaWindow) {
// Note: is_overrride_redirect() seem to be false for all wayland windows
const windowType = metaWindow.windowType;
Expand Down Expand Up @@ -2752,7 +2827,7 @@ function disable () {
Types of windows which never should be tiled.
*/
function add_filter(meta_window) {
if (meta_window.get_transient_for()) {
if (isTransient(meta_window)) {
// Never add transient windows
return false;
}
Expand Down Expand Up @@ -3086,9 +3161,18 @@ function updateSelection(space, metaWindow) {
// this means not active workspaces are shown as inactive
setAllWorkspacesInactive();

// then set the new selection active
space.setSelectionActive();
// if metawindow has transient window(s) and it's NOT focused,
// don't update visual selection (since transient is actually focused)
if (hasTransient(metaWindow) && metaWindow !== display.focus_window) {
space.setSelectionInactive();
}
else {
// then set the new selection active
space.setSelectionActive();
}

space.updateWindowPositionBar();

if (space.selection.get_parent() === clone)
return;
space.selection.reparent(clone);
Expand Down Expand Up @@ -3139,9 +3223,9 @@ function grabBegin(metaWindow, type) {
break;
case Meta.GrabOp.KEYBOARD_MOVING:
inGrab = new Extension.imports.grab.MoveGrab(metaWindow, type);

if (inGrab.initialSpace.isFloating(metaWindow))
if (!isTiled(metaWindow)) {
return;
}

// NOTE: Keyboard grab moves the cursor, but it happens after grab
// signals have run. Simply delay the dnd so it will get the correct
Expand All @@ -3153,6 +3237,10 @@ function grabBegin(metaWindow, type) {
break;
case Meta.GrabOp.MOVING:
case Meta.GrabOp.MOVING_UNCONSTRAINED: // introduced in Gnome 44
if (!isTiled(metaWindow)) {
return;
}

inGrab = new Extension.imports.grab.MoveGrab(metaWindow, type);

if (utils.getModiferState() & Clutter.ModifierType.CONTROL_MASK) {
Expand Down Expand Up @@ -3198,34 +3286,28 @@ function grabEnd(metaWindow, type) {
* Particularly noticable with multi-monitor setups.
*/
function setAllWorkspacesInactive() {
for (let i = 0; i < workspaceManager.get_n_workspaces(); i++) {
let ws = workspaceManager.get_workspace_by_index(i);
if (ws) {
spaces.get(ws).setSelectionInactive();
}
}
spaces.forEach(s => s.setSelectionInactive());
}

// `MetaWindow::focus` handling
function focus_handler(metaWindow, user_data) {
debug("focus:", metaWindow.title, utils.framestr(metaWindow.get_frame_rect()));

if (Scratch.isScratchWindow(metaWindow)) {
setAllWorkspacesInactive();
Scratch.makeScratch(metaWindow);
TopBar.fixTopBar();
return;
}

// If metaWindow is a transient window ensure the parent window instead
let transientFor = metaWindow.get_transient_for();
if (transientFor !== null) {
metaWindow = transientFor;
}

let space = spaces.spaceOfWindow(metaWindow);
space.monitor.clickOverlay.show();

// If metaWindow is a transient window ensure the parent window instead
let transient = metaWindow.get_transient_for();
if (transient) {
metaWindow = transient;
}

/**
Find the closest neighbours. Remove any dead windows in the process to
work around the fact that `focus` runs before `window-removed` (and there
Expand Down

0 comments on commit d7b53f3

Please sign in to comment.