Activate the frontmost window in the previous app.

Hello!

It is possible, at least manually, to get the frontmost window in the previous app to be active, and put nicely in front of the windows, of the now previous app.

Example. I sit in script debugger. I hit F9 for expose, and I choose a safari window, that window only of all the windows of safari, will now be put in front of every window of Script Debugger.

I have tried some stuff with System Events to simulate this behaviour, but it turns out to be not that easy.

I figure the easiest thing is to really get that window manually. But I am lazy and would love to do it programmatically, at least now, that my curiosity is awoken.

Ahhh! The objective with this is to take windows from the two front most applications, and put the nicely side by side. And I want to do that in one script, because that is how lazy I am. And the script shouldn’t mess a whole lot with the screen, but be as “silent” as possible.

A compromise here, is to have routines that skews the frontmost applications windows to the left, part of the screen, and all the previous frontmost applications windows to the right.

But, I really want the real thing!

So if any of you have any ideas to share for doing so, or even better, working code! :slight_smile:

Thanks

Hello!

It turned out to be far easier, as I read this Blog.

open -b “bundleidentifier” takes care of it. Try the script below! :slight_smile:

It is really nice in tandem with Quicksilver

Edit It turned out that Script Debugger didn’t play well with name so I have changed the script to use bundle identifier over name


-- Elevate http://macscripter.net/viewtopic.php?pid=154619#p154619
-- © McUsr 2012  and put into public domain! you may not post this anywhere else, what so ever!

on run
	script o
		property a : missing value
		property b : missing value
	end script
	local a, b, c, d,e, i
	tell application id "com.apple.systemevents"
		set {o's a, o's b} to {bundle identifier, name} of (every process whose visible is true)
		
		repeat with i from 1 to count o's b
			
			if (count every window of (application process (item i of o's b))) = 0 then
				set {item i of o's a, item i of o's b} to {missing value, missing value}
			else if (frontmost of (application process (item i of o's b))) = true then
				set e to item i of o's b
				set {item i of o's a, item i of o's b} to {missing value, missing value}
			end if
		end repeat
	end tell
	set {o's a, o's b} to {o's a's text, o's b's text}
	tell application id "com.apple.systemuiserver"
		activate
		set c to (choose from list o's b default items item 1 of o's b with title "Elevate a window")
	end tell
	
	if c = false then
		tell application e to activate
		error number -128
	end if
	set d to indexOfItem(c, o's b)
	do shell script "open -b " & item d of o's a
	
end run

on indexOfItem(theItem, itemsList)
	-- credit to Emmanuel Levy 
	local rs
	
	set text item delimiters to return
	set itemsList to return & itemsList & return
	set text item delimiters to {""}
	try
		set rs to -1 + (count (paragraphs of (text 1 thru (offset of (return & theItem & return) in itemsList) of itemsList)))
	on error
		return 0
	end try
	rs
end indexOfItem


I have updated it, with some optimization, and I am done with it!

It is polished! :slight_smile:

Hello!

:slight_smile: While I am at it, here is Pike. It lets you choose any window from any app! It should work fairly well with applications that supports scripting terminology. That leaves out a jailbroken Preview!

It doesn’t support minimized, miniaturized, or collapsed windows!

Edit It doesn’t work very well with BBEdit, I will come back to that fact!


-- Pike http://macscripter.net/viewtopic.php?pid=154619#p154619
-- © McUsr 2012  and put into public domain! you may not post this anywhere else, what so ever!
on run
	script o
		property a : missing value
		property b : missing value
		property f : missing value
	end script
	local c, d, e
	tell application id "com.apple.systemevents"
		set {o's a, o's b} to {bundle identifier, name} of (every process whose visible is true)
		
		repeat with i from 1 to count o's b
			
			if (count every window of (application process (item i of o's b))) = 0 then
				set {item i of o's a, item i of o's b} to {missing value, missing value}
			else if (frontmost of (application process (item i of o's b))) = true then
				set e to item i of o's b
			end if
		end repeat
	end tell
	set {o's a, o's b} to {o's a's text, o's b's text}
	tell application id "com.apple.systemuiserver"
		activate
		set c to (choose from list o's b default items item 1 of o's b with title "App that has the  window")
	end tell
	
	if c = false then
		tell application e to activate
		error number -128
	end if
	set d to indexOfItem(c, o's b)
	set c to c as text
	tell application id "com.apple.systemevents"
		set o's f to name of (every window of application process c)
	end tell
	
	repeat with i from 1 to count o's f
		if item i of o's f = missing value then
			if c = "Finder" then tell application "Finder" to set item i of o's f to displayed name of target of Finder window i
		else if item i of o's f = "" then
			set item i of o's f to missing value
		end if
	end repeat
	set o's f to o's f's text
	local g
	tell application id "com.apple.systemuiserver"
		activate
		set g to (choose from list o's f default items item 1 of o's f with title "Choose window")
	end tell
	
	if c = false then
		tell application e to activate
		error number -128
	end if
	local h
	set h to indexOfItem(g, o's f)
	local l
	tell application c
		activate
		set l to its window (g as text)
		set visible of l to false
		set visible of l to true
	end tell
	
	local m
	tell application e
		activate
		set m to count its windows
	end tell
	
	do shell script "open -b " & item d of o's a
	
end run

on indexOfItem(theItem, itemsList)
	-- credit to Emmanuel Levy 
	local rs
	
	set text item delimiters to return
	set itemsList to return & itemsList & return
	set text item delimiters to {""}
	try
		set rs to -1 + (count (paragraphs of (text 1 thru (offset of (return & theItem & return) in itemsList) of itemsList)))
	on error
		return 0
	end try
	rs
end indexOfItem

Hi!

If the two scripts above: Elevate and Pike, shouldn’t work for some reason with a scriptable app you fancy.

Don’t hesitate, tell me about it, and I’ll see what I can do about it! :slight_smile:

I ponder taking it a step further, giving choices about tabs, and contents of drawers!

If anybody knows what I have to do to make it work in BBEdit; feel free.

Thanks!

Oh well, I have changed login name since I made it originally: Here is a revised version of Pike from post #5

This script relies on auto-swooshing of windows by Spaces/Expose; that is, when you select a window in another space, that space is activated/you are taken to that space (pick your view).

You activate auot-swooshing by entering this from the command line:

-- Pike http://macscripter.net/viewtopic.php?pid=154619#p154619
-- © McUsr and put into public domain you may not post this anywhere else, what so ever!
-- Added a try block, since some applications doesn't allow you to set the visible property
-- of a window.
-- 2013/07/08 
-- When saved as an app, and the LSUIElement is not set (Application is an Agent): then 
-- The script will err, since there is no frontmost proces. I have "fixed this" by setting "me"
-- as the frontmost process in those cases.


-- Some windows of some apps doesn't even have a visible property.  
-- I have also forked out a script object for practical purposes, in the post above.

-- I have removed one more bug, the issue was when there were just one window in this
--  space, and windows in other spaces, and I tried to hide the window, and make it visible again,
--  then I would remain in the other space.


-- Ok, so I removed the choose dialog for the case where the app has just one window totally in every space.

-- There are probably still some glitches here, when an app isn't scriptable and so on, but this is as good as 
-- it gets from my side, to pick a window among those you have in the current space, or select from all spaces
--  if you have no more than one window. If you have none, then you command - tab to the app. The script is in
-- post #7 together with a skeleton for an app, so you can use it from various places.

-- Invisible windows, that should have stayed invisible started to turn up as a result of former fixes. It is updated in post #7.

-- Now it moves you into the space where a window resides, if the window you chose didn't reside in the current space, 
-- (if you had just one window in this space, you'll get the opportunity to select windows from other spaces, if the app has any). 
-- It is all in post #7.

-- Factored out a subroutine, and tested it thoroughly, with document based and non documentbased apps. It should work as intended 
-- for applications that are scriptable.

-- One last bug is fixed. The problem was not getting the window to front, when the window is residing in another space.

--   I had to differentiate between cases where there were just one window in another space, and more than one.

-- Perfect, as far as it goes. 

-- Apart from when there were multiple windows in the current space.  That is fixed now.

# Totally fixed, the right version too..

# fixed bug, when an app that we want to display windows for are somehow busy.

# implemented a workaround for Smile. Thanks to kel!

property tlvl : me
property scripttitle : "Pike"
property parent : AppleScript
property showOthersWhenMoreThanOneInCurrent : true
script windowlib
	
	property curAppName : missing value
	property curAppBid : missing value
	property curWindow : missing value
	to setCallingApp()
		set curWindow to missing value
		tell application id "com.apple.systemevents"
			
			set {curAppName, curAppBid} to {name, bundle identifier} of (first process whose visible is true and frontmost is true)
			if (count every window of application process curAppName) > 0 then
				try
					set curWindow to name of window 1 of application process curAppName
					if curWindow = "" then
						set curWindow to missing value
					end if
				end try
			end if
		end tell
	end setCallingApp
	
	
	to elevateWindow for windowname by appname
		script o
			property l : {}
			property m : {}
		end script
		set theWins to missing value
		tell application id "com.apple.systemevents"
			set itsBid to bundle identifier of process appname
			set winCount to count (name of every window of application process appname)
			set theWins to name of windows of process appname
		end tell
		-- we need to know if one of our windows is the first in current space!
		set firstWinInThisSpace to firstWindowInCurrentSpace()
		log firstWinInThisSpace
		-- weird construct if the first window in current space is among the windows in 
		-- our list, then we know for sure that we are active, AND has the front window here
		-- (Important because of Expose's "auto-swoosh" setting that we rely upon).
		
		set inThisSpace to windowname is in theWins
		local winpos
		if inThisSpace then
			
			set winpos to IndexOfItemNoCase(windowname, theWins)
			if winCount > 1 then
				selectWindow for windowname by appname from "Current Space"
				local m
				tell application curAppName
					try
						set m to count every window
					end try
				end tell
				do shell script "open -b " & itsBid
			else # no bother, just one window, maybe it's active..
				if firstWinInThisSpace is not in theWins then
					tell application appname to activate
				end if
			end if
		else
			
			if firstWinInThisSpace is in theWins then
				-- we'll deal with this, by activating another app.
				set processToActivate to missing value
				tell application id "com.apple.systemevents"
					set processToActivate to item 2 of (name of every process whose visible is true)
					if processToActivate is not missing value then
						set frontmost of process processToActivate to true
						# else .. never mind...
					end if
				end tell
			end if
			
			
			-- We'll also have to figure out if it is first win in another space
			tell application appname
				set fullWnList to name of windows
			end tell
			
			set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, theWins}
			set o's l to text items of (fullWnList as text)
			set AppleScript's text item delimiters to tids
			set winCount to length of o's l
			
			set i to 1
			repeat winCount times
				if item i of o's l = "" then
					set item i of o's l to missing value
				end if
				set i to i + 1
			end repeat
			set o's l to o's l's text
			set winpos to IndexOfItemNoCase(windowname, o's l)
			# selectWindow for windowname by appname from "Current Space"
			selectWindow for windowname by appname from "Other Space"
			
		end if
		
	end elevateWindow
	
	to selectWindow for aName by anApp from aSpace
		tell application anApp
			tell its window aName
				if aSpace is "Other Space" then
					activate
				end if
				try
					set index of it to 1
				end try
				try
					set visible of it to true
					if anApp is not "Smile" then
						set visible of it to false
						set visible of it to true
					end if
				end try
				
			end tell
		end tell
	end selectWindow
	
	on firstWindowInCurrentSpace()
		local winInCurSpace
		tell application id "com.apple.systemevents"
			set winInCurSpace to (name of every window of (every process whose visible is true and frontmost is true))
			local i
			set i to 1
			repeat (count winInCurSpace) times
				if item i of winInCurSpace is not {} then
					set winInCurSpace to text of item i of winInCurSpace
					exit repeat
				end if
				set i to i + 1
			end repeat
		end tell
		
		return winInCurSpace
	end firstWindowInCurrentSpace
	
	on IndexOfItemNoCase(theItem, theList) -- credits Emmanuel Levy
		set text item delimiters to return
		set theList to return & theList & return
		set text item delimiters to {""}
		try
			-1 + (count (paragraphs of (text 1 thru (offset of (return & theItem & return) in theList) of theList)))
		on error
			0
		end try
	end IndexOfItemNoCase
	
	
end script

on run
	script o
		property a : missing value
		property b : missing value
		property f : missing value
	end script
	local fromApp, d
	# we need to set the calling app...
	setCallingApp() of tlvl's windowlib
	# we'll find every window in the current space.
	tell application id "com.apple.systemevents"
		set o's a to name of (every process whose visible is true)
		
		repeat with i from 1 to count o's a
			# we sift out the crud
			if (count every window of (application process (item i of o's a))) = 0 then
				set item i of o's a to missing value
			end if
		end repeat
	end tell
	set o's a to o's a's text
	# time to ask for which app we want to pick a window from...
	tell application id "com.apple.systemuiserver"
		activate
		set fromApp to (choose from list o's a default items item 1 of o's a with title my scripttitle & ": App that has the Window:")
	end tell
	
	if fromApp = false then error number -128
	# So we find every window of the app in current space.
	set fromApp to fromApp as text
	tell application id "com.apple.systemevents"
		set bid to bundle identifier of application process fromApp
		set bn to (name of every process whose bundle identifier is bid) as text
		set o's f to name of (every window of application process bn)
	end tell
	
	repeat with i from 1 to count o's f
		if item i of o's f = missing value then
			if fromApp = "Finder" then tell application "Finder" to set item i of o's f to displayed name of target of Finder window i
		else if item i of o's f = "" then
			set item i of o's f to missing value
		end if
	end repeat
	set o's f to o's f's text
	local g
	
	if (count o's f) > 1 and not showOthersWhenMoreThanOneInCurrent then
		
		tell application id "com.apple.systemuiserver"
			activate
			set g to (choose from list o's f default items item 1 of o's f with title my scripttitle & ": Choose Window:")
		end tell
		
		if g = false then
			if (tlvl's windowlib's curWindow) = missing value then
				tell application id (tlvl's windowlib's curAppBid) to activate
			else
				elevateWindow of (tlvl's windowlib) for (tlvl's windowlib's curWindow) by (tlvl's windowlib's curAppName)
			end if
			error number -128
		end if
	else
		try
			with timeout of 2 seconds
				set o's f to name of every window of application fromApp whose visible = true
			end timeout
		on error e number n
			if n = -1712 then # timeout
				tell application id "com.apple.systemuiserver"
					activate
					try
						display dialog (fromApp & " is busy doing something else at the moment.
	Please try again later") buttons {"Ok"} with icon 2 with title my scripttitle default button 1
					end try
				end tell
				if (tlvl's windowlib's curWindow) = missing value then
					tell application id (tlvl's windowlib's curAppBid) to activate
				else
					elevateWindow of (tlvl's windowlib) for (tlvl's windowlib's curWindow) by (tlvl's windowlib's curAppName)
				end if
				error number -128
			else
				try
					set o's f to name of first window of application fromApp
				on error
					tell application id "com.apple.systemevents"
						set o's f to name of (every window of application process fromApp)
					end tell
				end try
			end if
		end try
		if (count o's f) > 1 then
			repeat with i from 1 to count o's f
				if item i of o's f = missing value then
					if fromApp = "Finder" then tell application "Finder" to set item i of o's f to displayed name of target of Finder window i
				else if item i of o's f = "" then
					set item i of o's f to missing value
				end if
			end repeat
			set o's f to o's f's text
			if (count o's f) > 1 then
				tell application id "com.apple.systemuiserver"
					activate
					set g to (choose from list o's f default items item 1 of o's f with title my scripttitle & ": Choose Window:")
				end tell
				
				if g = false then
					if (tlvl's windowlib's curWindow) = missing value then
						tell application id (tlvl's windowlib's curAppBid) to activate
					else
						elevateWindow of (tlvl's windowlib) for (tlvl's windowlib's curWindow) by (tlvl's windowlib's curAppName)
					end if
					error number -128
				end if
			end if
		else
			set g to missing value
			try
				set g to item 1 of o's f
			end try
		end if
	end if
	if g is not missing value then
		elevateWindow of (tlvl's windowlib) for (g as text) by fromApp
	else
		# it wasn't a document based app, but something with another kind of window.
		tell application fromApp to activate
	end if
	
	error number -128
end run

Then you just activate spotlight, type pike, and off you go. (You should set LSUIElement to true.)

But before you do that, be sure to comment out the quit, and drag it into the Dock while it is running. Then you’ll kill it from activity monitor, and then you set LSUIElement to true with Xcode or Property list editor. :slight_smile:

Hello.

Some windows of some apps doesn’t even have a visible property. :slight_smile: I have also forked out a script object for practical purposes, in the post above.

Hello.

I have removed one more bug, the issue was when there were just one window in this space, and windows in other spaces, and I tried to hide the window, and make it visible again, then I would remain in the other space.

That is fixed now, by a little test on the window count in the current space.

Ok, so I removed the choose dialog for the case where the app has just one window totally in every space.

There are probably still some glitches here, when an app isn’t scriptable and so on, but this is as good as it gets from my side, to pick a window among those you have in the current space, or select from all spaces if you have no more than one window. If you have none, then you command - tab to the app. The script is in post #7 together with a skeleton for an app, so you can use it from various places.

Invisible windows, that should have stayed invisible started to turn up as a result of former fixes. It is updated in post #7.

Now it moves you into the space where a window resides, if the window you chose didn’t reside in the current space, (if you had just one window in this space, you’ll get the opportunity to select windows from other spaces, if the app has any). It is all in post #7.

Factored out a subroutine, and tested it thoroughly, with document based and non documentbased apps. It should work as intended for applications that are scriptable.

One last bug is fixed. The problem was not getting the window to front, when the window is residing in another space.

:slight_smile: I had to differentiate between cases where there were just one window in another space, and more than one.

Perfect, as far as it goes. :slight_smile:

Apart from when there were multiple windows in the current space. :confused: That is fixed now.

It is totally finished. I really need that script object, that’s why I have bothered all of this, if you wonder. :slight_smile:
So the finished thing resides in post # 7.

It is a script called Pike, that lets you pick a window from any app that is active in current space, if there is just one window active in current space, then you are allowed to select windows in other spaces.

The idea is that if you want something “new”, from an app that isn’t there then you’ll switch or fire up that app, and arrange things as you want.

Fixed one bug relating to activating a window in another space, when there is just one window. There are still problems when there are several windows in another space, and you want to get a window that is not the front in that space (index = 1 ), I can’t bypass bringing all of the windows of that app in the front of the other windows in that space then. Maybe I’ll fix this one day, but I fear it will be a rather slow solution in AppleScript.

One thing I have forgotten to mention is that the whole thing relies on auto-swooshing of windows, that is, when you select a window in another space, that space is activated/you are taken to that space (pick your view).

You activate auot-swooshing by entering this from the command line:

.

The whole setup also works best with apps, that aren’t dedicated to any space, nor all spaces.

And the right version is posted in post #7 above.