Strech any front window to maximum size

Hi,

I’m trying to write a script, which stretches the frontmost window to maximal size, even with two displays.

The crucial points are:
¢ some applications are not scriptable
¢ some applications don’t even return the bounds of front window (like Preview.app with disabled AppleScript capabilities)
¢ some applications’ window 1 is not the visible front window

The present found main execptions are:
¢ Finder.app, which uses special bounds (doesn’t consider the menu bar)
¢ FireFox.app (AppleScript nightmare), which uses also special bounds
¢ Preview.app, which throws an error executing the get bounds of front window line

That’s what I have so far, suggestions are welcome

property Finder : false
property FireFox : false
property off_set : missing value
property scriptable : true
property AppName : ""

set menuSecondDisplay to false
tell application "Image Events" to set SecondDisplay to (count displays) > 1
tell paragraphs of (do shell script "defaults read /Library/Preferences/com.apple.windowserver DisplaySets | awk '/ Height =/||/ Width =/ ||/UnmirroredOriginX =/ ||/UnmirroredOriginY =/ {print $3}' | cut -f 1 -d ';'")
	set {d1height, d1x1, d1y1, d1width} to {item 1 as integer, item 2 as integer, item 3 as integer, item 4 as integer}
	try
		set {d2height, d2x1, d2y1, d2width} to {item 5 as integer, item 6 as integer, item 7 as integer, item 8 as integer}
	end try
end tell
if SecondDisplay then set menubarSecondDisplay to d2x1 < 0 -- true if the menu bar is on the second display

if d2x1 is not 0 then -- check if non mirrored
	tell application "System Events" to set AppName to name of (get 1st process whose frontmost is true)
	try
		tell application AppName to get version
		if result contains "unknown" then error
		tell application AppName to set {winx1, winy1, winx2, winy2} to (get bounds of front window)
		set scriptable to true
	on error
		tell application "System Events" to tell process AppName to set {{wPosx, wPosy}, {wWidth, wHeight}} to {position, size} of front window
		set {winx1, winy1, winx2, winy2} to {wPosx, wPosy, wPosx + wWidth, wPosy + wHeight}
		set scriptable to false
	end try
	set Finder to AppName is "Finder"
	set FireFox to AppName is "firefox-bin"
	if SecondDisplay then
		if menubarSecondDisplay then
			set display1 to (d2x1 < winx1 or d2y1 < winy1)
		else
			set display1 to (winx1 < d2x1 or winy1 < d2y1)
		end if
		set off_set to (((display1 is not menubarSecondDisplay) as integer) * 22) + ((Finder as integer) * 22)
		if display1 then
			set_Bounds(d1width, d1height, d1x1, d1y1)
		else
			set_Bounds(d2width, d2height, d2x1, d2y1)
		end if
	else
		set_Bounds(d1width, d1height, 0, 0)
	end if
end if

on set_Bounds(width, height, orix, oriy)
	if scriptable then
		tell application AppName to set bounds of window 1 to {orix, off_set, orix + width, oriy + height}
	else
		tell application "System Events"
			tell process AppName
				try
					set w to (get 1st window whose visible is true)
				on error
					set w to front window
				end try
				tell w
					set position to {orix, oriy + off_set}
					if FireFox then
						set size to {width, height - off_set}
					else
						set size to {width, height}
					end if
				end tell
			end tell
		end tell
	end if
end set_Bounds

Preview.app requires this approach:

tell application "System Events" to tell application process "Preview"
	set W to every window
	repeat with aW in W
		set {{p1, p2}, {s1, s2}} to aW's {position, size}
	end repeat
end tell

Thanks Adam,

Preview.app is already considered in the code.
If scriptability is disabled (default setting), it throws an error while getting the bounds
(Unfortunately enabling scriptability with this hint doesn’t work with my PPC 10.4.10 :/)

It worked for me for a while, but 10.4.10 killed it.

StefanK , you may want to see my post here: http://bbs.applescript.net/viewtopic.php?id=22439

The reason is because last week I downloaded your script to try and help you. But when I ran it I got bad information about my computer display. I usually have 2 displays attached to my computer, but at this point I only had one display attached. Your script gave me information about the display that wasn’t attached to my computer! I’ve tried several times in the past to read the plist files for information about my displays, in both the “by host” folder and the global plist file. Although I could get it to work initially, after a period of time they would always give me bad information. Probably because I often connect/disconnect displays to my computer and thus the plist files gets changed. I’ve come to the conclusion that reading from the plist files will never be reliable.

Anyway, when I saw you having the same problem I decided to do something about this problem once and for all. I decided to learn the C programming language and write my own program to query the Quartz Display Services of MacOSX for display information. So that’s how I’ve been trying to help you the last few days :smiley: although it was of course to help myself too. I think I have a reliable method now and you might like to use it. Anyway, it’s there if you want it.

I tried using it and it doesn’t want to play nice. >.<

First it told me d2x1 wasn’t defined so I threw a set d2x1 to “” in at the top and then it told me:

Script Editor got an error: Can't make {0, missing value, 1024, 768} into type bounding rectangle.

and highlighted “set bounds of window 1 to {orix, off_set, orix + width, oriy + height}”

Debugging it is out of my league so I figured I’d just let you know it didn’t play nice with my computer. :wink: Using it would be nice though for using Extra Suites and having windows and buttons be in the places they’re supposed to be when using mouse clicks and such.

Thanks for the reply.
As I use two displays, I couldn’t test the single display version reliably.
Here is a adjusted version, which should work also with one display

property Finder : false
property FireFox : false
property off_set : 0
property scriptable : true
property AppName : ""

set menuSecondDisplay to false
tell application "Image Events" to set SecondDisplay to (count displays) > 1
tell paragraphs of (do shell script "defaults read /Library/Preferences/com.apple.windowserver DisplaySets | awk '/ Height =/||/ Width =/ ||/UnmirroredOriginX =/ ||/UnmirroredOriginY =/ {print $3}' | cut -f 1 -d ';'")
	set {d1height, d1x1, d1y1, d1width} to {item 1 as integer, item 2 as integer, item 3 as integer, item 4 as integer}
	try
		set {d2height, d2x1, d2y1, d2width} to {item 5 as integer, item 6 as integer, item 7 as integer, item 8 as integer}
	end try
end tell
if SecondDisplay then set menubarSecondDisplay to d2x1 < 0

tell application "System Events" to set AppName to name of (get 1st process whose frontmost is true)
try
	tell application AppName to get version
	if result contains "unknown" then error
	tell application AppName to set {winx1, winy1, winx2, winy2} to (get bounds of front window)
	set scriptable to true
on error
	tell application "System Events" to tell process AppName to set {{wPosx, wPosy}, {wWidth, wHeight}} to {position, size} of front window
	set {winx1, winy1, winx2, winy2} to {wPosx, wPosy, wPosx + wWidth, wPosy + wHeight}
	set scriptable to false
end try
set Finder to AppName is "Finder"
set FireFox to AppName is "firefox-bin"
if SecondDisplay then
	if menubarSecondDisplay then
		set display1 to (d2x1 < winx1 or d2y1 < winy1)
	else
		set display1 to (winx1 < d2x1 or winy1 < d2y1)
	end if
	set off_set to (((display1 is not menubarSecondDisplay) as integer) * 22) + ((Finder as integer) * 22)
	if display1 then
		set_Bounds(d1width, d1height, d1x1, d1y1)
	else
		set_Bounds(d2width, d2height, d2x1, d2y1)
	end if
else
	set off_set to 22 + ((Finder as integer) * 22)
	set_Bounds(d1width, d1height, 0, 0)
end if


on set_Bounds(width, height, orix, oriy)
	if scriptable then
		tell application AppName to set bounds of window 1 to {orix, off_set, orix + width, oriy + height}
	else
		tell application "System Events"
			tell process AppName
				try
					set w to (get 1st window whose visible is true)
				on error
					set w to front window
				end try
				tell w
					set position to {orix, oriy + off_set}
					if FireFox then
						set size to {width, height - off_set}
					else
						set size to {width, height}
					end if
				end tell
			end tell
		end tell
	end if
end set_Bounds

Thanks for your suggestions, regulus,

I read it and it’s very helpful if you need to have also the display ID numbers,
but I think, it’s not necessary for my script. I changed a few things as you can see in the post right above

I guess you didn’t agree with me when I said “I’ve come to the conclusion that reading from the plist files will never be reliable.” That’s fine. I’m sure your script works great for your particular setup, but the question becomes does it work in all cases and will it continue to work over a long period of time? I’ve found numerous examples where reading from the plist file didn’t work, but I’ll just give you one example to show you what I mean.

For this example we’ll use the case where you have 2 user accounts on your computer and 2 displays attached to the computer. For this example if you don’t already have 2 user accounts just create a second one, then enable fast user switching so you can quickly switch between the user accounts.

Here’s a script, which uses your code, to test this with. I have the script setup so you can quickly see all the values of interest. Just save this script to a place where you can access it from both user accounts.

tell paragraphs of (do shell script "defaults read /Library/Preferences/com.apple.windowserver DisplaySets | awk '/ Height =/||/ Width =/ ||/UnmirroredOriginX =/ ||/UnmirroredOriginY =/ {print $3}' | cut -f 1 -d ';'")
	set {d1height, d1x1, d1y1, d1width} to {item 1 as integer, item 2 as integer, item 3 as integer, item 4 as integer}
	try
		set {d2height, d2x1, d2y1, d2width} to {item 5 as integer, item 6 as integer, item 7 as integer, item 8 as integer}
	end try
end tell
{{d1height, d1x1, d1y1, d1width}, {d2height, d2x1, d2y1, d2width}}

In your first user account setup the resolution of your 2 displays as you like. Then switch to the second user account using fast user switching. Change the resolution of the second display in this account to something different from what you had set in the first user account. Now run the above script in each user account noting the returned values. They values will be the same in each account… but we know that this is wrong because the display resolutions are different for each user!

If you want to try something else then just make the “arrangement” of the displays different in each user account. Once again you’ll find your script doesn’t return accurate information. The point is that once a person starts making changes to their display configuration (by plugging and unplugging monitors, changing resolutions, changing the arrangement etc.) the windowserver plist file quickly changes. That’s why the plist file has many display sets in it. The values that you’re reading into your script may not always reflect the current situation. Over time this will also become true on your machine.

Of course you’re free to write your script as you like, I just thought I’d point this out to you. :slight_smile:

I finally agree with you, you’re right. :slight_smile:
This is a version using your executable.



(*
 	the script requires the executable displaysInfo written by regulus6633, placed into usr/local/bin
 	it's available at http://rapidshare.com/files/54473723/displaysInfo.zip
 *)

property Finder : false
property FireFox : false
property off_set : 0
property scriptable : true
property AppName : ""


set displaysInfoParas to paragraphs of (do shell script "/usr/local/bin/displaysInfo | cut -d : -f 2") --> the path to the unix executable
if item 1 of displaysInfoParas is "" then
	display dialog "The executable \"displaysInfo\"" & return ¬
		& "couldn't be found. Please load it from" & return ¬
		& "http://rapidshare.com/files/54473723/displaysInfo.zip" & return ¬
		& "and install it in /usr/local/bin" buttons {"Cancel"} default button 1
	return
end if
set displaySets to {}
repeat with i from 0 to ((count of displaysInfoParas) div 10 - 1)
	set end of displaySets to getDisplaySet(items (1 + (i * 10)) thru (10 + (i * 10)) of displaysInfoParas)
end repeat

set menuSecondDisplay to false
set SecondDisplay to (count displaySets) > 1
set {{d1x1, d1y1}, {d1x2, d1y2}} to desktopPosition of item 1 of displaySets
set {d1height, d1width} to {d1y2 - d1y1, d1x2 - d1x1}
if SecondDisplay then
	set {{d2x1, d2y1}, {d2x2, d2y2}} to desktopPosition of item 2 of displaySets
	set {d2height, d2width} to {d2y2 - d2y1, d2x2 - d2x1}
	set menubarSecondDisplay to d2x1 < 0
end if

tell application "System Events" to set AppName to name of (get 1st process whose frontmost is true)
try
	tell application AppName to get version
	if result contains "unknown" then error
	tell application AppName to set {winx1, winy1, winx2, winy2} to (get bounds of front window)
	set scriptable to true
on error
	tell application "System Events" to tell process AppName to set {{wPosx, wPosy}, {wWidth, wHeight}} to {position, size} of front window
	set {winx1, winy1, winx2, winy2} to {wPosx, wPosy, wPosx + wWidth, wPosy + wHeight}
	set scriptable to false
end try
set Finder to AppName is "Finder"
set FireFox to AppName is "firefox-bin"
if SecondDisplay then
	if menubarSecondDisplay then
		set display1 to (d2x1 < winx1 or d2y1 < winy1)
	else
		set display1 to (winx1 < d2x1 or winy1 < d2y1)
	end if
	set off_set to (((display1 is not menubarSecondDisplay) as integer) * 22) + ((Finder as integer) * 22)
	if display1 then
		set_Bounds(d1width, d1height, d1x1, d1y1)
	else
		set_Bounds(d2width, d2height, d2x1, d2y1)
	end if
else
	set off_set to 22 + ((Finder as integer) * 22)
	set_Bounds(d1width, d1height, 0, 0)
end if

on getDisplaySet(p)
	tell p
		return {displayNum:item 1 as number, displayID:item 2, theResolution:{item 3 as number, item 4 as number}, bitDepth:item 10 as number, refreshRate:item 9 as number, desktopPosition:{{item 5 as number, item 6 as number}, {item 7 as number, item 8 as number}}}
	end tell
end getDisplaySet

on set_Bounds(width, height, orix, oriy)
	if scriptable then
		tell application AppName to set bounds of window 1 to {orix, off_set, orix + width, oriy + height}
	else
		tell application "System Events"
			tell process AppName
				try
					set w to (get 1st window whose visible is true)
				on error
					set w to front window
				end try
				tell w
					set position to {orix, oriy + off_set}
					if FireFox then
						set size to {width, height - off_set}
					else
						set size to {width, height}
					end if
				end tell
			end tell
		end tell
	end if
end set_Bounds

It took me awhile to come to that conclusion myself. I’m glad I could spare you the pain of not having to learn that lesson. It pained me every time my scripts stopped working because of changes to those windowserver plist files. No matter what I tried my scripts kept breaking and I finally had to give up reading those plists. I wish there was a better applescript way so as not to need a shell program, but I couldn’t find one.

In case you didn’t see it in my post, I changed the file on RapidShare so now there’s a new link to it. Please update your script to reflect the changed link. I promise not to change it any more!
http://rapidshare.com/files/54473723/displaysInfo.zip

Just for a follow up, I thought I’d let you know the updated version works for single monitors Stefan. :wink: Nice script.