Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Enumerating all windows

92 views
Skip to first unread message

Peter

unread,
Dec 13, 2006, 6:44:25 AM12/13/06
to
Hello.

I'm trying to enumerate all the windows on the desktop, but when I use:

WindowRef window = ::GetWindowList(); // or
::GetFrontWindowOfClass(kAllWindowClasses, true);
while(window != NULL)
{
WindowRef next = ::GetNextWindow(window); //or
...OfClass(window, kAllWindowClasses, true);

CopyWindowTitleAsCFString(window, &caption);
// print title

window = next;
}

I only get the windows in my application, not the other windows like
FireFox, Finder, Emacs, etc..

I am using Mac OS X 10.4.8 (Intel).

How can I enumerate all the windows, just like with the Win32 API
function EnumWindows()?

Thanks in advance,

Peter

David Phillip Oster

unread,
Dec 13, 2006, 9:35:33 AM12/13/06
to
In article <1166010265....@j72g2000cwa.googlegroups.com>,
"Peter" <oiv...@pvv.org> wrote:


You can enumerate all the processes, then use appleEvents to ask each
process to tell you about its windows. What are you really trying to do?

Michael Ash

unread,
Dec 13, 2006, 10:15:18 AM12/13/06
to

Use the Accessibiity API:

http://developer.apple.com/documentation/UserExperience/Accessibility-date.html

Of course it's probably not "just like" EnumWindows(), but there's a
reason they call it a completely different operating system.

--
Michael Ash
Rogue Amoeba Software

Reinder Verlinde

unread,
Dec 13, 2006, 2:02:59 PM12/13/06
to
In article <11660229...@nfs-db1.segnet.com>,
Michael Ash <mi...@mikeash.com> wrote:

> Peter <oiv...@pvv.org> wrote:
> > Hello.
> >
> > I'm trying to enumerate all the windows on the desktop, but when I use:
> >
> > WindowRef window = ::GetWindowList(); // or
> > ::GetFrontWindowOfClass(kAllWindowClasses, true);
> > while(window != NULL)
> > {
> > WindowRef next = ::GetNextWindow(window); //or
> > ...OfClass(window, kAllWindowClasses, true);
> >

> > window = next;
> > }
> >
> > I only get the windows in my application,
> >

> > How can I enumerate all the windows, just like with the Win32 API
> > function EnumWindows()?
>
> Use the Accessibiity API:
>
> <http://developer.apple.com/documentation/UserExperience/Accessibility-date.html>
>

Warning: because of the security implications of the accessibility API
(for example, a background-only application could read a paswword from a
text field in another application), Apple included a master switch to
enable this functionality. By default, it is off. So, do not count on
getting to work this without user intervention on all systems.

Reinder

Peter

unread,
Dec 13, 2006, 2:22:36 PM12/13/06
to
> > How can I enumerate all the windows, just like with the Win32 API
> > function EnumWindows()?
> >
> You can enumerate all the processes, then use appleEvents to ask each
> process to tell you about its windows. What are you really trying to do?

I am trying to extract the window title of FireFox/Safari/Opera or
other browsers.

Can you give me some more information about the technique you propose?
Which events should I use?

Thanks,

Peter

Peter

unread,
Dec 13, 2006, 2:26:16 PM12/13/06
to
> > Use the Accessibiity API:
> >
> > <http://developer.apple.com/documentation/UserExperience/Accessibility-date.html>
> >
> Warning: because of the security implications of the accessibility API
> (for example, a background-only application could read a paswword from a
> text field in another application), Apple included a master switch to
> enable this functionality. By default, it is off. So, do not count on
> getting to work this without user intervention on all systems.

Is it possible to change this master switch programatically, either
from an application or an installer?

Thanks,

Peter

Michael Ash

unread,
Dec 13, 2006, 2:55:28 PM12/13/06
to

No, that would make the master switch kind of pointless, wouldn't it?

From the actual problem you're trying to solve, you want to use
AppleScript. A classic example of why you should just ask about what
you're trying to do instead of asking "equivalent" questions.

Peter

unread,
Dec 13, 2006, 8:04:40 PM12/13/06
to

Michael Ash wrote:
> A classic example of why you should just ask about what
> you're trying to do instead of asking "equivalent" questions.

I did just that. Stop lecturing. My original post had an example code
snippet which tried to enumerate all the windows and extract the window
title, which is exactly what I want to do.

Michael Ash

unread,
Dec 13, 2006, 9:43:45 PM12/13/06
to

I'm sorry, I didn't realize we were supposed to divine your ultimate
intent from 10 lines of broken test code. I guess I just have a big thick
head that really wants the goal to be in the actual question.

Peter

unread,
Dec 13, 2006, 10:04:21 PM12/13/06
to
Ignoring Michael Ash..... What a douche.


After some digging around, I came up with this:

typedef int CGSConnection;
typedef int CGSWindow;
typedef int CGSValue;

extern "C"
{
CG_EXTERN CGSConnection _CGSDefaultConnection();
CG_EXTERN CGError CGSGetConnectionIDForPSN(const CGSConnection
connection, ProcessSerialNumber * psn, CGSConnection *
targetConnection);
CG_EXTERN CGError CGSGetOnScreenWindowCount(const CGSConnection
connection, CGSConnection targetConnection, int * count);
CG_EXTERN CGError CGSGetOnScreenWindowList(const CGSConnection
connection, CGSConnection targetConnection, int count, int * list, int
* outCount);
CG_EXTERN CGError CGSGetWindowProperty(const CGSConnection
connection, CGSWindow window, CGSValue key, CGSValue * outValue);

extern CGSValue CGSCreateCStringNoCopy(const char * str);
extern char *CGSCStringValue(CGSValue string);
}


ProcessSerialNumber psn = {0, kNoProcess};
for(int i=0; i<2000; i++) // Stop at 2000 just in case something
loops
{
OSErr err = GetNextProcess(&psn);
if(err != noErr)
break;

CGSConnection connection = _CGSDefaultConnection();

CGSConnection procConnection;
err = CGSGetConnectionIDForPSN(connection, &psn,
&procConnection);
if(err == noErr)
{
int windowCount = 0;
err = CGSGetOnScreenWindowCount(connection, procConnection,
&windowCount);
if(err == noErr)
{
const int MAX_WINDOWS = 200;
int windowList[MAX_WINDOWS + 1];
windowCount = min(windowCount, MAX_WINDOWS);

err = CGSGetOnScreenWindowList(connection,
procConnection, windowCount, windowList, &windowCount);
if(err == noErr)
{
for(int wI = 0; wI<windowCount; wI++)
{
CGSWindow window = windowList[wI];
CGSValue windowTitle;

err = CGSGetWindowProperty(connection,
window,

CGSCreateCStringNoCopy("kCGSWindowTitle"),
&windowTitle);

if(err == noErr)
{
printf("Win Title: %s\n",
CGSCStringValue(windowTitle));
}
}
}
}
}
}


I know this uses private functions from CoreGraphics, but this seems to
be used by many people, and the functions are still around and working
in 10.4.8 so I might go for this (even if it is unsupported and might
change at any time and break my code).

What I really am worried about is object leakage. Is there some kind of
cleanup function for the connections I create in this loop?

Thanks to David Phillip Oster for pointing me to the "enum processes"
direction. That was actually helpful.

I have no experience using AppleScript. Is there some specific script
functions or events I can use to do the same thing without using the
private CoreGraphics functions? Any keyword I can use to lookup in the
xcode documentation or search for using Google would be grestly
appreciated. Just "AppleScript" does not narrow it down much for me.


Thanks,

Peter

Sherm Pendley

unread,
Dec 13, 2006, 10:28:48 PM12/13/06
to
"Peter" <oiv...@pvv.org> writes:

> Ignoring Michael Ash..... What a douche.

Ignoring and insulting one of the most helpful and informative members of
this community is a good way to ensure that you'll get *no* help from the
rest of us.

Best of luck with going it on your own.

sherm--

--
Web Hosting by West Virginians, for West Virginians: http://wv-www.net
Cocoa programming in Perl: http://camelbones.sourceforge.net

David Phillip Oster

unread,
Dec 13, 2006, 10:31:58 PM12/13/06
to
In article <1166037756.7...@l12g2000cwl.googlegroups.com>,
"Peter" <oiv...@pvv.org> wrote:

Paste the following into Script Editor, then hit the "Run" button:

tell application "Safari"
name of windows
end tell

Under the hood, it is using the Process Manager to loop over the
processes, with GetNextProcess(), and for each process calling
GetProcessInfo() until it finds the process id of the process named
"Safari".

Next, it AECreate()s an appleEvent in the standard suite with a GetData
verb, and puts as the direct object an object descriptor asking for the
name property of every window of the null descriptor (the last clause
reprresents the application itself.)

it uses AESend() to send the appleEvent, and receives a AERecord where
the resultKey '----' contains an aeDescriptor that is an aeList of
aeDesriptors of 'utxt' (i.e, unicode strings.)

If you are not using Carbon, Cocoa wraps this all nicely in
NSAppleScript and related classes, or you can use the OSA calls to
compile and execute an Script Editor AppleScript string.

If you do a search on groups.google.com, you'll see I've written about
this topic before, and posted sample code.

Michael Ash

unread,
Dec 13, 2006, 10:36:03 PM12/13/06
to
Peter <oiv...@pvv.org> wrote:
> Ignoring Michael Ash..... What a douche.

I love the sound of plonk in the morning.

> After some digging around, I came up with this:
>
> typedef int CGSConnection;
> typedef int CGSWindow;
> typedef int CGSValue;
>
> extern "C"
> {
> CG_EXTERN CGSConnection _CGSDefaultConnection();

[snip]

Ignoring everybody's advice and going off to use a bunch of undocumented,
likely-to-change, private functions is a *great* way to write your app!

Peter

unread,
Dec 13, 2006, 10:37:53 PM12/13/06
to

David Phillip Oster wrote:
> Paste the following into Script Editor, then hit the "Run" button:
> ...
> ...

Thanks :-)

Peter

Peter

unread,
Dec 13, 2006, 10:50:50 PM12/13/06
to
Sherm Pendley skrev:

> "Peter" <oiv...@pvv.org> writes:
>
> Ignoring and insulting one of the most helpful and informative members of
> this community is a good way to ensure that you'll get *no* help from the
> rest of us.
>
> Best of luck with going it on your own.

. He wasn't helping.
- He was rude to me first. (My mom confirms this.)
- I got the answers I needed.
- You are equally unhelpful, adding to the flame war.

Gregory Weston

unread,
Dec 14, 2006, 8:23:12 AM12/14/06
to
In article <1166068250.8...@l12g2000cwl.googlegroups.com>,
"Peter" <oiv...@pvv.org> wrote:

> Sherm Pendley skrev:
> > "Peter" <oiv...@pvv.org> writes:
> >
> > Ignoring and insulting one of the most helpful and informative members of
> > this community is a good way to ensure that you'll get *no* help from the
> > rest of us.
> >
> > Best of luck with going it on your own.
>
> . He wasn't helping.

He tried. His very first post suggested an excellent and supported means
of achieving the result you asked for.

> - He was rude to me first. (My mom confirms this.)

Moms can be wrong. The first post in this thread that evinced hostility
of any sort was yours:
<1166058280.1...@79g2000cws.googlegroups.com>

So was the only one that actually entered the territory of outright
rudeness:
<1166065461.2...@80g2000cwy.googlegroups.com>

> - I got the answers I needed.

You got multiple answers and then apparently chose to go with none of
them, instead relying on undocumented and unsupported techniques on a
platform with which you're not familiar.

> - You are equally unhelpful, adding to the flame war.

You didn't think Michael was helpful when he offered a reliable answer
less than 4 hours after you posted your initial question and now you
think Sherm is being unhelpful when he warns you that attitude counts? I
get the feeling your mom has spent too much time protecting you from the
consequences of your actions.

--
The best intentions in the world don't make a flawed argument magically valid.

0 new messages