The fun part of "home made products" is always that you can make it pretty much exactly as you like. The possible downside is that you easily get carried away a bit by a project if it is nice to work on...
That might be the case with the script below :). While I would have preferred to add a detailed explanation on how it works "under the hood", this is a "ready to use" solution. Although I added some commentary lines, it is hard to give a simple inside explanation on the code. It seems however to be close to what you are looking for.
What it is
The script is a purely text-based solution to list all opened, "normal" application windows (and raise a chosen one), but it has a number of options:
list the windows, sorted by window name:
Run with the command:
python3 <script> -win
type the first character(s) of the sought window and press return to bring the window to front.
list the windows, sorted by application:
Run with the command:
python3 <script> -app
list the windows, sorted by workspace:
Run with the command:
python3 <script> -ws
As you can see, the displayed columns are: Window name, Application, Workspace. The pre- set sorted column is always the first one.
Fuzzy?
To select an item from the list, simply type the first character. If there are more items that meet the typed character(s) the arrow keys will only browse through the items that meet the typed characters:
Furthermore:
workspace indication
The current workspace is marked with a *
: e.g. if you see 2*
, it means the window is on workspace 2
and workspace 2
is the current workspace. This works no matter how many workspaces you have.
The window size
of the slection window is set automatically to the window's (longest) name and the number of windows to be displayed, e.g.:
or:
How to use
The setup is pretty straightforward:
The script (definitely) needs wmctrl
:
sudo apt-get install wmctrl
Then copy the script below into an empty file, save it as list_windows.py
Then Test- run it with the commands:
python3 /path/to/list_windows.py -app
python3 /path/to/list_windows.py -win
python3 /path/to/list_windows.py -ws
If all works fine, add one or more of the preferred commands to one or more shortcut keys: choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script
(still "unpolished" code)
#!/usr/bin/env python3
import subprocess
import socket
import sys
arg = sys.argv[1]
# list (column) header titles and their (data) position in the produced window data list
cols = [["Workspace", -1], ["Application name", -2] , ["Window name", -3]]
# rearrange columns, depending on the chosen option
if arg == "-app":
cols = [cols[1], cols[2], cols[0]]
elif arg == "-ws":
cols = [cols[0], cols[2], cols[1]]
elif arg == "-win":
cols = [cols[2], cols[1], cols[0]]
# extract headers, list positions, to be used in the zenity list
col1 = cols[0][0]; i1 = cols[0][1]
col2 = cols[1][0]; i2 = cols[1][1]
col3 = cols[2][0]; i3 = cols[2][1]
# just a helper function
get = lambda cmd: subprocess.check_output([
"/bin/bash", "-c", cmd
]).decode("utf-8")
# analyse viewport data, to be able to calculate relative/absolute position of windows
# and current viewport
def get_spandata():
xr = get("xrandr").split(); pos = xr.index("current")
res = [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]
spandata = get("wmctrl -d").split()
span = [int(n) for n in spandata[3].split("x")]
cols = int(span[0]/res[0]); rows = int(span[1]/res[1])
curr_vector = [int(n) for n in spandata[5].split(",")]
curr_viewport = int((curr_vector[1]/res[1])*cols + (curr_vector[0]/res[0])+1)
return {"resolution": res, "n_columns": cols, "vector": curr_vector, "current_viewport": curr_viewport}
posdata = get_spandata()
vector = posdata["vector"]; cols = posdata["n_columns"]
res = posdata["resolution"]; currvp = posdata["current_viewport"]
# function to distinguish "normal" windows from other types (like the desktop etc)
def check_window(w_id):
w_type = get("xprop -id "+w_id)
if " _NET_WM_WINDOW_TYPE_NORMAL" in w_type:
return True
else:
return False
# split windowdata by machine name
mach_name = socket.gethostname()
wlist = [[l.strip() for l in w.split(mach_name)] for w in get("wmctrl -lpG").splitlines()]
# split first section of window data
for i, w in enumerate(wlist):
wlist[i][0] = wlist[i][0].split()
# filter only "real" windows
real_wlist = [w for w in wlist if check_window(w[0][0]) == True]
# adding the viewport to the window's data
for w in real_wlist:
w.append(get("ps -p "+w[0][2]+" -o comm=").strip())
loc_rel = [int(n) for n in w[0][3:5]]
loc_abs = [loc_rel[0]+vector[0], loc_rel[1]+vector[1]]
abs_viewport = int((loc_abs[1]/res[1])*cols + (loc_abs[0]/res[0])+1)
abs_viewport = str(abs_viewport)+"*" if abs_viewport == currvp else str(abs_viewport)
w.append(abs_viewport)
# set sorting rules
if arg == "-app":
real_wlist.sort(key=lambda x: x[-2])
elif arg == "-ws":
real_wlist.sort(key=lambda x: x[-1])
elif arg == "-win":
real_wlist.sort(key=lambda x: x[-3])
# calculate width and height of the zenity window:
# height = 140px + 23px per line
h = str(140+(len(real_wlist)*23))
# width = 250px + 8px per character (of the longest window title)
w = str(250+(max([len(w[-3]) for w in real_wlist])*8))
# define the zenity window's content
cmd = "zenity --list --hide-column=4 --print-column=4 --title='Window list' "\
"--width="+w+" --height="+h+" --column='"+col1+"' --column='"+col2+"' --column='"+col3+\
"' --column='w_id' "+(" ").join([(" ").join([
'"'+w[i1]+'"','"'+w[i2]+'"','"'+w[i3]+'"','"'+w[0][0]+'"'
]) for w in real_wlist])
# finally, call the window list
try:
w_id = subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8").split("|")[0]
subprocess.Popen(["wmctrl", "-ia", w_id])
except subprocess.CalledProcessError:
pass
Best Answer
If I understand your question correctly, there are several routes that don't require the Alt+F2 route.
Alt+Tab
This basic method has a few possibilities itself which you can explore via
System Settings
>Window Management
>Task Switcher
. My preference is the very simple one shown below. On pressing Alt+Tab, I have a plain text display of open windows.I keep the Alt key depressed and cycle through the choices with the Tab key. You can try various other options available on the
Task Switcher
page.As shown in the image below, I've chosen "Text Only" from the dropdown and I have "Show selected window" unchecked. You may like something else.
Flip windows
Open
System Settings
>Desktop Behavior
>Desktop Effects
and typeflip
in the search bar at the top of the page. ActivateFlip Switch
.If you click on the circled icon, you'll see a preview of what this can do. (It may take a while to load.)
If you decide you want to try it, open
System Settings
>Shortcuts
>Global Shortcuts
>System Settings
and enterflip
in the search bar (as before). Here, decide on a keyboard shortcut of choice to activate theFlip Switch
or leave the existing choice in effect if there is one there. I've gone with Ctrl+MetaF10. Use Alt+Tab to cycle through the choices and pressEnter
when you've found the one you want. (Meta
is theSuper
or Windows key.)Present Windows
I won't go into detail here because the procedure to find it is the same as for
Flip Switch
. In this case, I went with Ctrl+F10 because that was already set up. Here, as you hover over individual windows, they're highlighted and clicking on the hovered one brings it into focus.Using
Screen Edges
Another thing for you to explore is
System Settings
>Desktop Behavior
>Screen Edges
. Again, I'll not go into detail but just leave you with an image which I took after right-clicking on the top-right corner white square:Edit:
To use many of the desktop effects, you must have compositing enabled and compositing is enabled by default if your system provides it.
To check, run
qdbus org.kde.KWin /KWin supportInformation | grep -i composit
My system shows:
By the way, you can toggle compositing on or off using Alt+Shift+F12.