I've been searching all over the place for a solution to this.
How can I show/hide (or minimize/unminimize if you rather) Linux windows.
I'm interested in any solution in any language.
I use Debian, Gnome, Metacity and Compton composite manager if they're relevant
Note: I tried using wmctrl but the toggle,hidden feature of wmctrl has been broken for a while and it's not been updated in two years so unlikely to work any time soon. The net is full of bug reports concerning this.
You can use xdotool:
$ xdotool search --name "Stack Overflo"
24415619
$ xdotool windowminimize 24415619
Basically, you first find a window (by title, by active state etc.), which gives you its ID. Then you invoke commands. There are many ways to find a window, see the manpage.
xdotool is available as a package in at lease Debian, Ubuntu and Fedora.
Note: Shamelessly stolen from this answer: https://superuser.com/questions/186748/how-to-hide-or-minimize-x11-window-from-console
Maybe you can try something like this. It uses xdotool like #sleske suggested. I bind the script to a mouse button using xbinkeys.
#!/bin/bash
file=/tmp/last_active_window
if [[ -s $file ]] ; then
xdotool windowmap `cat $file`
cat /dev/null > $file
else
wid=`xdotool getactivewindow`
xdotool windowunmap $wid
echo $wid > $file
fi
you can hide and unhide windows using
xdotool windowunmap id
xdotool windowmap id
and you can get the id by
xdotool getactivewindow
this gets you the id for the current active window and if you want to search for the id, by application name or the pid
xdotool search --onlyvisible --name nameofapp
xdotool search --pid pid
Related
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
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.
I have a script which launches multiple gvim windows. I want to position them in a certain way. wmctrl can do this, but because there are multiple instances, the window names are ambiguous. I figure: use pids.
gvim /tmp/xxx &
X=$!
wmctrl -lp | grep $X
echo $X
wmctrl -lp | grep GVIM
echo sleeping
sleep 3
wmctrl -lp | grep GVIM
The output is:
5211
sleeping
0x03400062 0 5218 localhost xxx (/tmp) - GVIM
It seems gvim starts out with pid 5211 but launches a new process for the actual window. Also, that process doesn't exist yet.
How can I unambiguously get the wmctrl window handle of the gvim instance I just started? Or should I use something else?
The --echo-wid option looks nice but I am using KDE.
I just ran into the same problem, and solved it by running
gvim -f &
pid=$!
just as n.m. suggested in the comments above.
The manpage of gvim sais:
-f Foreground. For the GUI version, Vim will not fork and detach from the
shell it was started in. On the Amiga, Vim is not restarted to open a new
window. This option should be used when Vim is executed by a program that
will wait for the edit session to finish (e.g. mail). On the Amiga the
":sh" and ":!" commands will not work.
which explains why it works.
I don't know if you tried this, or if the answer even matters anymore, but I hate leaving a good question unanswered :)
credit goes to n.m. for pointing out the -f switch
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
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.