Ryan (tekman) wrote,
Ryan
tekman

repos.rb

The RubyCocoa project makes Ruby an incredibly powerful scripting language in Mac OS X.

As an example, here's a script that I used to rearrange windows when switching between various monitors. Based on the width of the main screen (something which I couldn't find a robust way to query outside of the NSScreen Cocoa API), it applies my preferred size and positioning to specific windows I care about. If you run it with '-q', it instead dumps a structure with those windows' current sizes and positions, for feeding back into the script as configuration.

Enjoy:

#!/usr/bin/env ruby -w

require 'optparse'
require 'osx/cocoa' # http://rubycocoa.sourceforge.net
require 'pp'

options = { :query => false }
OptionParser.new do |opts|
  opts.banner = 'Usage: repos.rb [options]'
  opts.on( '-q', '--query', 'Query rather than set positioning' ) do |q|
    options[:query] = q
  end
end.parse!

def first_window_of( s ) %Q{the first window of process "#{s}"} end
WindowsOfInterest = {
  :adium_chat     => first_window_of('Adium')   + ' whose name is not "Contacts"',
  :adium_contacts => first_window_of('Adium')   + ' whose name is "Contacts"',
  :firefox        => first_window_of('Firefox') + ' whose name is not "Downloads"',
  :ical           => first_window_of('iCal'),
  :iterm          => first_window_of('iTerm'),
  :itunes         => first_window_of('iTunes'),
  :mail           => first_window_of('Mail'),
  :terminal       => first_window_of('Terminal'),
  :tweetie        => first_window_of('Tweetie') + ' whose name is "Tweetie"',
}
PropertiesOfInterest = [ :position, :size ]
ConfigurationForWidth = {
  2560 => {
    :adium_chat     => { :position => [2058, 1241], :size => [501, 357]   },
    :adium_contacts => { :position => [2419, 22],   :size => [141, 357]   },
    :firefox        => { :position => [632, 223],   :size => [1459, 1096] },
    :ical           => { :position => [3199, 800],  :size => [640, 715]   },
    :iterm          => { :position => [0, 740],     :size => [786, 860]   },
    :itunes         => { :position => [1080, 22],   :size => [1336, 946]  },
    :mail           => { :position => [0, 22],      :size => [1079, 717]  },
    :terminal       => { :position => [2560, 800],  :size => [641, 795]   },
    :tweetie        => { :position => [2058, 549],  :size => [500, 690]   },
  },
  1920 => {
    :adium_chat     => { :position => [1419, 844],  :size => [501, 357]   },
    :adium_contacts => { :position => [1785, 22],   :size => [135, 319]   },
    :firefox        => { :position => [397, 72],    :size => [1208, 1034] },
    :ical           => { :position => [949, 1203],  :size => [640, 715]   },
    :iterm          => { :position => [0, 355],     :size => [810, 844]   },
    :itunes         => { :position => [494, 22],    :size => [1280, 715]  },
    :mail           => { :position => [0, 22],      :size => [1079, 717]  },
    :terminal       => { :position => [312, 1202],  :size => [641, 723]   },
    :tweetie        => { :position => [1418, 293],  :size => [501, 550]   },
  },
}

def do_apple_script(s)
  result = OSX::NSAppleScript.alloc.initWithSource(s).executeAndReturnError(nil)

  # Return an array of the values (AppleScript uses 1-based indexing)
  (1..result.numberOfItems).map do |i|
    result.descriptorAtIndex( i ).int32Value
  end
end

main_display_width = Integer( OSX::NSScreen.mainScreen.frame.width )
window_properties = {}

if options[:query]

  WindowsOfInterest.each do |key,spec|
    window_properties[key] = {}
    PropertiesOfInterest.each do |prop|
      window_properties[key][prop] = do_apple_script(
        %Q{tell application "System Events" to get the #{prop} of #{spec}}
      )
    end
  end

  puts "#{main_display_width} =>"
  pp window_properties

else

  config = ConfigurationForWidth[main_display_width] or
    raise "No configuration for main display width #{main_display_width}"

  config.each do |window,props|
    props.each do |prop,rubyval|
      value = '{' + rubyval.join(',') + '}'
      do_apple_script(
        %Q{tell application "System Events" to set the #{prop} of #{WindowsOfInterest[window]} to #{value}}
      )
    end
  end

  system %Q{/Users/ryan/bin/emacsclient -e '(rdj-smartsize-frame-for #{main_display_width}))' > /dev/null}

end
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 2 comments