From the 10.3 prerelease thread, it appears that Panther's finder still doesn't update its windows in response to filesystem activity.That is, if you created/delete files using the terminal, or any other app that doesn't keep the finder updated, those changes don't show up until you click on the finder window in question.

Fortunately, Panther offers kqueue/kevent notifiers, so that apps can automatically be notified about filesystem changes. Unfortunately, Apple doesn't seem to have integrated this in with the finder yet.

Fortunately again, our own calumr had the good idea to think of making a 3rd party daemon that would register for kqueue notifications on all of the windows the finder has open (and possibly all the folders with folder action scripts), and then notify the finder about the changes with Cocoa's -[NSWorkspace noteFileSystemChanged:] method.

So, this is looking like a nice easy project to work on that would be pretty useful.I'd start today, but there are a few little catches that I was wondering if the Ach could help with.

(1) Finding out what windows the finder has openTo work right, this would need a list of all of the windows the finder has open and all of the folders in list view with the disclosure triangles down.I know you can get information about the former with AppleScript or AppleEvents, but how about the latter?

(2) Avoiding pollingIt would be nice for the daemon to register with the finder, the WM, or the AppleEvents service to be notified about window openings and closings. This way, it wouldn't have to constantly poll the finder to find this information out. (I'd like to avoid polling -- sort of defeats the purpose of using kqueue!)Is this possible?

(3) Finding out (without polling?) what folders have folder actions attachedI'm at a loss here. Not enough experience.

tell application "Finder"
set listViews to every Finder window whose current view is list view
set theWindow to first item of listViews
tell target of theWindow
set expandedItems to every folder whose expanded is yes -- <- the goodness
end tell
end tell

Does anyone know if the expanded applescript property is implemented in Panther?

FixxxerThat "update" command looks pretty useful... do you -- or does anyone -- have any more information about it? I couldn't find anything in the Apple docs, and the signal/noise ratio when searching for "Applescript command update" on google is pretty low, as you'd expect.

Aah, thanks for the info on "update." Here I was thinking it was some sort of general Applescript mechanism to avoid polling -- some way of receiving notification that an application's state has changed. (You know, "on update do ...")

It turns out it's a command in the finder dictionary -- no wonder it didn't show up in the Applescript language reference.

Well, fortunately we've got "telling the finder to update" and "getting the windows/etc. that are open" covered.

So, here are the questions:

(1) Is there any way to find this information out without polling the finder?

That is, can you (with Applescript or otherwise) set up an interrupt-driven mechanism for finding out about open windows, etc.

(2) If not, is polling for open windows still OK?

The nice thing about kqueue is that the kernel tells you when a file/folder has changed. Otherwise your thread is just asleep, consuming NO resources (almost).

But if the app has to constantly poll the finder to find out what windows are open, it's all of a sudden using resources (potentially lots if answering Apple Events is resource-intensive) all of the time, even when nothing's happened.

So -- is there any way to avoid polling? If not, is this project still worthwhile?

sheytan:Could you not trigger an AppleEvent every time a Finder window is opened by the user?How would you go about that? We'd also need to track changes in the focus of the window(s).

zpincus:So -- is there any way to avoid polling?Not that I'm aware of. The Finder doesn't seem to post any DistributedNotifications about what the windows are doing, and I don't think there's even an AppleScript equivalent to notifications. It has "handlers," and maybe you could somehow "handle" calls to the Finder's open window command (I think others call your handlers), but I doubt that's even what the Finder calls to open a window'¦

This is interesting, but I don't see how it's really helpful; a DistributedNotification called "com.apple.carbon.core.DirectoryNotification" is posted by the Finder whenever you use it to modify a directory. Oddly, when you move something to the trash, it posts two notifications (one for the source directory, and one for the Trash), but emptying the Trash doesn't post anything.

If not, is this project still worthwhile?You know, I was thinking about it, and this could probably be solved directly in the Finder code in about 10 minutes (unless I'm missing something - I only know as much about it as is in these two threads, but it seems to me that they just have to register an appropriate kqueue when they "look" at a folder, right? It's probably like two or three lines of code, isn't it?), and more effectively on top of it.

Does Apple have a Volunteer Finder Department*?

*Since that's not likely to be an option, I'm thinking the best method may be what calmur originally suggested - somehow overriding the functions that (we suspect) the Finder is using to monitor a particular node. My question would be, does anyone here have the skills to pull that off without using APE? I've heard bad things (and good things - no flames!) about it, and I would much rather have a stand-alone daemon. In any case, I don't think polling would be a very good way to go. AppleScript is an easy and effective form of inter-app communication for the average user, and often, it's the only method, but it doesn't seem to be "cheap" IME.

I guess at this point it's safe to say it won't make to GM. Perhaps later on, perhaps not.

I was wondering, since with QE all windows are textures, would it not be possible to know that the number of open windows has changed by looking at some QE stats for the Finder? That would eliminate the need for polling constantly, at least on QE machines. Is this even possible?

I've had a stab at implementing this, and the results are encouraging.

I have a little tool that takes argument (a path to a file or directory) and watches it using kqueue and kevent (link to the source is below). When a file is deleted, renamed, written to or chmod'd -noteFileSystemChanged: is called with the appropriate path. In the case of directories, modifying the contents counts as being written to.

And the good news? It works. Touch, mv, cp, rm all update the Finder immediately. I have only tested it with files in my home directory - not sure what it'll do for network volumes etc., but have a look if you want:

Hey calumr, that was the exact program I was writing Thanks for saving me the work (I was just going through the kqueue docs). I plan on using it to watch the desktop folder (sans printf()s and maybe daemonized) and probably also as an example in my Panther review.

quote:Originally posted by serversurfer:But we still have to tie it to the Finder views somehow, right? That's the hard part.

Edit: Good work, btw, and an even better idea.

Yeah - I've been playing around with APE on 10.3 but I can't seem to get it to work.

When I do get APE working, I have 2 choices. Override the NodeSync() function in the Finder, whose signature I don't know (I need to know what arguments it takes so that I can write a replacement), or override the PowerPlant (C++) LView::Activate() method. There can be other ways to do this, but they are basically variations on those 2. Hmmmm...

quote:Originally posted by calumr:Yeah - I've been playing around with APE on 10.3 but I can't seem to get it to work.

Do we know how Ape does its "override magic"? Like I said, if we could override the functions ourselves, then everyone could use it, even if they don't want to install APE.

quote:When I do get APE working, I have 2 choices. Override the NodeSync() function in the Finder, whose signature I don't know (I need to know what arguments it takes so that I can write a replacement), or override the PowerPlant (C++) LView::Activate() method. There can be other ways to do this, but they are basically variations on those 2. Hmmmm...

Again, I'm talking out of my ass here, but weren't those two "register" functions you found more likely candidates? Just going by their names, it sounds to me like NodeRegisterChildChangedNotification says "we want to know if this guy's children change" and NodeScan would be what's called if they do. But maybe not every time. Or maybe it's also called at other times. It seems to me like the ChildChangedNotification is more the functional equivalent of what kqueue does. Am I missing something?

quote:Originally posted by serversurfer:Do we know how Ape does its "override magic"? Like I said, if we could override the functions ourselves, then everyone could use it, even if they don't want to install APE.

I don't have a clue how APE does it, but I know that it's very difficult. If the Finder was a Cocoa app, I could do it in about 10 minutes by using the obj-c runtime to sniff out the methods I need to replace.

quote:Again, I'm talking out of my ass here, but weren't those two "register" functions you found more likely candidates? Just going by their names, it sounds to me like NodeRegisterChildChangedNotification says "we want to know if this guy's children change" and NodeScan would be what's called if they do. But maybe not every time. Or maybe it's also called at other times. It seems to me like the ChildChangedNotification is more the functional equivalent of what kqueue does. Am I missing something?

I realised that the 2 "register" functions probably had a complex argument list, which would be difficult to deciopher. I thought NodeSync() would probably be simpler, and may only take 1 argument. I could be wrong though. As Apple strip the debug symbols from the executables, even in the developer previews, there may be no other way to do it except by trial & improvement.

Well, I've got a queue set up that will watch a list of folders (updating the Finder accordingly), and refresh that list when it receives a signal (like SIGIO).

At the moment, I plan to update the list only when the front-most application changes (by waiting for the kEventAppFrontSwitched Carbon event and sending a SIGIO when one is received). This avoids polling, and should only fail to update the Finder when the filesystem is being updated AND you have the Finder in the foreground AND you are changing the list of folders the Finder is displaying.

It's not a perfect solution, but it'll do until I can get APE working. I'll post more progress tomorrow, but I have to go to bed now

Hi guys,It looks like something like this is already implemented in Panther. The problem is, you can't see it until you click on the folder.I just enabled folder actions on my Desktop and attached the action to notify me of any new files added to the Desktop. So, I opened the Terminal and "touch file" and script popped up telling me that new file is added to the Desktop. Something is telling the script that filesystem is changed.Please discuss.

quote:Originally posted by jasenko:It looks like something like this is already implemented in Panther. The problem is, you can't see it until you click on the folder.

That's what people are complaining about - you have to click on the folder. I'm trying to implement a solution that doesn't require you to click on the folder.

Your solution could work, but folder actions would have to be enabled for every folder visible in the Finder, and then disabled when the Finder stops displaying them. Which would be harder than what I'm trying to do.

quote:Originally posted by calumr:I'm on the verge of doing this, but I would need some AppleScript expert to write a script that returns the list of all paths currently displayed by the Finder. Anyone?

Trivial, if they ever implement the expanded keyword.

tell application "Finder"
set thePaths to {}
set theWindows to every Finder window
repeat with theWindow in theWindows
set thePaths to thePaths & POSIX path of target of theWindow
if current view of theWindow is list view then
tell the target of theWindow to set disclosedFolders to (every folder whose expanded is yes)
repeat with disclosedFolder in disclosedFolders
set thePaths to thePaths & POSIX path of target of disclosedFolder
tell the target of disclosedFolder to set disclosedFolders2 to (every folder whose expanded is yes)
repeat with disclosedFolder2 in disclosedFolders2
set thePaths to thePaths & POSIX path of target of disclosedFolder2
tell the target of disclosedFolder2 to set disclosedFolders3 to (every folder whose expanded is yes)
repeat with disclosedFolder3 in disclosedFolders3
set thePaths to thePaths & POSIX path of target of disclosedFolder3
end repeat
end repeat
end repeat
end if
end repeat
end tell

AFAIK, you need those subloops, and you'll need to keep adding them for as many levels as you want to check, but there's no way for me to test it, as enabled doesn't even work.

Does applescript support recursion? If so, you could recursively walk the disclosure tree with no need for the subloops.

Otherwise you can emulate recursion (with lower overhead, too!) with a queue or stack-like structure and a while loop. (E.g. just add every disclosed folder onto the stack and keep popping them off to find new disclosed folders therein, and then adding those folders to the stack, until you've traversed all of the disclosed folders and the while loop terminates.)

It sometimes hangs when it's getting the list of URLs from the Finder, but other than that it works as I explained above. Whenever you switch the frontmost application it updates the list of folders to watch. I don't know if it'll work for smb, ftp or other non-local folders. Enjoy!

EDIT: It doesn't support expanded folders in list view - just the parent folder (plus icon + column view). But then who cares? List view is crap

it's been a while since I've done any AppleScript, but wouldn't you do this with a function which lists folders, then recursively check each item in the parent folder, list it, if it's a folder, enter it, list it, etc etc ?

I seem to remember from WWDC that there is an "entire contents of" or something that gives you a recursive list, but I just tried it out quickly and couldn't get it working...

and that's pretty weird about not supporting POSIX paths anymore, and only using URLs... I guess this is the one true way forward then eh?

quote:Originally posted by dhaveconfig:it's been a while since I've done any AppleScript, but wouldn't you do this with a function which lists folders, then recursively check each item in the parent folder, list it, if it's a folder, enter it, list it, etc etc ?

I need to know if a folder is expanded in list view, not if it exists or not. Currently, this is unimplemented in Panther.

I hope you're all submitting bug reports about this to try and get expanded implemented in Panther? I've had a huge increase in my bug report responses from Apple lately... they seem to be working overtime on the ones I've reported at least...

Slava Karpenko briefly posted to Unsanity's weblog an alpha APE called 'FinderLove' that would auto-refresh Finder windows for 10.3 only. The entry has disappeared from the front page and the RSS feed, and I assume there is good reason for that, but if you're feeling adventurous it's very easy to figure out the URL.

quote: Slava Karpenko briefly posted to Unsanity's weblog an alpha APE called 'FinderLove' that would auto-refresh Finder windows for 10.3 only. The entry has disappeared from the front page and the RSS feed, and I assume there is good reason for that, but if you're feeling adventurous it's very easy to figure out the URL.

Have you tried it? And I must be stupid, for the life of me I can't figure out the URL