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.

2
  • Since Raspberry Pi OS - Bullseye which is significantly different from Raspberry Pi OS - Buster it is essential to specify OS and Pi model.
    – Milliways
    Commented Jan 15, 2022 at 23:24
  • @Milliways fixed.
    – Piotr
    Commented Jan 16, 2022 at 8:28

4 Answers 4

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 [[ "$alts" == *"KEY_LEFTALT"* ]]; then
        echo "Alt key up!" >> $log_file
    else
        # if alt hasn't been released stop at counting
        exit
    fi
    # alt released, reset count and timer
    echo "0 0" > $ttfile
    num_presses=$(($tabtimes+2)) #skip "panel" 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
1
  • Thanks Jaciss. I've been using your script, have modified it, added a popup and posted on Raspberry Pi forums. All best.
    – Drdrm46
    Commented Mar 11, 2022 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.

7
  • 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 Bot
    Commented Jan 16, 2022 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
    Commented Jan 21, 2022 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
    Commented Jan 22, 2022 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
    Commented Jan 22, 2022 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
    Commented Jan 23, 2022 at 9:09
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

4
  • 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
    Commented Dec 19, 2021 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
    Commented Dec 19, 2021 at 11:16
  • 1
    The window_manager definition is under [Session] in my file. Commented Dec 19, 2021 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. Commented Dec 19, 2021 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="/dev/input/event0"  # thd event filter for keyboard
    read runno < $run_file
    ((runno+=1))
    echo $((runno%64)) > $run_file
    LOG=" " ; log
    LOG="NEW RUN $runno " ; 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 "[p]opup.py"
    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="Popup running")
        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("\\\\n\\'']"," ")
        winclass=winclass.replace('"',' ')
        winclass=winclass.replace('"',' ')
        winclasslist.append(winclass)

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

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

    for i in range(ii):
        j=ii-i-1
        if not (("panel" in winnamelist[j]) or \
          ("pcmanfm" in winnamelist[j])):
            idlist.append(winidlist[j])
            namelist.append(winnamelist[j])
            classlist.append(winclasslist[j])
    ii=len(idlist)
    print("FOCUSABLE WINDOWS IN REVERSE STACKING ORDER ")
    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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.