Sizing an apps window, then bringing only that window to front

This is all there is to it, it should work with any app, as a matter of fact, but you’ll soon discover that it won’t with some for some reason. Mainly because of malformed info.plist files I believe, but it works with most apps!

If you are happy with the window size of said App, and only wants to change the position, feed width and height to the handler with a size of 0!

You should know that the app is running before running this handler.

Tell application "YourApp" to launch

certifies that!

Another way is to test that with this handler:


on isrunning(appName)
	local proceccsNameList
	tell application id "sevs" to set proceccsNameList to name of application processes
	if appName is in proceccsNameList then return true
	return false
end isrunning

Here is the script that brings a window with the preferred size and position to front. If the window isn’t in your space, and you have activated the setting jump to the space where the app has open windows, it will take you to that space.

You have to be sure that the app in speak is running before using it!


script genUI
	# © McUsr 2012 and put in public domain, you may not post this as a stand-alone thing 
	# anywhere else, nor put into a public repository. 
	# Please refer to this link: http://macscripter.net/edit.php?id=157665
	on posFrontWinForAppAndDisplay(appname, x1, y1, w, h)
		local bid, success, probe, ctr
		
		set {success, ctr} to {false, 0} # maybe no windows in this space
		repeat while success = false
			set ctr to ctr + 1
			tell application id "sevs"
				if UI elements enabled = false then set UI elements enabled to true
				tell application process appname
					set bid to bundle identifier of it
					try
						set position of its front window to {x1, y1}
						set success to true
						
						if not (w = 0 and h = 0) then
							set size of window 1 to {(w - x1), (h - y1)}
						end if
					end try
				end tell
			end tell
			if success then
				do shell script "open -b \"" & bid & "\""
			else if ctr = 1 then
				do shell script "open -a " & appname
			else
				return 0 # second time without any success. -- Missing windows?
			end if
		end repeat
	end posFrontWinForAppAndDisplay
end script
genUI's posFrontWinForAppAndDisplay("FreeMind", 0, 22, 800, 800)

# Xcode uses the "non-flipped" "cocoa model" of window addressing, where the left lower corner is the start point 
# for x1, y1 You'll have to trial and error a little!
# Terminal is even worse, haven't figured it out, but VLC, FreeMind, and such apps works!
# When you pass the width parameter, be sure to add up for x1, and the same goes for height where you should 
# add in y1.

I have tested it on a range of apps, it is finished, as it stands, and it works very well in most of the cases. When you pass the width parameter, be sure to add up for x1, and the same goes for y1.

You’ll have to adjust the values for some apps. And some apps are just impossible! :slight_smile:

This solutions is as generic solution, as it can be.

There are two kinds of impossible apps.

The first kind is the one Terminal is in, apps that choose how to interpret, or neglects the call to set the size.

Then there are this other kind, which XQuartz and Omni Graffle Professional is in, the problem with this kind, is that they have different names and display names, which means that you have to feed the name to System Events, and the display name to open.

I’ll be back with handlers and a howto for those apps, for completion. But then we are not talking generic anymore, but taking control! :slight_smile:

Edit

I had a look with UI Element Inspector, and XQuartz is a no no even though its windows are wrapped in Cocoa, there isn’t anything there to support UI Scripting.

There is a version of this script for Mavericks further down the thread


-- MacScripter / Sizing an apps window, then bringing only that window to front
-- http://macscripter.net/viewtopic.php?id=39849
script genUI
	-- © McUsr 2012 and put in public domain, you may not post this as a stand-alone thing 
	-- anywhere else, nor put into a public repository. 
	-- Please refer to this link: http://macscripter.net/edit.php?id=157665
	on posFrontWinForAppAndDisplay(appname, x1, y1, W, H)
		-- Width is the actual width, Height the actual height for how apps treats those parameters differs slightly.
		-- you'll have to figure out the formulaes outside the handler.
		-- most often the formula for the width is width - x1, and  height respective is height - y1. 
		local success
		set success to my getFrontWinForAppAndDisplay(appname)
		if success then
			tell application id "sevs"
				tell application process appname
					try
						set position of its front window to {x1, y1}
						set size of its front window to {W, H}
					end try
				end tell
			end tell
		end if
	end posFrontWinForAppAndDisplay
	
	on getFrontWinForAppAndDisplay(appname)
		-- gets the front window to front for an app
		-- returns true if it manages, false otherwise
		local bid, success, failure, pass, curAppName, curBid
		set {success, failure, pass} to {false, false, 1}
		repeat while success = false
			tell application id "sevs"
				if pass = 1 then
					if UI elements enabled = false then set UI elements enabled to true
					set curAppName to name of first application process whose frontmost is true
					set curBid to bundle identifier of application process curAppName
					if {appname} is not in name of application processes then
						set failure to true # it wasn't running so we're exiting
					else
						if {appname} is not in name of (application processes whose visible is true) then
							set visible of application process appname to true
							set frontmost of application process curAppName to true
						end if
					end if
				end if
				
				if not failure then tell application process appname
					local wnCount
					set wnCount to count (its windows whose role is "AXWindow")
					if wnCount = 0 then
						# no regular windows open, there may be, however, in other spaces.
						if pass = 2 then set failure to true
						# there are no open windows in any space and we fail.
					else
						set bid to bundle identifier of it
						try
							local dummy
							set dummy to position of its front window
							# if this doesn't fail, then we do have a window in the current space
							set success to true
						end try
					end if
				end tell
				
			end tell
			
			if failure then
				do shell script "open -b \"" & curBid & "\""
				return false
			else if not success then
				do shell script "open -a \"" & appname & "\""
				# some apps open an empty window if there was none.
				set pass to pass + 1
			end if
		end repeat
		do shell script "open -b \"" & bid & "\""
		# no use in this if we have made the app visible!
		# then we activate the previous app, and the bring the window forward.
		return true
	end getFrontWinForAppAndDisplay
	
end script

-- Example calls
--  genUI's posFrontWinForAppAndDisplay("FreeMind", 0, 22, 800, 800)
-- genUI's getFrontWinForAppAndDisplay("TextEdit")


-- Xcode uses the "non-flipped" "cocoa model" of window addressing, where the left lower corner is the start point 
-- for x1, y1 You'll have to trial and error a little!
-- Terminal is even worse, haven't figured it out, but VLC, FreeMind, and such apps works!
-- When you pass the width parameter, be sure to add up for x1, and the same goes for height where you should 
-- add in y1.

New Stuff

This is the second handler for generic UI that is residing in the GenUI library.

It has the dedicated purpose of just bringing an app’s window to front. It is intended to be very good at that, as long as the app are running:

You can check the return value to see if the handler succeeded or not, before you start changing the window size and such. It leaves the previous current app current, if the previous app didn’t have any window open or such.

Purpose:

First and foremost to be enabled to make small automator services, which each is used for activating a specific app, by a specific hotkey. To make it easy to switch betweeen the apps you use the most. I use the keys cmd-opt 2 thru 0 and beyond, on that row, as the key combination is easy to type on a Macbook Pro keyboard.

Why not just use the 1 or 2 together with command-tab?

That may be a slow operation, if you have many windows open. And it requires more keypresses/chances to do wrong.

Usage:

A working Automator Service look like this:


set hfsScriptName to "Hfs Path:To:Where:You:Saved:GenUI.scpt"
set genUI to genUI of (load script (hfsScriptName as alias))

genUI's getFrontWinForAppAndDisplay("BBedit")

The Service should take no input from any app, you add an AppleScript Procedure and add the code above with your changes. When that is done, you enter the keyboard preferences: use the snippet below for quick access, and assign a keyboard shortcut to it, then try it!


script displayKeyboardPrefPane
	tell application "System Preferences"
		tell anchor 2 of pane "com.apple.preference.keyboard" to reveal
		activate
	end tell
end script
tell displayKeyboardPrefPane to run

What it does:

It bring a specified App’s first window to front, whether that window is hidden or minimized. If the App has no windows open, the App may create one. This pair of handlers are designed to just one thing each, and do them well, as robustly as possible.

Caveats:

  • The first one is that, if we are active in one space, and the App has windows open in another space, and those windows are hidden, then all the windows of that App is brought forward. This is just how it is, as we can’t run around in different spaces, register the current App, and test if the invisible app has windows open there… err we can, but it won’t look good.

  • The second caveat is that an App can be associated with a space, so that you will be teleported to that space, and a new window made there, if the app is running but has no open windows. But this you’ll figure out when it happens, if it happens and can deal with it, the obvious thing, is either to accept it as something you want, or disassociate the App with the space, (unassign it).

Enjoy! :slight_smile:

Edit

It doesn’t work with HelpView, so helpview you would have to switch from, one way or another.

Hello.
I post this on this thread, as it is related, and for Mavericks, what is new, is that there are no resizing here anymore, not for this app anyway, that brings the previous window of an app to front, and only the first window.

If you are to call this app from a script, or a script in an automator action, once you have gotten thru the hurdles of making it work, then you have to do so within an ignoring application responces block.

Here is an app that basically intends to bring the front window of the previous app to front. It does not consider what display this happens in, so it isn’t perfect at all times.

Save this as an applet, open the bundle by "Show package contents, and replace the info plist file that is inside the Contents folder with the contents that is below the script. The first time you run it, you have to accept the first dialog that comes when it runs if you want to let this applet control your machine, open the privacy settings, and check off for rc.app.


# copyright © 2013 McUsr
script recap
	property parent : AppleScript
	on run
		local curProcName, prevProcName
		tell application id "com.apple.systemevents"
			set frontProcesses to (every process whose visible is true and frontmost is true and role is "AXApplication")
			
			if (count frontProcesses) > 0 then
				set curProcName to name ¬
					of item 1 of frontProcesses
				
			else
				set curProcName to name ¬
					of item 1 of (every process whose visible is true and frontmost is true)
			end if
			
			tell application process curProcName to keystroke tab using command down
			try
				set {prevProcName, prevProcBundle} to {name, bundle identifier} ¬
					of item 1 of (every process whose visible is true and frontmost is true and role is "AXApplication")
			on error
				set {prevProcName, prevProcBundle} to {name, bundle identifier} ¬
					of item 1 of (every process whose visible is true and frontmost is true)
			end try
			tell application process prevProcName to keystroke tab using command down
			
		end tell
		try
			tell application curProcName to tell application id "sevs" to tell application process prevProcName
			end tell
		end try
		do shell script "open -b " & prevProcBundle
	end run
end script
run script recap

I just want to mention that you (or anybody else) should save the contents of info.plist as UTF-8 with linefeed as line endings, with TextWrangler or Similiar.

This replaces the script library in post #4 in this thread, for Mavericks, it doesn’t size or position anything anymore, as that is best done in a separate step/library.

Hello.

This is a library, that contains a handler that brings the front window of a named app to front under Mavericks, for instructions on how to create a libray see below.

Example usage: The script below will also work inside a “Run AppleScript” Action in Automator, so you can bind your versions of the example script to hot-keys in the Services tab of the Keyboard Preferences pane.

use AppleScript version "2.3"
use scripting additions
use awt : script "AppWindowToggler"

awt's toggleApp("FileMaker Pro")

Save the script below in the folder /Users/You/Library/Script Libraries/AppWindowToggler, make the folder /Users/You/Library/Script Libraries/ if you have to.


# copyright © 2013 McUsr
use AppleScript version "2.3"
use scripting additions

property parent : AppleScript
on toggleApp(appname)
	
	local curProcName, prevProcName
	
	tell application id "com.apple.systemevents"
		set frontProcesses to (every application process whose visible is true and frontmost is true and role is "AXApplication")
		
		if (count frontProcesses) > 0 then
			set curProcName to name ¬
				of item 1 of frontProcesses
			
		else
			set curProcName to name of (first application process whose visible is true and frontmost is true)
		end if
		
		tell application process curProcName
			keystroke tab using command down
		end tell
		
		try
			set {prevProcName, prevProcBundle} to {name, bundle identifier} ¬
				of item 1 of (every application process whose visible is true and frontmost is true and role is "AXApplication")
		on error
			set {prevProcName, prevProcBundle} to {name, bundle identifier} ¬
				of item 1 of (every application process whose visible is true and frontmost is true)
		end try
		
		tell application process prevProcName
			keystroke tab using command down
		end tell
		
	end tell
	
	if appname = curProcName then
		local wid
		try
			tell application id "sevs" to tell application process appname
				keystroke "h" using command down
			end tell
		end try
		do shell script "open -b " & prevProcBundle
	else if appname = prevProcName then
		try
			tell application id "sevs" to tell application process appname
				set visible of it to true
			end tell
		end try
		do shell script "open -b " & prevProcBundle
	else
		tell application id "sevs" to tell application process appname
			set visible of it to true
		end tell
		do shell script "open -a " & quoted form of appname
	end if
	
end toggleApp

Edit

A minor fix of the placement of the do shell script statement.
I made the library to work when the app isn’t one of the two frontmost apps! :slight_smile:

Hello.

The Applet in post #5 is only usable from Spotlight, which somewhat limits its usability.

The Script Library in post #6 removes those problems as it gives you the same functionality (in principle) from a script, but by the time you make it work with all your favorite apps, you have done a whole lot of acknowledging programs to control your machine in the preferences pane. That’s how it is nowadays! :slight_smile:

This caveat is because the Operating system sees the application process that is called by System Events to be the one that controls the machine, and not System Events.