Linux close another app after period of user inactivity - linux

I want to close iceweasel when user inactive.
Earlier i am using "Reset kiosk" extension,but it is not compatible with "R-Kiosk" extension.
It is possibly to get inactive event via Bash?

You can try trace running screensaver and run killall -9 iceweasel or give some time for user operations. Below realization of last variant:
#!/bin/sh
TIMELIMIT=10 #10 seconds for example
MYPROGRAMM=chromium-browser #I use chromium-browser for example
MYPID=-1
$MYPROGRAMM & MYPID=`echo $!`
sleep $TIMELIMIT
kill -9 $MYPID
zenity --info --timeout=5 --text="Session expired" #show message for user
Note, zenity can be replace with dialog, gdialog or kdialog in depend from your distributive.
Furthermore you can check screensaver running. It's just concept. I haven't KDE on my descktop, so you can make experiments.
#!/bin/sh
MYPROGRAMM=chromium-browser #I use chromium-browser for example
if [ "$(qdbus org.freedesktop.ScreenSaver /ScreenSaver org.freedesktop.ScreenSaver.GetActive)" $= 'false' ]; then
killall -9 $MYPROGRAMM
exit 0;
fi
You can try replace
qdbus org.freedesktop.ScreenSaver /ScreenSaver org.freedesktop.ScreenSaver.GetActive
upon
qdbus org.kde.screensaver /ScreenSaver org.freedesktop.ScreenSaver.GetActive
Note, it can work from (running) KDE(1).
More difficult but more reliable it parse result of ps -C kscreenlocker command.
(1)It work for me with Gnome through qdbus org.gnome.ScreenSaver /ScreenSaver org.gnome.ScreenSaver.GetActive

Related

How to check in If-Statement if a screen is already running

I want to write a bash script where I check If my Screen (I gave this screen the name a3_altis) is already running or not, just like this:
if (screen a3_altis is running)
then
./stop.sh
sleep 5
./start.sh
else
./start.sh
fi
I'm new in Bash, so I don't really know how to check If a screen is running.
screen may provide a more robust mechanism, but it should suffice to just use grep:
if screen -ls | grep -q a3_altis; then
./stop.sh
sleep 5
fi
./start.sh

What is the cleanest way to exit/kill/logout linux session?

I am using tiling window managers and from time to time I want to go back to a normal desktop environment or switch to another tiling window manager.
Usually I use a rofi script with loginctl terminate-user $USER.
Before this I used pkill -9 -u $USER.
I also found other options such as loginctl kill-user $USER and pkill dwm or pkill i3.
With so many options, I started to wonder which is the best and cleanest way to exit a session?
To kill a window manager, you only need to kill the X server, leaving Linux and your login shell running.
For a general command, you can use:
pkill -x X
In the specific case of i3, from i3's documentation:
To exit i3 properly, you can use the exit command, however you don’t need to (simply killing your X session is fine as well).
Example:
bindsym $mod+Shift+e exit

How to detect when a bash script is triggered from keybinding

Background
I have a Bash script that requires user input. It can be run by calling it in a terminal or by pressing a keyboard shortcut registered in the i3 (or Sway) config file as follows:
bindsym --release $mod+Shift+t exec /usr/local/bin/myscript
The Problem
I know I can use read -p to prompt in a terminal, but that obviously won't work when the script is triggered through the keybinding. In that case I can use something like Yad to create a GUI, but I'm unable to detect when it's not "in a terminal". Essentially I want to be able to do something like this:
if [ $isInTerminal ]; then
read -rp "Enter your username: " username
else
username=$(yad --entry --text "Enter your username:")
fi
How can I (automatically) check if my script was called from the keybinding, or is running in a terminal? Ideally this should be without user-specified command-line arguments. Others may use the script and as such, I'd like to avoid introducing any possibility of user error via "forgotten flags".
Attempted "Solution"
This question suggests checking if stdout is going to a terminal, so I created this test script:
#!/usr/bin/env bash
rm -f /tmp/detect.log
logpass() {
echo "$1 IS opened on a terminal" >> /tmp/detect.log
}
logfail() {
echo "$1 IS NOT opened on a terminal" >> /tmp/detect.log
}
if [ -t 0 ]; then logpass stdin; else logfail stdin; fi
if [ -t 1 ]; then logpass stdout; else logfail stdout; fi
if [ -t 2 ]; then logpass stderr; else logfail stderr; fi
However, this doesn't solve my problem. Regardless of whether I run ./detect.sh in a terminal or trigger it via keybind, output is always the same:
$ cat /tmp/detect.log
stdin IS opened on a terminal
stdout IS opened on a terminal
stderr IS opened on a terminal
It seems like the easiest way to solve your actual problem would be to change the i3 bind to
bindsym --release $mod+Shift+t exec /usr/local/bin/myscript fromI3
and do
if [[ -n "$1" ]]; then
echo "this was from a keybind"
else
echo "this wasn't from a keybind"
fi
in your script.
False Positive
As most results on Google would suggest, you could use tty which would normally return "not a tty" when it's not running in a terminal. However, this seems to differ with scripts called via bindsym exec in i3/Sway:
/dev/tty1 # From a keybind
/dev/pts/6 # In a terminal
/dev/tty2 # In a console
While tty | grep pts would go part way to answering the question, it is unable to distinguish between running in a console vs from a keybinding which you won't want if you're trying to show a GUI.
"Sort of" Solution
Triggering via keybinding seems to always have systemd as the parent process. With that in mind, something like this could work:
{
[ "$PPID" = "1" ] && echo "keybind" || echo "terminal"
} > /tmp/detect.log
It is likely a safe assumption that the systemd process will always have 1 as its PID, but there's no guarantee that every system using i3 will also be using systemd so this is probably best avoided.
Better Solution
A more robust way would be using ps. According to PROCESS STATE CODES in the man page:
For BSD formats and when the stat keyword is used, additional characters may be displayed:
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+ is in the foreground process group
The key here is + on the last line. To check that in a terminal you can call ps -Sp <PID> which will have a STAT value of Ss when running "interactively", or S+ if it's triggered via keybinding.
Since you only need the STATE column, you can further clean that up with -o stat= which will also remove the headers, then pipe through grep to give you the following:
is_interactive() {
ps -o stat= -p $$ | grep -q '+'
}
if is_interactive; then
read -rp "Enter your username: " username
else
username=$(yad --entry --text "Enter your username:")
fi
This will work not only in a terminal emulator and via an i3/Sway keybinding, but even in a raw console window, making it a much more reliable option than tty above.

How to make xdotool work with matchbow-window-manager?

I have trouble using xdotool to simulate simple keypresses in my browser.
Now my browsers starts up on boot by adding the following code in '/home/pi/.xintirc'
#!/bin/sh
xset -dpms
xset s off
xset s noblank
// not sure if this is needed.
killall -TERM matchbox-window-manager 2>/dev/null;
killall -9 matchbox-window-manager 2>/dev/null;
exec matchbox-window-manager -use_titlebar no &
iceweasel [someURL]
python /etc/xdo_test.py
My /etc/xdo_test.py looks as follows:
import time
import subprocess
time.sleep(20)
subprocess.call(["xdotool", "key", "c"]);
I don't have any output of this file while using it on startup but if I excecute this in another console, I get the following output:
Error: Can't open display: (null)
Failed creating new xdo instance
Does anyone have an idea why I get this error and how to solve it?
You use in the python script the subprocess.call command. This call don't set the currently set environment variables in the subprocesse. Hence the missing display. Simply call the xdotool command in the .xinitrc file directly.
#!/bin/sh
xset -dpms
xset s off
xset s noblank
// not sure if this is needed.
killall -TERM matchbox-window-manager 2>/dev/null;
killall -9 matchbox-window-manager 2>/dev/null;
exec matchbox-window-manager -use_titlebar no &
iceweasel [someURL] & #<--- add ampersand
sleep 20
# you have to determine the window to which you want to send the keystroke
WIN=`xdotool search --sync --onlyvisible --class iceweasel | head -1`
# then activate it
xdotool windowactivate $WIN
# and send the keystroke
xdotool key --window $WIN c
If you have problems with the ampersand in the iceweasel call try to put quotes around the URL.
I got it to work. I eventually found this tutorial and used some ideas from it. I'll post the solutions for the people who may have a similar problem.
This is what i placed in the /home/pi/.xinitrc file:
#!/bin/sh
xset -dpms
xset s off
xset s noblank
// not sure if this is needed.
killall -TERM matchbox-window-manager 2>/dev/null;
killall -9 matchbox-window-manager 2>/dev/null;
exec matchbox-window-manager -use_titlebar no &
iceweasel [someURL] &
sudo /etc/xdo_test.sh
I changed the python script to a shell script an inserted the following code:
sleep 20
$WIN=$(xdotool search --onlyvisible --class Iceweasel|head -1)
xdotool key --window $WIN c
while:
do
sleep 300
done
The while loop at the end is something I added because Xserver crashed from the moment it lost connection to the script. I'm still looking for a cleaner solution to end the script but this works for now. I'll update this awnser when I find one.
Thanks Sebastian Stigler for the help!
call xdo_test.sh before running the window manager

Wait for a process launched by another program to terminate

So I'm creating a quick script that basically launches xboxdrv then a game from steam to enable controller support. Yes, while the most games with controller support automatically work with the Xbox 360 controller, there are some games that require you to be running the controller under the xpad driver, else it won't recognize the controller for some reason. The game in question is Bit.Trip Runner 2 on Linux (XUbuntu).
The problem I'm having is trying to get the script to wait for the game to exit (since it gets launched by steam's own commands), and then terminate xboxdrv, to free up memory, but what is happening is when the game exits, I have to go into the terminal and hit Ctrl+C in order to move it along.
If possible, please explain in layman's terms, because this is my first full out batch scrpt for linux. Below is the script in question:
sudo --validate
sudo xboxdrv --silent --detach-kernel-driver --mimic-xpad --dbus session & sleep 2
steam steam://rungameid/$APPID #<-- I want the game to exit to then kill xboxdrv
wait -n $! #<-- If I don't put wait, it will immediately kill xboxdrv after the game launches
sudo killall xboxdrv
exit 0
Well, it seems like the issue was that wait wasn't applying properly, something about child processes. If it wasn't that it was waiting on xboxrdv, it was that it couldn't apply itself properly. After doing a bit more looking around, I happened upon this question, which gave me the code I needed for the wait. So what I ended up doing was adding that bit of code along with a pgrep -x command, so that it could grab and wait on the proper pid.
So in the end, the important part code ended up looking like this:
if [ "$GAMENAME" = "BTR2" ] || [ "$GAMENAME" = "Runner 2" ]; then
APPID=218060
GameProc=[r]unner2
fi
sudo --validate
sudo xboxdrv --silent --quiet --detach-kernel-driver --mimic-xpad --dbus session & sleep 2
steam steam://rungameid/$APPID & sleep 20
check_run_and_grab(){
if ps aux | grep "$GameProc" > /dev/null
then
GamePID=$(pgrep -x "$GameProc")
while kill -0 "$GamePID";do
sleep 5
done
sudo killall xboxdrv
exit 0
else
echo "Game process not found, waiting 5 seconds and trying again"
sleep 5
check_run_and_grab
fi
}
check_run_and_grab
To me, the only thing that would make this better is if it didn't care for capitalization for the game argument (first if statement).

Resources