Use terminal to display image without losing focus - linux

I have a bash-script in which I want to display an image to the user. This is possible using ImageMagick's display.
display image.png
But now the focus of the terminal window is lost, and is placed to the image. To continue my bash-script I have to ask the user to click on the terminal before continuing. This is unwanted behaviour.
Is there a way to display an image without losing the focus of my bash terminal? I want it to get it work on Ubuntu Linux (12.04).

Here is a not-too-awkward solution using wmctrl:
wmctrl -T master$$ -r :ACTIVE: ; display image.png & sleep 0.1 ; wmctrl -a master$$
To explain, I'll break it down into steps:
wmctrl -T master$$ -r :ACTIVE:
To control a window, wmctrl needs to know its name, which by default is its window title. So, this step assigns the current window to a unique name master$$ where the shell will expand $$ to a process ID number. You may want to choose a different name.
display image.png &
This step displays your image as a "background" process. The image window will grab focus.
sleep 0.1
We need to wait enough time for display to open its window.
wmctrl -a master$$
Now, we grab focus back from display. If you chose a different name for your master window in step 1, use that name here in place of master$$.
If wmctrl is not installed on your system, you will need to install it. On debian-like systems, run:
apt-get install wmctrl
wmctrl supports Enlightenment, icewm, kwin, metacity, sawfish, and all other EWMH/NetWM compatible X-window managers.
Alternative approach that doesn't require knowing the window title
First, get the ID of the current window:
my_id=$(wmctrl -l -p | awk -v pid=$PPID '$3 == pid {print $1}')
We can now use this ID in place of a window title. To launch display while maintaining focus in the current window:
display image.png & sleep 0.1 ; wmctrl -i -a "$my_id"

in addition to John1024 answer.
yet another way to get wid of active window:
$ xdotool getwindowfocus
and set focus:
$ xdotool windowfocus <wid>
so the full command will look like this (note the option -i, it is important!):
$ wid=$(xdotool getwindowfocus); display image.png & sleep 0.1; xdotool windowfocus $wid
p.s. read about xdotool.

Without losing the focus of terminal you can use sublime text to open any image
subl image.png

You can use picterm, it was created for this purpose: https://github.com/artemsen/picterm

Related

bash: how get xsel -o to paste to focused window if command invoked by hotkey in fluxbox

The trackpad on my laptop will not middle-mouse paste. I figured it should be easy to simulate, just focus the target app and invoke 'xsel -o' with a hotkey from fluxbox. But it won't work, that is, xsel -o operates, but its output does not go to the focussed app.
Man xsel states that the -o option sends the current selection to standard output, which I assumed would be the app with focus. Could someone explain why it does not do so in this situation, and how to achieve the desired result?
That's not what "standard output" means.
Standard output is where commands like echo and printf send their output by default. It is the screen in a terminal. Run xsel -o in your terminal and you will see the output displayed.
You need a tool that actually simulates the middle click or simulates an X11 paste.
I believe you can use xdotool to do this sort of thing (among other tools).
You can easily do this with xdotool:
xdotool getwindowfocus click 2

wmctrl to open window without focus

I am using the command:
wmctrl -a **id of application** -i
This is very close to what I am looking for, however Is there a away I can use wmctrl without bringing focus to the application.
For example if i run the command to bring up a window on my 2nd screen in terminal the focus of the mouse and keyboard stay on terminal.
xdotool may come in handy in your situation.
You should save your active window's ID to temporary file:
xdotool getactivewindow > ~/.window_id
Then focus desired window:
wmctrl -a **id of application** -i
And then restore focus to the previous window:
xdotool windowfocus $(cat ~/.window_id)
xdotool windowactivate $(cat ~/.window_id)
Using xbindkeys, xdotool and wmctrl combined create a very powerful tool-set.

Attach to 'screen' session with creating a new screen window

I have a screen session running with several windows. I want to attach to it, create a new screen window within it and start a shell in that new window.
Question: How can I do this from the command line outside the screen session?
I already tried a lot, e. g. screen -x (but it attaches to one of the existing screen windows; it does not create a new one nor does it start a new shell). Any hints are welcome.
Environment is Linux (Ubuntu 12.04).
Add new detached window to sesion_name and run command
screen -S sesion_name -x -X screen bash -c 'command; exec bash'
To choose a window to join, use the -p option. Giving + will create a new one, so your command is simply:
screen -x session_name -p +
This is documented on the man page:
-p n̲u̲m̲b̲e̲r̲_o̲r̲_n̲a̲m̲e̲|̲-̲|̲=̲|̲+̲
Preselect a window. This is useful when you want to reattach to a
specific windor or you want to send a command via the "-X" option
to a specific window. As with screen's select commant, "-" selects
the blank window. As a special case for reattach, "=" brings up the
windowlist on the blank window.
I found something on the mailing list, thank you tuxuday :)
I'm doing it now this way:
#!/bin/bash
screen -X screen -t NEWWINDOW # create new window (switches existing attached terminal)
sleep 0.1
screen -X other # switch existing attached terminal back to its old window
sleep 0.1
gnome-terminal -e 'screen -x -p NEWWINDOW' # connect to new window
I'm not sure about those sleeps, maybe they aren't necessary in all environments, but I can wait those 0.2s easily.
My .bash_aliases is changing the screen window title with a delay, so the awkward NEWWINDOW won't stick for long (and thus not hinder further calls to this script).

Using xdotool to locate click and apply appropriate action

I would like to have xdotool detect if a right-click is on a particular window (I can capture window IDs without problem), and then run the appropriate shell command/function, if the click was on the desired window..
In real terms this means I want xdotool to get the window ID of a VLC video playback window, and then to run a specific command if I right click on that window.
I am using BASH 4.2.0(1)-release, and Xdotool 2.20101012.3049
EDIT: This is as close as I have got, but it does not work:
xdotool search --name "VLC" behave %# mouse-click exec 'myscript'
However, these commands DO work, but is not really what I need:
xdotool search --name "VLC" behave %# mouse-enter exec 'myscript'
xdotool search --name "VLC" behave %# mouse-leave exec 'myscript'
Cheers..
Something like following might work:
xdotool behave 18893317 mouse-click exec '/usr/bin/bash -c "echo hi"'
However xdotool doesn't work for arbitrary applications. You could try to read mouse events directly using: evdev.py
ls -l /dev/input/by-id/usb-062a_0000-event-mouse
lrwxrwxrwx 1 root root 9 2011-12-21 18:05 /dev/input/by-id/usb-062a_0000-event-mouse -> ../event4
evdev.py /dev/input/event4
When you get click you can use coordinates to determine if it's within VLC window (by comparing with coordinates returned by xdotool).
I realize this is a very old thread, but man xdotool SENDEVENT NOTES explains (implicitly) why 'mouse-click' may not work.
Alternatively, using 'focus' instead of 'mouse-click' does work for a user mouse click.
Note that the command
xdotool search --name "VLC" behave %# focus exec 'myscript'
may not terminate, but remain active. At least this is true for the way I am trying to use it, to set cropping locations in imagemagic, thus
xdotool search --name "imagemagic" behave %# focus getmouselocation

How can I tell whether I'm in a screen?

When using screen in linux, how can I tell if I'm in a screen or not?
I could do exit and I'll exit a screen if I was in one, but if I wasn't, then I'll end up closing my terminal.
When doing screen -r, I could see if I have other screens attached, but how do I know if my current terminal is one of those attached screens?
Check $STY. If it's null, you're on a "real" terminal. If it contains anything, it's the name of the screen you're in.
If you are not in screen:
eric#dev ~ $ echo $STY
eric#dev ~ $
If you are in screen:
eric#dev ~ $ echo $STY
2026.pts-0.ip-10-0-1-71
Another way I've done it is to echo $TERM.
$ echo $TERM
screen
Since I end up doing this a lot, I added an alias into my .bashrc file:
alias trm='echo $TERM'
This way, whether in screen or not, if I just execute 'trm' it will show me whether I'm in SCREEN or elsewhere (usually XTERM).
Alternative approach to check if you are in screen.
type:
Ctrl-a ?
If you see the screen help you are in screen.
Otherwise you'll get a question mark '?' on the prompt.
Since all of the other methods here rely on environment variables (which can simply be overridden) or the command character for screen (which can also be overridden), the most foolproof way to check would be to list all the ancestors of the current process.
pstree --show-parents -p $$ | head -n 1 | sed 's/\(.*\)+.*/\1/' | grep screen | wc -l
If it prints 1, then the current process you're running has an ancestor with the word 'screen' in the executable's name, otherwise there wasn't.
A more facile visible inspection might be obtained from:
pstree --show-parents -p $$ | head -n 1 | sed 's/\(.*\)+.*/\1/' | less
My solution to the problem is a lot simpler: just hitting TAB makes the full terminal blink (a quick video inversion) if you are inside GNU Screen.
Tested working on most Linux (Ubuntu, Kali, Debian, RaspBerry... etc) and FreeBSD, GUI and any terminal, local or remote, including CtrlAltFn ones.
As an exception for this method, please, note this (rather complex, but possible) case scenario:
1.- SSH into computer A (lets assume Linux).
2.- Enter a new screen -S AScr from remote terminal on computer A.
3.- SSH from GNU Screen AScr terminal into Computer B.
4.- Enter a new screen -S BScr from remote terminal on computer B.
You are inside a Screen on cases 2 and 4, and outside a Screen on cases 1 and 3, but the terminal will blink on cases 2, 3 and 4.
While ssh'd into a remote (older) system I noticed that $TERM indicated I was using 'screen-256color', however there was no termcap/terminfo entry for that, so I was forced to resort to the following in .bashrc to prevent the terminal from producing occasional garbage:
case $TERM in
(screen-256color) export TERM='screen'
esac
to get it to use the plain entry instead.
TL;DR, $TERM will usually indicate if you are in a screen session when ssh'd remotely. You can use case $TERM in (screen*) echo "you are in a screen session"; esac if you just want a visual clue and don't need to do something specific
Add one or more of the followings into your .bashrc
alias mysession='echo ${STY}'
alias myterm='echo ${TERM}'
alias isscreen='if test -n "$STY"; then echo " screen session: ${STY}"; else echo " NOT a screen session"; fi'
Then you can know if you are inside a screen by typing simple commands.
The problem with most of the above answers is that we might be in a subshell of an attached screen session. Or we might be opening a shell to a remote host from within a screen session. In the former case, we can walk the process tree parentage and match for the screen program name. In the latter case, most of the time, we can check the TERM variable for something like screen*.
My answer os similar to /u/Parthian-Shot but not so dependent on the pstree utility; the options he use are not available to me. On the other hand, my implementation is still Linux-dependent: for non-Linux systems, one must tweak the ps command; for systems with older shells that don't support arrays, you'll have yet more work-arounds. But anyway:
ps_walk_parents() {
local tmp
local ppid=$PPID
while [[ $ppid != 1 ]]; do
tmp=($( ps -o ppid,comm -p $ppid ))
ppid=${tmp[0]} # grab parent pid
echo ${tmp[1]} # output corresponding command name
done
}
if [[ "$TERM" =~ screen* ]] || ps_walk_parents |grep -qxi screen ; then
# we are in a screen terminal
fi
We could optimize our function a bit to stop searching if/when a process parent matches the target command name ("screen"), but in general, the function will only hit 2 to 3 iterations. Presumably you want to put this code in some startup initialization such as .bashrc or .profile or something, so again, not worth optimizing.
screen -ls can tell you.
Outside screen:
$ screen -ls
There are screens on:
16954.pts-1.auds916 (Detached)
242.pts-8.auds916 (Detached)
2 Sockets in /tmp/screens/S-glennj.
Inside a screen:
$ screen -ls
There are screens on:
16954.pts-1.auds916 (Attached)
242.pts-8.auds916 (Detached)
2 Sockets in /tmp/screens/S-glennj.

Resources