2

I just started my adventure with Raspberry Pi and there's a silly productivity problem for which I can't find a solution online.

Basically Alt+Tab shortcut in Desktop switches between two most recently focused applications. I.e. when I keep holding Alt and then press Tab multiple times it swaps between just two windows. I often have more than 2 windows open and grabbing a mouse to change focus between them in the panel is a pain.

Does anyone know how to change this so it circles through all the open windows?

I'm on Raspberry Pi OS Bullseye (64 bit version, but Alt+Tab works the same on 32 bit, I doubt bitness matters here) with default window manager and everything related, on Raspberry Pi 4. XDG_CURRENT_DESKTOP is LXDE.

Thanks in advance.

Update 1

The accepted answer is a workaround. Switching to another Window Manager (Openbox) to change Alt+Tab behavior has its drawbacks, biggest of which seems to be performance degradation. I posted a question / feature request about configuring Alt+Tab behavior in Mutter's GitLab repo.

Update 2

Posted another issue on RPi-Distro/raspberrypi-ui-mods on GitHub. As pointed out by @Drdrm46's comment, this is most likely not a Mutter specific problem.

Piotr
  • 131
  • 5

4 Answers4

3

I posted this in the linked Update 2 github thread, but it's probably easier for people to find here. Below is a bash script that emulates Alt+Tab and can be bound to Alt+Tab with xbindkeys. No menu to see what window is selected but it works for me, even across multiple monitors (thank you, xdotool).

Note that many settings seem to have been migrated out of conf files and into gsettings. Typing gsettings list-recursively org.gnome. and hitting tab a couple of times will show you where everything has been hiding. Or use pretty dconf-editor GUI thing and click a lot.

Probably also of note if you use Alt+Tab: I had to remove keybindings for cycle-group and cycle-group-backward to restore Ctrl+Tab and Ctrl+Shift+Tab functionality within applications (e.g., browser, terminal). If that is still the case this will work (and is easy to undo, see script):

gsettings set org.gnome.desktop.wm.keybindings cycle-group-backward []
gsettings set org.gnome.desktop.wm.keybindings cycle-group []

With time all of this should settle back into the fairly universal behaviours we all know and love. For now making aliases for:

sed -i "s/window_manager=mutter/window_manager=openbox/" ~/.config/lxsession/LXDE-pi/desktop.conf
sed -i "s/window_manager=openbox/window_manager=mutter/" ~/.config/lxsession/LXDE-pi/desktop.conf

Might help you switch back and forth easily. On to the script:

#!/bin/bash

A bash Alt+Tab behaviour for Raspbery Pi Bullseye (Mutter)

for xprop: sudo apt install x11-utils

for xdotool: sudo apt install xdotool

You can bind this with xbindkeys

something like this (assumes file named alttab on $PATH):

```

sudo apt install xbindkeys

xbindkeys --defaults > ~/.xbindkeysrc #this will overwrite ~/.xbindkeysrc!

echo '"alttab"' >> ~/.xbindkeysrc

echo ' Alt + Tab' >> ~/.xbindkeysrc

xbindkeys --poll-rc #[re]load rc file

```

don't forget chmod +x alttab or similar to make alttab executable

Disable the default Alt+Tab behaviour with:

gsettings set org.gnome.desktop.wm.keybindings cycle-windows []

to undo that: replace 'set' w/'reset' and remove [] ('get' will show)

set use_xbindkey_hack to 0 to use it as intended (alt+tab demo):

run it (equivalent of pressing alt+tab) and hit the tab key n times

use_xbindkey_hack=1 #this is a temporary hack; you have been warned log_file='/dev/null' #'/tmp/tabs.log' # use tail -f /tmp/tabs.log to see what it's doing

count tab presses

if [[ $use_xbindkey_hack -eq 1 ]]; then ttfile='/tmp/tabtimes.txt' tnow=date +%s tabtimes=0 lasttime=0 if [ -f "$ttfile" ]; then read tabtimes lasttime < $ttfile fi tdiff=$(($tnow-$lasttime)) # if last keypress <= 1 second ago increment, otherwise set count to 1 if [[ $tdiff -le 1 ]]; then ((tabtimes+=1)) else tabtimes=1 fi lasttime=date +%s echo "$tabtimes $lasttime" > $ttfile echo "alttab $tabtimes tabs last hit $tdiff seconds ago" >> $log_file

# this was less annoying than tinkering with xbindkeys
alts=`timeout .4 thd --dump /dev/input/event*`
if [[ &quot;$alts&quot; == *&quot;KEY_LEFTALT&quot;* ]]; then
    echo &quot;Alt key up!&quot; &gt;&gt; $log_file
else
    # if alt hasn't been released stop at counting
    exit
fi
# alt released, reset count and timer
echo &quot;0 0&quot; &gt; $ttfile
num_presses=$(($tabtimes+2)) #skip &quot;panel&quot; window and active window (+2)

else i=2 num_presses=2 while [ $i -ge 0 ] do IFS= read -t 1 -n 1 input # is it a tab? if [[ $input = $'\t'* ]]; then ((num_presses+=1)) ((i+=1)) # timeout if no input elif [[ -z "$input" ]]; then i=0 fi ((i-=1)) done fi

echo "Effective tab presses: $num_presses" >> $log_file

get window stack list

stacklist=xprop -root | grep '_NET_CLIENT_LIST_STACKING(WINDOW)' | sed 's/.*#//'

reverse the order

stacklist=echo $stacklist | sed 's/, /\n/g' | tac | sed ':a;$!{N;ba};s/\n/, /g'

loop through stack until we get to our $num_presses index; raise window

j=0

echo $stacklist | sed -n 1'p' | tr ',' '\n' | while read win_id; do ((j+=1)) wname=xprop -id $win_id WM_NAME #you can get _NET_WM_ICON as well echo "$j: $win_id $wname" >> $log_file if (( $j == $num_presses )); then echo "raise $win_id" >> $log_file xdotool windowactivate $win_id fi done

Jaciss
  • 56
  • 5
  • Thanks Jaciss. I've been using your script, have modified it, added a popup and posted on Raspberry Pi forums. All best. – Drdrm46 Mar 11 '22 at 20:43
2

Modifying desktop.conf , as suggested above, does not work properly - for example it stops Ctrl Alt t from working properly to open a terminal. It's better to modify /usr/bin/startlxde-pi by increasing the threshold value of memory at which mutter is enabled in preference to openbox. I searched for the value 2048 in the file and changed it to 20480. Now my Raspberry Pi 4 starts using openbox. Another method is to enable vnc through the Raspberry Pi preferences menu - this forces use of openbox after reboot as vnc does not work properly with mutter. You can check which windows manager is in use by installing wmctrl (sudo apt install wmctrl) and typing wmctrl -m in a terminal window. After changing to openbox, Alt Tab works correctly as before - also ctrl alt t and all other keyboard shorcuts work properly and custom keyboard shortcuts can be added. Search for Mutter in Raspberry pi forums for more details.

Drdrm46
  • 66
  • 5
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center. – Community Jan 16 '22 at 11:41
  • I ended up enabling "VNC". I hope they change that Alt-Tab behavior in Mutter in the future, as it does feel more snappy than Openbox tbh. But for now it is what it is :). Thanks for help! – Piotr Jan 21 '22 at 15:25
  • 1
    Regarding Piotrs comment on the Mutter Gitlab submission , it seems that Alt tab works correctly in GNOME, because mutters functionality is augmented by the gnome-shell plug-in so the request may not be recognised as an issue for mutter per se. – Drdrm46 Jan 22 '22 at 18:25
  • 1
    It may be better to submit to github Rpi-distro raspberrypi-ui-mods. Getting Alt-Tab to work properly is very important to me as I have persuaded my household to use Raspberry Pi 4's as desktop machines in preference to windoze - and I'd be very reluctant to force reduced Alt-Tab functionality onto them now that I've educated them in how to use it to switch applications – Drdrm46 Jan 22 '22 at 18:37
  • @Drdrm46 thanks again. I made a new issue in the repo you pointed, and updated the question. Let's see what happens ;). – Piotr Jan 23 '22 at 09:09
  • And I supported you. I think the selection icons are important though – Drdrm46 Jan 23 '22 at 10:59
  • Jaciss. I have written a script, (of course !) to install your script and I like it and am using it. There is some conflict with other shortcuts I was using with xbindkeys e.g. if I had other shortcuts using Alt then xbindkeys got confused and no shortcuts seemed to work. But the work around is to use a different modifier. I've also posted about your script on Raspberry Pi forums as drmullins – Drdrm46 Feb 09 '22 at 15:24
1

It is a "feature" of the Mutter window manager Raspberry Pi OS has recently started using.

Maybe it can be configured to work differently but I was not able to figure out how. Instead I just changed the window manager to Openbox.

You can do this by editing ~/.config/lxsession/LXDE-pi/desktop.conf and changing window_manager=mutter to window_manager=openbox

  • Hmm that file did not contain window_manager setting on my Pi. But I found the update-alternatives --config x-window-manager command that should do this. What surprises me though is that it was already set to openbox (mutter is also an option there). There's also x-session-manager setting that by default (on my Pi at least) is set to startlxde-pi, but can be changed to openbox-session where Alt+Tab works as desired, but it changes too many other things (e.g. no panel whatsoever, only rmb menu to start apps). What do you think of all this? :) Thanks. – Piotr Dec 19 '21 at 11:15
  • Oh and adding window_manager=openbox to ~/.config/lxsession/LXDE-pi/desktop.conf did not seem to have any effect (I did log out and in after changing it) but I'm guessing it needs to be put under specific section which I'm missing? I only have [GTK] section in the file. – Piotr Dec 19 '21 at 11:16
  • 1
    The window_manager definition is under [Session] in my file. – muttereffer Dec 19 '21 at 18:34
  • 1
    There is an example file in /usr/share/doc/lxsession/examples/desktop.conf.example. I'm using the latest (Oct-2021) "Raspberry Pi OS with desktop" distribution btw. – muttereffer Dec 19 '21 at 18:44
1

It is still desirable to have not only Alt Tab 'Select and Toggle' capability as provided by Jaciss's excellent script, but also a popup splash showing a list of active windows for selection when using Mutter windows manager.

I wrote a popup daemon in python 3 to work together with a modified version of Jaciss's Alt Tab script - modified to allow time for selecting the required window from the popup. The script is a drop-in replacement for Jaciss's script and communicates with the popup daemon through temporary files. The script counts the number of times the Tab key is pressed with the Alt key held down and waits for the Alt key to be released. If the popup is not running it then also raises the selected window. However if the popup is running, it signals each Tab press and Alt Up to the popup daemon. On first Tab press the popup daemon, creates, displays and with subsequent Tab presses updates a splash list (application name and windows name with selected window in bold) of focusable windows, then raises the selected window as chosen from the splash after the Alt key is released.

The script is totally reliant on the continuing availability of X11 functionality so should continue to work for the moment but may not survive the eventual move to Wayland. It is to be hoped that we do not move to Wayland before xWayland supports all the commonly used features of X11 including those required by this script.

I attach the code for the revised script and the popup daemon below as well as the code for some support utilities. The following files are required:

Suggested file name Suggested directory Function
alttab.sh /home/pi/bin/ Replacement for Jaciss's script activated by xbindkeys in response to Alt Tab key press
popup.py /home/pi/bin/ Daemon providing popup splash , started via autostart desktop shortcut and script
startpopup.sh /home/pi/bin/ Script to start popup daemon called from desktop shortcut in autostart
startpopup.desktop /home/pi/.config/autostart/ Desktop shortcut to autostart daemon
.xbindkeysrc /home/pi/ xbindkeys configuration file

The files in /home/pi/bin need execute permission.

The following packages, which may not already be installed, are required and can be installed via apt install :

x11-utils xbindkeys xdotool python3-tk

Alt Tab needs to be disabled by issuing the following command (not as root)

gsettings set org.gnome.desktop.wm.keybindings cycle-windows []

It can be re-enabled, if needs be, by issuing the following command

gsettings reset org.gnome.desktop.wm.keybindings cycle-windows

The popup daemon uses the tkinter graphics library as requirements are undemanding and tkinter is part of the python core language. The daemon displays the popup, with a short delay, the first time the Tab is pressed with Alt key held down with the next item in stacking order preselected. The popup disappears after the user has tabbed through to the required window and released the Alt key. The Alt key needs to be released after the Tab key. If the popup remains (because Alt key was released first), just press and release the Alt key. For toggling between the last two focussed windows a quick Alt Tab and release can be done without waiting for the popup daemon to appear.

Notes :

  • To view the log file for alttab.sh , issue the following command in a terminal window: tail -f /tmp/tabs.log and enable logging in the script by deleting the value 1 in the last but one line of the script
  • To view the log file for popup.py, disable the popup (if running) by issuing the following command in a terminal window bash /tmp/killpopupup.sh and run popup.py from an IDE such as geany
  • In running thd in the script, thdevent is set to the value /dev/input/event0 because keyboard events came as event0 in my case. If Alt Up detection is not working try with the value of thdevent changed to /dev/input/event*
  • If running the script without the popup, note that the existence of any running program with popup.py in its name will prevent the the script from raising the newly required window. In such case kill any running instances of popup.py

If any problems please let me know and I'll try to fix them !

alttab.sh

#!/bin/bash
# 07/03/22 by drdrm46 with many many thanks to Jaciss !
# To be run from xbindkeys with /home/pi/.xbindkeysrc containing :
#       #Alt Tab select and toggle with popup support
#       bash alttab.sh"
#       Alt+Tab
# This script runs every time Tab key is pressed with Alt key held down,
# checks for Alt key up and terminates after Alt key is released or
# timeout. Multiple instances may run simultaneously for a short while.

function execute {
initialise count_tabs detect_alt_up if [ $altup ] ; then reset_tab_count is_popup_running if [ ! $running ] ; then activate_window # if popup.py daemon not enabled fi LOG="EXITING Alt Tab found in Run No : $runno" ; log elif [ $timeout ] ; then reset_tab_count LOG="EXITING Timeout in Run No : $runno" ; log elif [ $abort ] ; then LOG="ABORTING earlier Run No $runno" ; log fi }

function initialise { log_file="/tmp/tabs.log" # General logging run_file="/tmp/runno.txt" # Distinguish current from previous runs ttfile='/tmp/tabtimes.txt' # Count tabs + signal to popup.py daemon key_file="/tmp/keys.log" # For output of 'thd' daemon mod_file="/tmp/modulus.txt" # Save count of focusable windows

May need to change event id depending on keyboard config eg 0 to * :

thdevent=&quot;/dev/input/event0&quot;  # thd event filter for keyboard
read runno &lt; $run_file
((runno+=1))
echo $((runno%64)) &gt; $run_file
LOG=&quot; &quot; ; log
LOG=&quot;NEW RUN $runno &quot; ; log

}

function count_tabs { tabcount=0 lasttime=0 if [ -f "$ttfile" ] ; then read tabcount lasttime < $ttfile fi ((tabcount+=1)) tnow=date +%s tdiff=$(($tnow-$lasttime)) LOG="tabs : $tabcount tdiff : $tdiff "; log lasttime=$tnow echo "$tabcount $lasttime" > $ttfile }

function detect_alt_up { killthd="/tmp/thd$runno" LOG="Starting thd in Run No : $runno" ; log thd --dump $thdevent >> $key_file & # Save key events echo "kill -9 $!" > $killthd i=0 abort= timeout= altup= while [ ! $abort ] && [ ! $timeout ] && [ ! $altup ] ; do read latestno < $run_file if [ $runno == $latestno ] ; then if [ $i -gt 100 ] ; then timeout=1 else lastline=$( tail -n 1 $key_file ) if [[ $lastline == "LEFTALT" ]] && [[ $lastline == "0" ]] ; then altup=1 LOG="Found Alt Up in Loop $i" ; log echo "0" >> $key_file fi sleep 0.1 fi else abort=1 fi ((i+=1)) done LOG="Killing thd in Run No : $runno" ; log bash $killthd rm $killthd }

function reset_tab_count {
echo "0 $lasttime" > $ttfile num_presses=$(($tabcount+2)) #skip "panel" window and active window (+2) LOG="Effective tab presses (tab count + 2) : $num_presses" ; log }

function is_popup_running { running=

Use distinctive part of popup filename with [] around first letter

ps -aux | grep &quot;[p]opup.py&quot;
ok=$?
if [ $ok == 0 ] ; then
    running=1
fi

}

function activate_window { # get window stack list stacklist=xprop -root | grep '_NET_CLIENT_LIST_STACKING(WINDOW)' | sed 's/.*#//' # reverse the order stacklist=echo $stacklist | sed 's/, /\n/g' | tac | sed ':a;$!{N;ba};s/\n/, /g' # loop through stack until we get to our $indexplus2 index; raise window j=0 echo $stacklist | sed -n 1'p' | tr ',' '\n' | while read win_id; do ((j+=1)) echo $j > $mod_file done read total < $mod_file focus=$((total-2)) index=$((tabcount%focus)) indexplus2=$((index+2)) LOG="total windows $total focusable $focus tabcount $tabcount index $index index+2 $indexplus2"; log j=0 echo $stacklist | sed -n 1'p' | tr ',' '\n' | while read win_id; do ((j+=1)) wname=xprop -id $win_id WM_NAME #you can get _NET_WM_ICON as well LOG="$j: $win_id $wname" ; log if (( $j == $indexplus2 )); then LOG="raise $win_id" ; log xdotool windowactivate $win_id fi done }

function log { if [ ! $nolog ] ; then timenow=date +%T echo "$runno $timenow $LOG" >> $log_file fi }

nolog=1 # Set to disable all logging, blank for logging execute

popup.py

#!/usr/bin/env python3
# drdrm46 07/03/22 
# Start up as daemon with "nohup python3 /home/pi/bin/popup.py &"
# To be used with associated "alttab.sh" bash script
# Filename must match name in "is_popup_running" in bash script
import sys,shlex,os
import tkinter as tk        # Requires python3-tk package installed
import subprocess as sp
Goldtabcount=0
Gwinnamelist=[]
Gwinclasslist=[]
Gwinidlist=[]
Glablist=[]
Goldwinid=None
Gnewwinid=None
Gstarted=False

def main(): ttfile='/tmp/tabtimes.txt' # To communicate with script timeout=100 leftoffset=0.8 fonts=(( "Piboto",11,"normal"),("Piboto",11,"bold" )) aspects=(500,1000) root=tk.Tk() root.wm_attributes('-type', 'splash') width=root.winfo_screenwidth() height=root.winfo_screenheight() geom='+'+str(int(leftoffset*width/2))+'+'+ str(int(height/2)) root.geometry(geom) popupid=tk.Frame(root) popupid.grid()

Hack to ensure that popup is properly withdrawn on startup

hack(root,popupid)
root.after(timeout,checkforchange,root,popupid,ttfile,timeout,fonts,aspects)
root.mainloop()

def checkforchange(root,popupid,ttfile,timeout,fonts,aspects): root.after(timeout,checkforchange,root,popupid,ttfile,timeout,fonts,aspects) global Goldtabcount global Gwinnamelist global Gwinclasslist global Gwinidlist global Glablist global Goldwinid global Gnewwinid tabcount=get_tab_count(ttfile) if tabcount is not None: if tabcount==0 and Goldtabcount != 0 : # Found Alt Up rows=len(Gwinnamelist) Goldwinid=Gwinidlist[0] index=Goldtabcount%rows Gnewwinid=Gwinidlist[index] focus_window(Goldwinid) # in case popup breaks stacking order focus_window(Gnewwinid) print( "Times Tab pressed :",Goldtabcount,
"Focusable windows :",rows,
"Index into ordered window list :",index)
print( "Switching from ", Gwinnamelist[0]) print( " to ", Gwinnamelist[index]) clear_splash(Gwinnamelist,Glablist) Gwinidlist=[] Gwinnamelist=[] Goldwinid=None Gnewwinid=None Glablist=[] root.withdraw() elif tabcount==1 and Goldtabcount==0: # Found first Alt Tab Gwinidlist,Gwinnamelist,Gwinclasslist=get_window_info() Glablist=fill_splash(popupid,fonts,aspects,tabcount,Gwinnamelist,
Gwinclasslist) root.deiconify() elif tabcount>1 and Goldtabcount!=tabcount: # Found more Alt Tabs update_splash(tabcount,fonts,Gwinnamelist,Glablist) Goldtabcount=tabcount

def get_tab_count(ttfile): tabcount=None try: f=open(ttfile) tabinfo=f.read() tabcount=int(tabinfo.split()[0]) f.close() except: print(ttfile+' not found') return tabcount

def hack(root,popupid):

Hack to ensure that popup is properly withdrawn on startup

global Gstarted
if not Gstarted:
    messid=tk.Label(popupid)
    messid.config(text=&quot;Popup running&quot;)
    messid.grid()
    messid.destroy()
    root.withdraw()
    Gstarted=True

def clear_splash(winnamelist,lablist): if winnamelist is not None: rows=len(winnamelist) for row in range(rows): lablist[row].destroy() for row in range(rows): lablist[row+rows].destroy() return

def fill_splash(popupid,fonts,aspects,tabcount,winnamelist,winclasslist): lablist=[] rows=len(winnamelist) for row in range(rows): lab=tk.Message(popupid,aspect=aspects[1]) lablist.append(lab) lab.config(text=winnamelist[row]) if row==tabcount: lab.config(font=fonts[1]) else: lab.config(font=fonts[0]) lab.grid(row=row,column=2,sticky=tk.W) for row in range(rows): lab=tk.Message(popupid,aspect=aspects[0]) lablist.append(lab) lab.config(text=winclasslist[row]) if row==tabcount: lab.config(font=fonts[1]) else: lab.config(font=fonts[0]) lab.grid(row=row,column=1,sticky=tk.W) return lablist

def update_splash(tabcount,fonts,winnamelist,lablist): rows=len(winnamelist) for row in range(rows): lab=lablist[row] if row==tabcount%rows: lab.config(font=fonts[1]) else: lab.config(font=fonts[0]) for row in range(rows): lab=lablist[row+rows] if row==tabcount%rows: lab.config(font=fonts[1]) else: lab.config(font=fonts[0])

def get_window_info(): command="xprop -root" cmd=shlex.split(command) handle = sp.Popen ( cmd , stdout = sp.PIPE) stdout, stderr = handle.communicate() winfo=str(stdout).split('\n') i=0 for info in winfo: if '_NET_CLIENT_LIST_STACKING(WINDOW):' in info: winids=info.split(' ') i=i+1 winidlist=[] i=0 for item in winids: if i>3 : winidlist.append(item) i=i+1 winnamelist=[] for id in winidlist: handle = sp.Popen( ['xprop', '-id',id,'WM_NAME'],
stdout = sp.PIPE ) stdout, stderr = handle.communicate() print(str(stdout)) wnameinfo=str(stdout).split(',') winname1=str(wnameinfo).split()[2:] winname2=' '.join(winname1) winname=winname2.replace("\\n\'']"," ") winname=winname.replace('"',' ') winnamelist.append(winname)

winclasslist=[]
for id in winidlist:
    handle = sp.Popen( ['xprop', '-id',id,'WM_CLASS'], \
      stdout = sp.PIPE )
    stdout, stderr = handle.communicate()
    wclassinfo=str(stdout).split(',')
    winclass1=str(wclassinfo).split()
    winclass2=winclass1[4]
    winclass=winclass2.replace(&quot;\\\\n\\'']&quot;,&quot; &quot;)
    winclass=winclass.replace('&quot;',' ')
    winclass=winclass.replace('&quot;',' ')
    winclasslist.append(winclass)

idlist=[]
namelist=[]
classlist=[]
ii=len(winidlist)

print(&quot; &quot;)
print(&quot;ALL WINDOWS IN STACKING ORDER&quot;)
for i in range(ii):
    print (i, winidlist[i],winclasslist[i],winnamelist[i])

for i in range(ii):
    j=ii-i-1
    if not ((&quot;panel&quot; in winnamelist[j]) or \
      (&quot;pcmanfm&quot; in winnamelist[j])):
        idlist.append(winidlist[j])
        namelist.append(winnamelist[j])
        classlist.append(winclasslist[j])
ii=len(idlist)
print(&quot;FOCUSABLE WINDOWS IN REVERSE STACKING ORDER &quot;)
for i in range(ii):
    print (i, idlist[i],classlist[i],namelist[i])

return idlist,namelist,classlist

def focus_window(id): command="xdotool windowactivate "+id cmd=shlex.split(command) handle = sp.Popen ( cmd , stdout = sp.PIPE , stderr = sp.PIPE) sout,serr = handle.communicate() if not (sout==b'' and serr==b''): print ("ERROR in focus_window","stdout=", str(sout),
"stderr=",str(serr)) return

if name == "main": main()

startpopup.sh

#!/bin/bash
sleep 10
nohup python3 /home/pi/bin/popup.py & > "/tmp/nohup.out"
pid=$!
echo "kill $pid" >/tmp/killpopup.sh

startpopup.desktop

[Desktop Entry]
Name=Start Popup
Type=Application
Exec=bash /home/pi/bin/startpopup.sh``

.xbindkeysrc

# Alt Tab select and toggle with popup
"bash alttab.sh"
Alt+Tab

Drdrm46
  • 66
  • 5