Created
May 5, 2009 18:39
-
-
Save johnnyt/107116 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
property apps_to_maximize : {"MacVim", "iTunes", "Dragon's Lair"} | |
property menubar_height : 22 | |
property fuzzy_limit : 10 -- number of pixels that the top and bottom could be off by | |
property unmaximized_window_bounds : {200, 100, 1200, 700} -- size that the unmaximized window should be (it will be placed on its current monitor) | |
property apps_with_wacky_coords : {"Dragon's Lair", "PivotalTracker"} | |
property apps_without_title_bars : {"Dragon's Lair", "PivotalTracker"} | |
property apps_bounds_to_secondary_monitor : {"Dragon's Lair"} | |
-- We now move ALL apps to primary monitor (except what is listed above) | |
-- property apps_bounds_to_primary_monitor : {"Finder", "Firefox", "MacVim", "Terminal", "iTunes"} -- "Sequel Pro", "Thunderbird", "Script Editor", "TextMate" | |
property apps_with_double_title_height : {"Finder", "Thunderbird"} | |
property apps_needed_to_activate_for_windows : {"Mail", "MacVim", "PivotalTracker", "Dragon's Lair"} | |
global window_is_on_primary_monitor | |
set window_is_on_primary_monitor to true | |
global monitor_properties | |
set monitor_properties to my monitorProperties() | |
global primary_monitor_bounds | |
set primary_monitor_bounds to my bounds_from_properties(monitor1 of monitor_properties) | |
global secondary_monitor_bounds | |
global multiple_monitors | |
if monitorCount of monitor_properties is equal to 2 then | |
set multiple_monitors to true | |
set secondary_monitor_bounds to my bounds_from_properties(monitor2 of monitor_properties) | |
else | |
set multiple_monitors to false | |
set secondary_monitor_bounds to {0, 0, 0, 0} | |
end if | |
global active_apps_with_windows | |
set active_apps_with_windows to my get_active_apps_with_windows() | |
--##################################################################################### | |
--##################################################################################### | |
--##################################################################################### | |
-- First move all windows (other than Dragon's Lair) to main monitor | |
my move_all_windows() | |
-- Maximize all windows of specified apps | |
my maximize_specified_apps() | |
-- Make Dragon's Lair active on all spaces | |
--tell application "Dragon's Lair" to activate | |
my remove_spaces_application_binding("com.fluidapp.FluidInstance.Dragon's Lair") | |
my set_spaces_application_binding_for_application("com.fluidapp.FluidInstance.Dragon's Lair", "All") | |
--##################################################################################### | |
--##################################################################################### | |
--##################################################################################### | |
on move_all_windows() | |
set dbg to {} | |
-- repeat with an in (apps_bounds_to_primary_monitor & apps_bounds_to_secondary_monitor) | |
repeat with an in my active_apps_with_windows | |
set app_name to name of application an | |
tell application an | |
try | |
--activate | |
repeat with x from 1 to (count windows) | |
set current_window to window x | |
if visible of current_window is true then | |
set current_window_needs_to_be_moved to true | |
set returned_bounds_list to bounds of current_window | |
if (count returned_bounds_list) = 4 then | |
set current_bounds to returned_bounds_list | |
else | |
set current_bounds to item 1 of returned_bounds_list | |
end if | |
set current_bounds to bounds of current_window | |
set new_bounds to current_bounds | |
if (app_name is in apps_bounds_to_secondary_monitor) then | |
set new_bounds to my convert_bounds(secondary_monitor_bounds) | |
else | |
set possible_new_bounds to my relative_bounds_on_current_monitor(current_bounds) | |
if my bounds_match(current_bounds, possible_new_bounds) then | |
set current_window_needs_to_be_moved to false | |
else | |
set new_bounds to possible_new_bounds | |
end if | |
end if | |
if current_window_needs_to_be_moved then | |
set bounds of current_window to new_bounds | |
end if | |
end if | |
end repeat | |
on error error_string | |
-- return {error_string, app_name, returned_bounds_list} | |
end try | |
end tell | |
end repeat | |
return dbg | |
end move_all_windows | |
on maximize_specified_apps() | |
repeat with app_name in apps_to_maximize | |
if active_apps_with_windows contains app_name then | |
tell application app_name | |
-- activate | |
repeat with x from 1 to (count windows) | |
-- try | |
my toggle_window(app_name, window x, true) | |
-- on error error_string | |
-- end try | |
end repeat | |
end tell | |
end if | |
end repeat | |
end maximize_specified_apps | |
on get_active_apps_with_windows() | |
set app_names to {} | |
tell application "System Events" to set all_procs to application processes | |
repeat with i from 1 to count all_procs | |
tell application "System Events" to tell process i to set app_name to short name | |
if apps_needed_to_activate_for_windows contains app_name then | |
activate application app_name | |
delay 0.5 | |
end if | |
tell application "System Events" to tell process i | |
if (count windows) > 0 then | |
set end of app_names to app_name | |
end if | |
end tell | |
end repeat | |
--return {"Safari", "PivotalTracker"} | |
return app_names | |
end get_active_apps_with_windows | |
on bounds_match(current_bounds, possible_new_bounds) | |
set lefts_match to (item 1 of current_bounds) = (item 1 of possible_new_bounds) | |
set tops_match to ((item 2 of current_bounds) = (item 2 of possible_new_bounds)) or ((item 2 of current_bounds) = ((item 2 of possible_new_bounds) + menubar_height)) or ((item 2 of current_bounds) = ((item 2 of possible_new_bounds) - menubar_height)) | |
return lefts_match and tops_match | |
end bounds_match | |
on process_for_app_name(app_name) | |
tell application "System Events" to get the first process whose short name is app_name | |
end process_for_app_name | |
on convert_bounds(old_bounds) | |
set pm_height to (item 4 of primary_monitor_bounds) | |
set sm_height to (item 4 of secondary_monitor_bounds) | |
set screen_height to item 4 of primary_monitor_bounds | |
set window_height to (item 4 of old_bounds) - (item 2 of old_bounds) | |
if multiple_monitors then | |
set new_top to -(item 2 of old_bounds) + (pm_height - sm_height) | |
set new_bottom to -(item 4 of old_bounds) + (pm_height + sm_height) | |
else | |
set new_bottom to screen_height - (item 4 of old_bounds) + window_height | |
set new_top to screen_height - (item 2 of old_bounds) - window_height | |
end if | |
return {item 1 of old_bounds, new_top, item 3 of old_bounds, new_bottom} | |
end convert_bounds | |
on monitorProperties() | |
--system_profiler parsing | |
set SPDisplaysData to (do shell script "system_profiler SPDisplaysDataType") | |
set text item delimiters to "Displays:" | |
set SPDisplaysData to text item 3 of SPDisplaysData | |
set text item delimiters to (word 1 of SPDisplaysData) | |
copy text item 1 of SPDisplaysData to text item delimiters | |
set SPDisplaysData to text items 2 thru -1 of SPDisplaysData | |
set text item delimiters to "" | |
repeat with i from 2 to length of SPDisplaysData | |
if character 1 of item i of SPDisplaysData is not " " then | |
set display1 to items 2 thru (i - 1) of SPDisplaysData | |
set display2 to items (i + 1) thru -1 of SPDisplaysData | |
exit repeat | |
end if | |
end repeat | |
--END OF system_profiler parsing | |
set layout_values to (do shell script "displays_layout") | |
set {displayCount, output} to {1, {}} | |
repeat with curList in {display1, display2} | |
set mainDisplay to false | |
-- We have already parsed the primary monitor and are looking at the non-existent secondary monitor | |
if item 1 of curList contains "Status: No display connected" then | |
set monitorCount to 1 | |
set display2 to {width:missing value, height:missing value, OriginX:missing value, OriginY:missing value} | |
else | |
repeat with i from 1 to length of curList | |
set curItem to item i of curList | |
if curItem contains "Resolution:" then | |
set {y, x} to {word 2 of curItem, word 4 of curItem} | |
end if | |
if curItem contains "Main Display: Yes" then | |
set mainDisplay to true | |
end if | |
end repeat | |
if mainDisplay then | |
set display1 to {width:y as integer, height:x as integer, OriginX:(word 4 of layout_values) as integer, OriginY:(word 5 of layout_values) as integer} | |
else | |
set monitorCount to 2 | |
set display2 to {width:y as integer, height:x as integer, OriginX:(word 9 of layout_values) as integer, OriginY:(word 10 of layout_values) as integer} | |
end if | |
end if | |
end repeat | |
return {monitor1:display1, monitor2:display2, monitorCount:monitorCount} | |
end monitorProperties | |
on relative_bounds_on_current_monitor(current_bounds) | |
set mon_bounds to my get_monitor_bounds(current_bounds) | |
set rel_bounds to {0, 0, 0, 0} | |
repeat with i from 1 to 4 | |
set item i of rel_bounds to (item i of current_bounds) - (item (((i - 1) mod 2) + 1) of mon_bounds) | |
end repeat | |
return rel_bounds | |
end relative_bounds_on_current_monitor | |
--##################################################################################### | |
--##################################################################################### | |
--##################################################################################### | |
--##################################################################################### | |
--##################################################################################### | |
-- For maximizing / minimizing windows | |
--##################################################################################### | |
--##################################################################################### | |
on toggle_window(app_name, win_to_toggle, always_maximize) | |
try | |
if apps_with_wacky_coords contains app_name then | |
set window_bounds to my convert_bounds(bounds of win_to_toggle) | |
else | |
set window_bounds to bounds of win_to_toggle | |
end if | |
set monitor_bounds to my get_monitor_bounds(window_bounds) | |
-- Already maximized | |
if fuzzy_match_bounds(window_bounds, monitor_bounds, (apps_with_double_title_height contains app_name)) then | |
if not always_maximize then unmaximize_window(win_to_toggle, monitor_bounds) | |
else | |
if (apps_without_title_bars contains app_name) and window_is_on_primary_monitor then | |
set item 2 of monitor_bounds to ((item 2 of monitor_bounds) - menubar_height) | |
set item 4 of monitor_bounds to ((item 4 of monitor_bounds) - menubar_height) | |
end if | |
set bounds of win_to_toggle to monitor_bounds | |
-- Some apps (e.g. MacVim) have a grid for bounds, and may need to be adjusted up a little | |
set set_bounds to bounds of win_to_toggle | |
if (item 2 of set_bounds) is not equal to (item 2 of monitor_bounds) then | |
set item 4 of monitor_bounds to ((item 4 of monitor_bounds) - 4) | |
set bounds of win_to_toggle to monitor_bounds | |
end if | |
end if | |
on error | |
set invalidNum to true | |
end try | |
end toggle_window | |
on unmaximize_window(win_to_change, monitor_bounds) | |
set new_bounds to {0, 0, 0, 0} | |
repeat with i from 1 to 4 | |
set item i of new_bounds to (item (((i - 1) mod 2) + 1) of monitor_bounds) + (item i of unmaximized_window_bounds) | |
end repeat | |
set bounds of win_to_change to new_bounds | |
end unmaximize_window | |
on fuzzy_match_bounds(win_bounds, mon_bounds, window_has_double_title_height) | |
set win_top to item 2 of win_bounds | |
if window_has_double_title_height then set win_top to win_top - menubar_height | |
set left_matches to (item 1 of win_bounds is equal to item 1 of mon_bounds) | |
set right_matches to (is_within(item 3 of win_bounds, {((item 3 of mon_bounds) - fuzzy_limit), ((item 3 of mon_bounds) + fuzzy_limit)})) | |
set top_matches to is_within(win_top, {((item 2 of mon_bounds) - fuzzy_limit), ((item 2 of mon_bounds) + fuzzy_limit)}) | |
--set bottom_matches to is_within(item 4 of win_bounds, {((item 4 of mon_bounds) - fuzzy_limit), ((item 4 of mon_bounds) + fuzzy_limit)}) | |
return left_matches and right_matches and top_matches -- and bottom_matches | |
end fuzzy_match_bounds | |
on get_monitor_bounds(window_bounds) | |
set is_in_primary_width to my is_within(item 1 of window_bounds, {item 1 of primary_monitor_bounds, item 3 of primary_monitor_bounds}) | |
set is_in_primary_height to my is_within(item 2 of window_bounds, {item 2 of primary_monitor_bounds, item 4 of primary_monitor_bounds}) | |
-- Is on primary monitor | |
if (not multiple_monitors) or (is_in_primary_width and is_in_primary_height) then | |
return {item 1 of primary_monitor_bounds, menubar_height, item 3 of primary_monitor_bounds, item 4 of primary_monitor_bounds} | |
else | |
set window_is_on_primary_monitor to false | |
return secondary_monitor_bounds | |
end if | |
end get_monitor_bounds | |
on bounds_from_properties(monitor_props) | |
set _left to OriginX of monitor_props | |
set _top to OriginY of monitor_props | |
return {_left, _top, (_left + (width of monitor_props)), (_top + (height of monitor_props))} | |
end bounds_from_properties | |
on is_within(var, range) | |
return (var ≥ item 1 of range and var < item 2 of range) | |
end is_within | |
--##################################################################################### | |
--##################################################################################### | |
--##################################################################################### | |
--##################################################################################### | |
--##################################################################################### | |
-- For changing spaces settings | |
--##################################################################################### | |
--##################################################################################### | |
on make_lowercase(the_string) | |
return do shell script "echo " & quoted form of the_string & " | /usr/bin/perl -pe 'use encoding utf8; s/(\\w)/\\L$1/gi'" | |
end make_lowercase | |
on list_to_string(l, d) | |
tell (a reference to my text item delimiters) | |
set {o, contents} to {contents, d} | |
set {l, contents} to {"" & l, o} | |
end tell | |
return l as Unicode text | |
end list_to_string | |
on string_to_list(s, d) | |
tell (a reference to my text item delimiters) | |
set {o, contents} to {contents, d} | |
set {s, contents} to {s's text items, o} | |
end tell | |
return s | |
end string_to_list | |
on set_spaces_application_binding_for_application(application_bundle_id, chosen_space) | |
set application_bundle_id to my make_lowercase(application_bundle_id) | |
if chosen_space is in {0, "None"} then | |
my remove_spaces_application_binding(application_bundle_id) | |
else | |
if chosen_space = "All" then set chosen_space to 65544 | |
my set_spaces_application_bindings((run script "{|" & application_bundle_id & "|: " & chosen_space & "}") & (my get_spaces_application_bindings())) | |
end if | |
end set_spaces_application_binding_for_application | |
on remove_spaces_application_binding(application_bundle_id) | |
set application_bundle_id to my make_lowercase(application_bundle_id) | |
set app_bindings to my get_spaces_application_bindings() | |
try | |
get app_bindings as string | |
on error error_string | |
set app_bindings to my string_to_list(text 13 thru -20 of error_string, ", ") | |
end try | |
set new_bindings to {} | |
repeat with i in app_bindings | |
set i to contents of i | |
if i does not start with "|" & application_bundle_id & "|:" then set end of new_bindings to i | |
end repeat | |
my set_spaces_application_bindings(run script "{" & (my list_to_string(new_bindings, ", ")) & "}") | |
end remove_spaces_application_binding | |
on get_spaces_application_bindings() | |
tell application "System Events" to tell spaces preferences of expose preferences to return (get application bindings) | |
end get_spaces_application_bindings | |
on set_spaces_application_bindings(new_bindings) | |
tell application "System Events" to tell spaces preferences of expose preferences to set application bindings to new_bindings | |
end set_spaces_application_bindings |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment