Swallow - bakkeby/dusk GitHub Wiki

The Swallow functionality allows terminal windows marked with the Terminal flag to "swallow" X windows being started from the command line.

The idea of window swallowing is known from Plan 9's windowing system rio.

As an example running xclock from a terminal will normally open an X window showing a clock leaving the terminal in a "useless" state where it is just waiting on the command to finish. The Swallow functionality in this scenario allows the xclock window to take the place of the terminal.

swallow.gif

For programs where window swallowing is undesirable the feature can be disabled on a per client basis by setting the NoSwallow flag via client rules.

A typical example of this being the xev (Event Tester) program where you still need to see what the application outputs to the terminal.

The size hints of the terminal being replaced does not affect the size hints of the new window and vice versa. This is achieved by keeping the two as entirely separate clients and one just takes the other's place in the client list.

When a floating terminal window is replaced by another window then by default the window will inherit the size and position of the terminal window.

Note that when this happens the size hints of the new window may result in a size that is different than what the terminal window was, and additionally the new window may be sending ConfigureRequest events to specify another size and/or position.

It is possible to ignore configure events fully or partially using flags such as:

If the SwallowFloating functionality is disabled then windows that are floating will not replace the terminal unless they are also ruled.

When the window is closed and the terminal window returns then the terminal window will by default (again) inherit the size and position of the previous window.

If desirable then the size of the terminal window and the size of the new window can be completely independent of each other by ensuring that either of the two have the SwallowRetainSize flag set via client rules. This will allow both windows to retain their original size when swallowed / unswallowed.

In general the window swallowing functionality should be intuitive with the floating, tiled and fullscreen states seamlessly transitioning between clients on swallow and unswallow giving the illusion that it is the same window.

A swallowed window can be restored without killing the new window by triggering the unswallow function.

Technical requirements for window swallowing to work

The fundamental requirement for window swallowing to work is that there is a clear relation between the two windows that are to share the same space.

Typically this is done using process IDs (PIDs) and if a new window (xclock) is found to be a decendant of the terminal process (i.e. the terminal process is a parent process of the xclock process) then we have a clear link. This requires the window manager to walk the process tree, which inherently is an OS-specific task.

Another problem with this is that there is no clear link or registry that ties window IDs with process IDs. Thankfully most programs expose the process ID by setting the _NET_WM_PID property on the window. Some programs do not, however, which means that the corresponding windows can't swallow the terminal window.

Only terminals created by local processes can swallow windows, and only windows created by local processes can be swallowed automatically.

As an example it is not possible to simply mark a file manager like Nautilus as being a terminal and expecting it be swallowed by windows when opening documents or other files using it. This is because in most cases file managers like this act as daemons which means that new windows will be opened as orphans and will not be descendants of the file manager. In other words the file manager will not be the parent process of the new window, hence the swallow mechanism will not work automatically.

Workaround for file managers

A file manager will typically open files in orphaned processes which means that there will be no link between the file manager process and the new window.

For window swallowing to work in this situation we need a way to create a relation between the file manager and the new window.

One way to do this is to set an environment variable for the file manager when it starts - this because a child process will normally inherit the environment variables of its parent process.

So we have the example command that runs the nemo file manager with the environment variable of SWALLOWKEY set to N.

$ SWALLOWKEY=N nemo

To mark the file manager as a window that can be swallowed we need a client rule setting the Terminal flag as well as the matching swallow key of N.

   { .class = "Nemo", .flags = Terminal, .swallowkey = 'N'},

Now when the file manager opens a file, e.g. a photo in an image viewer, then that program window should replace the file manager. When the image viewer is closed then the file manager is revealed again.

Technically this works by identifying the PID of the window by looking at the _NET_WM_PID property if present, then trying to read the SWALLOWKEY environment variable from /proc/<pid>/environ provided that we have permission to do so. If found then the value of the environment variable (N in this case) is stored in the swallowedby field of the client which is used when identifying the terminal for the window.

This has been tested successfully with PCManFM and Nemo, but has found to not work with Thunar because spawned processes appear to not inherit the environment variables of the parent process.

Another approach is to create client rules that explicitly set the swallowedby value for clients. The downside of this is that you need to set up rules for all programs that you may want to use that should swallow the file manager.

Functions

Here is a list of functions relating to window swallowing.

Function Description
swallow Force all marked clients to be swallowed by the selected client
swallowmouse Allows for one window to swallow another using the mouse
unswallow Force the selected client to unswallow the most recently swallowed client

Functionality

Here is a list of functionality related to window swallowing.

Functionality Description
Swallow Enables window swallowing

Flags

Here is a list of flags that are related to window swallowing.

Flag Description
NoSwallow Indicates that the client should never swallow a terminal window
SwallowRetainSize Allow swallowed windows to retain their own size
SwallowNoInheritFullScreen Prevents the client from inheriting the fullscreen property when swallowed / unswallowed
Terminal Indicates that the client is a terminal, used by swallow

Additional notes

1) When it comes to window swallowing the terminology used is not always obvious or intuitive.

There are two views:

a) the terminal window swallows the xclock window b) the xclock window swallows the terminal window

Which of the two is more correct is up for debate. To avoid confusion this wiki tries to use simpler terminology such as one window replaces another, but otherwise it should adhere to view b).

2) You may also want to look at devour which is a WM agnostic tool for window swallowing.


Back to Functionality.

⚠️ **GitHub.com Fallback** ⚠️