GTD/productivity guru Ethan Schoonover at Kinkless has put up the last installment of his “Kinkless Desktop” series of screencasts. Of course, this particular one interests me as it focuses on Hazel, showing how he integrates it into his workflow to keep his folders organized. He even makes the rules he uses available for download. Check it out here and make sure to check out the rest of the series.
Archive for May 2007
Today I got to demo Hazel for the first time at the MetroMac users group meeting. I didn’t do massive prep for it. I just had a general outline of what I wanted to show and talk about. I’m the type of person that can’t deal with too much prep in these types of situations; it makes me nervous. I ran through the demo earlier in the day a few times and it ran fine. I felt pretty loose going into this.
For the demo, I did the typical vacuum cleaner salesman pitch. I had a bunch of files dumped onto the Desktop. I went over the rules I had set up (basically, just a variation on the sample rules Hazel ships with). I activated them all then ran them expecting that Hazel would clean it all up.
Ran them again.
I checked the logs and everything looked fine. The MetroMac guys ran some interference for me (thanks guys) while I did a little flailing and head-scratching. Ultimately, I just moved on with the rest of the demo but I never really recovered. The impact of the rest of demo was blunted by the fact that there was a mess of files all over the Desktop.
Afterwards, I sat on the sidelines and took the time to diagnose the problem. I looked at the Desktop directory in Terminal. Lo and behold. The files were gone. I looked at my Desktop. I looked at the Desktop folder in a Finder window. The files were still there. It finally dawned on me. Finder failed to refresh. Worse than that. It would refuse to refresh after I navigated to other folders and came back. I ended up force-relaunching Finder and was finally greeted by what the audience should have seen: a clean Desktop. In a nutshell, Hazel worked; Finder didn’t.
It was weird in that the subsequent rules I created worked fine on any new files I downloaded. Thinking about it now, it might be related to the fact that I set the clock forward to demonstrate a time-based rule. I did it during my test runs and I guess Finder got very confused afterwards. I don’t remember but it’s possible the setting-the-clock aspect of the demo was added later and therefore not “regression-tested,” so to speak.
In the end, it’s not such a big deal. It was maybe less than 30 people. Nonetheless, it’s not fun sitting up there clicking that button that refuses to do anything. I’m sure there’s a lesson here but at this point I don’t care. What is this? South Park?
Unfortunately, I don’t have lackeys to yell at like Steve but this thing is behind me and I have a bottle of scotch in front of me so here’s to looking forward!
In keeping with my tradition of random experiments of no practical use, I present another edition of “Productive Waste of Time”.
In a Cocoa app, there’s a notion of the main thread. It’s the thread where all events are dispatched. If you don’t create any threads yourself, all your code is going to run in this thread.
The issue of getting a hold of the main thread came up in #macsb. While the Cocoa docs talk a bit about the main thread and what should and should not happen there, they do not give you a way to actually get a handle on it. Daniel Jalkut, whose fault it is for bringing this all up, suggested using
pthread_main_np(). While it may work, I looked for a Cocoa-only solution that didn’t assume that pthreads’ notion of a main thread would always align with Cocoa’s.
So, I whipped up this NSThread category to do just that. Just drop it in. No special hooks or hook up needed. It basically just uses
-performSelectorOnMainThread:Ã¢â‚¬Â¦ to set a static var. I didn’t use any locks as I felt the worse that would happen is a bunch of threads set the variable multiple times with the same value. If there’s a subtlety in the memory model that I’m missing here, let me know. Also, if the main thread is tied up, you could potentially tie up other threads as well. Also also, if the main thread exits, I’m guessing bad stuff will happen though it will happen regardless of the code here.
@interface NSThread (MainThreadAdditions)
+ (NSThread *)mainThread;
static NSThread *_mainThread;
@implementation NSThread (MainThreadAdditions)
// Only call this from the main thread.
// Actually, do not call this at all. It is done for you.
_mainThread = [NSThread currentThread];
+ (NSThread *)mainThread
if (_mainThread == nil)
[self performSelectorOnMainThread:@selector(_setMainThread) withObject:nil waitUntilDone:YES];
return [[NSThread currentThread] isEqual:[NSThread mainThread]];
Now, why would you need this? Beats me. It came up in discussion and I decided to roll with it. I provide the code here for your use. It is released under the ‘Splain license. This license says you can do whatever you want with this code under the condition that you ‘splain why you need it. Please post here.
Use this code at your own risk. I am not liable for any bad stuff that may happen as the result, directly or indirectly, of using this code. Side-effects may include nausea, dry mouth and brain rash. This is not a suppository.