4

I have a script that I'm trying to use to make handing applications easier. Right now it gets the window id of an application name (the first parameter) and checks if the window_id exists or not. If it doesn't exist, it runs the command to open that applications (second parameter. If it does exist, it uses wmctrl to get the window by window_id and move it to the front.

My plan is to add this script to shortcuts for each application I use often. However, I want to add the ability to cycle through all the windows open for an application, instead of just being able to raise the last one open. Any recommendations on how to do this in bash? Would I need to set a global system variable? Though it's obvious, I'm fairly new to bash. Here's the script for windowctl, the place I want to extend is the get_window_id function.

#!/bin/bash
#command [app_name] [app_command]

function get_window_id() {
    #this is the part I want to extend
    window_id=$(wmctrl -l | grep -i "$1" | tail -1 | cut -f1 -d" ")
}

function open_app() {
    exec $2  
}

get_window_id $1

if [ -z $window_id ]
    then 
        open_app $1 $2
    else
        wmctrl -i -a "$window_id" 
fi

An example would be adding the command windowctl sublime subl3 to Alt+S.

1

I've been long using a miniscript I named lonew for this. It's meant to be short for "lastof or new". lastof is another script of mine, which attempts to find a visible window that matches a given command a was accessed the most recently.

Both of the scripts are below:

(they might use some refactoring but they get the job done)

lonew:

#!/bin/bash
CMD="$1"; shift; ARGS="$@"
lastof $CMD || { echo $CMD $ARGS; $CMD $ARGS & }
disown

lastof:

#!/usr/bin/env ruby
#open-last
#List all windows and sort them by the time they were last accessed

require 'shellwords'

XTIME="_NET_WM_USER_TIME"

QARGV=ARGV.map {|arg| Shellwords.escape(arg)}

ids=IO.popen "xdotool search --onlyvisible #{QARGV.join(" ")}"
max_time_id=nil
max_time=nil

ids.each_line do |id|
  id.chomp!
  puts "id=#{id}"
  time=`xprop -id #{id} #{XTIME}`.split('=')[1].to_i

  max_time||=time
  max_time_id||=id
  if time > max_time
    max_time=time
    max_time_id=id
  end
end
exit(1) unless max_time_id
puts "Switching to ID: #{max_time_id}"
exit system("xdotool windowactivate #{max_time_id}")

__END__
1

Perhaps this is something along the lines of what you are looking for. I have just used sleep, but you can use a dialog such as yad or zenity, and change the loop so that it keeps cycling, or whatever you need. You can then add a hot-key as needed .

It requires that you prime the script with the application's startup command, and also the application's window title regex (which can vary from window to window for a specific application.

shortname=$1
case $shortname in
  (firefox)  cmd='firefox';  rx='Mozilla Firefox$';; 
 (nautilus)  cmd='nautilus'; rx=' (-|—) File Browser';;
        (*)  echo 'unknown shortname'; exit;;
esac
id=( $(wmctrl -l | awk "/$rx/"'{print $1}') )
(( !${#id[@]} )) && { "$cmd" & exit; }
for (( i=0; i<${#id[@]}; i++ )) ;do
    wmctrl -i -a ${id[i]}
    sleep 3
done

Note that wmctrl cannot activate (interect with) a particular tab within an application's X Window.

  • While this script is certainly an improvement, doesn't allow me cycle through the open windows when running it in the terminal. It just changes the focus to the latest one. Do you have any recommendation on how to modify it so I can cycle through open windows or should that already be the case and I need to look at how I've adapted it? Also, as the first impelmentation, I am trying to cycle through every open window of chromium (or open chromium if it's closed). Does this command cycle through every application listed? – Deciple Aug 7 '15 at 21:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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