MacSanta is back in town

December 7th, 2007 — 1:05am


It’s that time of year again. MacSanta is here, providing discounts on all sorts of Mac software for the month of December. I couldn’t get my act together last year but this year Noodlesoft is participating.

Today, Hazel is one of the apps being featured. That means you can get 20% off Hazel for today and 10% off for the rest of the month. Just saunter on over to the MacSanta site for the coupon codes to get your discount on Hazel as well as some other great software.

Comment » | Hazel, Noodlesoft, Software

Weak Linking

December 5th, 2007 — 6:05pm

It’s been a while since I posted. Since then, Leopard has been released and it’s been keeping me busy. Now that I’ve finally upgraded my dev machine to Leopard, I’ve started implementing Leopard-specific functionality. I still want to maintain Tiger-compatibility but there are cases where I need to reference new symbols in Leopard. These articles 1 2 tell you what you need to know, though I thought I’d provide a boiled down guide to what you need to do.

For the purposes of this article, we’ll assume we want a binary that will run on Tiger or later but have access to Leopard-only functionality. In this case, the deployment target is Tiger and the Target SDK (which API version you are using) is Leopard.

  • In Xcode, Project->Edit Project Settings->General. For Cross-Develop Using Target SDK, select the latest OS version whose features you want to use. In this case, Mac OS X 10.5
  • targetsdk.png

  • Click on the Build tab. Make sure the Configuration pop-up is set to All Configurations. Set Mac OS X Deployment Target to the minimum OS version you want to support (Mac OS X 10.4).
  • deploymenttarget.png

In most cases, this is all you need to do. Why’s that? It’s because Apple defines Availability macros that they use to set what symbols are available for different OS releases, based on the settings you just made above. If your target SDK is a later version than your deployment target, the symbols unique to the later target are weak-linked. This means that if the symbol does not exist, it will be set to NULL. As indicated in the articles linked above, you can compare these symbols to NULL before using them. Note that this mostly pertains to things like C functions. For Objective-C, you can check for the existence of classes using NSClassFromString(). For methods, just use -respondsToSelector:. What this all allows is for your program to dynamically use Leopard-specific functionality if it’s available. You can test for specific functionality without relying on doing a broader OS version check.

Of course, there are cases where things don’t work out of the box. For instance, it seems the headers for some lower level APIs aren’t set up with the Availability macros. In such a case, you can do your own prototype, this time asserting the weak linking:

extern void somefunction() __attribute__((weak_import));

If you don’t do this, somefunction() will end up being non-null even on older OS versions which will screw up your check for the function’s existence.

And then there are issues that aren’t based on API so much as behavior. For instance, if there was a bug in Tiger that was fixed in Leopard. It’s not the type of thing your program can detect so in such cases you’ll have to resort to version checking.

Nothing particularly new here but thought it might be helpful for people doing the OS version straddle for the first time.

1 comment » | Carbon, Cocoa, OS X, Programming, Xcode

You’re Doing It Wrong

October 25th, 2007 — 11:00am

In IRC, someone noted how they just learned about gdb’s print-object (or po) command. It was surprising since this was an experienced dev. It just goes to show that no matter how long you’ve been programming, there’s always some thing you should know, but don’t. These are those commands or features you just somehow missed. You bitch about what a pain in the ass something is only to realize that there was a simple solution all along.

So, in the interest of full disclosure, here are a couple of mine.

NSStringFromRect(), NSStringFromRange(), NSStringFromPoint(), et al.

Stupidly, whenever I needed to log an NSRect, NSRange, etc., I’d list out each of the components. For NSRect, it was always the worst, as it would look like this:

NSLog(@"%f %f %f %f", NSMinX(rect), NSMinY(rect), NSWidth(rect), NSHeight(rect));

I could have put this in a #define but for some twisted reason I would just keep copying it from other places or worse, typing it out. I finally learned about the above functions and now my teeth are whiter than ever!

Dragging header files into IB

For years, when I needed to have the header file for my class read into IB, I’d click on the “Classes” tab, select my class, do “Read Files…” (because of peculiarities in my project, the “Read Something.h” item is not enabled) and select my file in the open panel. The step of clicking on the “Classes” tab seemed particularly ridiculous to me if you had an instance of the class selected in the “Instances” pane.

At the last Cocoaheads meeting, Cathy Shive was giving a presentation on doing custom controls. While demonstrating how she put together the nib, I watched in amazement as she dragged the header file into the IB window to update her outlets and actions. I suppressed a sob as I reflected on all the time I wasted.

Command-double-click and option-double-click in XCode

In XCode’s editor, command-double-clicking on a symbol will bring up its definition, opening the appropriate header file as needed. Option-double-click brings up its documentation. You know. Me no know. Me ashamed.

• • •

Maybe these are news to you as well and if so, then I feel slightly less dumb. There are probably worse cases than this but I have erased all traces of them from my memory.

What are your embarrassing discoveries?

10 comments » | Cocoa, Debugging, OS X, Programming

On Leopard compatibility

October 22nd, 2007 — 11:31am

Hazel 2.1 has just been released. One of the main focuses of this release was Leopard compatibility but what does this really mean?

In this case, it means that, for the most part, Hazel will work on Leopard as it did on Tiger. As other devs have pointed out 1, 2, 3, we do not get the final version of Leopard any sooner than you do. Actually, unless we go into a store and pay for a copy on launch day, we will probably get it later.

The implications of this are that there could be changes that have occurred since the last prerelease and the final version that could break things and we won’t know until launch day. It’s a gamble but I’d rather have something usable in your hands the minute you upgrade to Leopard. This version addresses the known Leopard issues to date and should be ready to help organize your Stacks come August 26th.

As for the longer term roadmap with Hazel on Leopard: Hazel is not providing any special Leopard-only functionality currently. When will Hazel start using exclusive Leopard features or go fully Leopard-only? It’s hard to say. Leopard does provide some functionality that Hazel can take advantage of. But until I feel comfortable that a good number of my users have upgraded, I’ll try and support both Tiger and Leopard.

As a user, you do have the ability to influence this. When checking for updates, you have the option of sending anonymous data about your system. One of the things sent is your OS version (you can see all the data sent if you click on the “More Info…” button). Using this data, I can get a sense of Leopard adoption. If you want to be properly represented, then check the “Include anonymous profile” box in the update settings. I keep the data to myself and won’t do any bad things with it. Your participation will help guide Hazel’s future development so, if you’re not doing it already, please consider casting your vote in this manner.

So, in the end, I just want to clarify that there’s a bit of a juggling game here. I’ve tried to make sure that everything works as smoothly on Leopard as it does on Tiger. If it turns out that something changed in the final release or if I just flat out missed something, I’ll fix it. Leopard compatibility is not so much a state as it is a commitment.

2 comments » | Hazel, Noodlesoft, OS X, Software

The Road To Leopard

October 16th, 2007 — 12:06am

As Apple is hurtling towards a Leopard release, we developers are scrambling to make sure our apps work. With the clock ticking down, I am making Hazel 2.1 beta available for testing. It should be Leopard compatible so if you have access to Leopard, I’d love it if you could download it and let me know how well it works.

I’ve also added a couple new features and a bunch of fixes so even if you are using Tiger, this release should have something of interest. For instance, you can now properly format the “Authors” Spotlight field so you don’t get the annoying parentheses and quotes (chalk that up to me stupidly using NSArray’s -description method). In any case, Hazel should be useful for replicating the iTunes folder structure of artist/album/song now.

I’m looking to go final with this next week so no time like the present to try and break things.

Enjoy: Hazel Beta page

Update (Oct. 16, 2007): It’s official. Leopard is shipping on October 26th, available for pre-order now.

Comment » | Downloads, Hazel, Noodlesoft, OS X

Web Traffic Mystery

October 13th, 2007 — 10:26am

In the past couple weeks, I’ve been observing some strange traffic. I’ve been getting a good number of hits to an old blog article of mine. Close to 1000 hits a day which is a lot for an old article that hasn’t been linked to in months.

The traffic has the following characteristics:

  • No referrer.
  • Different IPs.
  • User agent is the same: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
  • No other hits from those IPs (at least from the ones I’ve checked at random).

Seeing as how the article is Mac-centric and the user agent is for a Windows client, I suspect that these are automated hits and that whoever is hitting the article doesn’t care about its content. But if it’s some sort of bot attack, I don’t see the point of it.

Unfortunately, I can’t figure out much more than that. So, yes, consider this a “Dear Lazyweb” post. If you have any ideas on what’s going on, please post here. Oh, and don’t ask me how, but I have eliminated the Illuminati from the list of suspects. UFOs/aliens are still fair game though.

Update (Oct. 16, 2007): Not sure what happened but it stopped, pretty much completely. It’s like someone flicked a switch. I still have no idea what that was all about but the fact that it stopped pretty suddenly implies there’s a central source to all this.

Also, something else I realized was that it seems as if those hits were hitting the article page but not any of the associated files (css, graphics, etc.). Very strange.

Again, any theories are welcome.

Comment » | Web

Talking to my self

October 9th, 2007 — 10:21pm

I have code that takes in a string and uses key-value coding to extract a value from an object. It works fine if you want to get a property of an object, but what about getting the object itself? Using nil or an empty string with -valueForKey: or -valueForKeyPath: causes it to call -valueForUndefinedKey: which, by default, throws an exception.

After some diddling around, I found that you can use the key @"self". Doing valueForKey:@"self" on an object returns that object. There’s no magic here. NSObject has a -self method which returns, crazily enough, itself. This is peculiar because on the surface, this method is useless. Anywhere where you can type [anObject self] you can type anObject instead. Where this method comes in handy is in cases where you dynamically call a method/selector, as in KVC, and you want to specify a method that is a short-circuit of sorts.

So, in short, all of the following are equivalent:

someObject
[someObject self]
[someObject valueForKey:@"self"]
[[[someObject valueForKey:@"self"] self] valueForKey:@"self"]

I’m sure someone can use the last one in some Objective-C obfuscation contest.

5 comments » | Cocoa, OS X, Programming

Adjusting screen brightness with the “crumb-catcher” keyboard

October 8th, 2007 — 12:12pm

This can be filed under “Things that everybody probably already knows but you only just discovered recently”.

Both my old Powermac and my current Mac Pro shipped with the white “crumb catcher” keyboards. While the keyboards on Apple’s laptops as well as the newer aluminum keyboards have buttons for brightness, I always thought that you could not do so on the white keyboards. They have dedicated volume and eject buttons so I assumed that any brightness controls would be labeled as such. To adjust the brightness on my ACDs, I just used the buttons on the side of the screen itself. Not ideal as I prefer to not have to leave the keyboard when possible.

keys.png

Thar be brightness controls on those keys!

Imagine my surprise when I overshot the “Home” key and hit F15. The screen brightness overlay appeared and the brightness went up by a notch. Sure enough, its neighbor to the left, F14, decreased the brightness. Now, while I’m happy that I can now adjust the brightness from the keyboard, I have to say I’m puzzled as to why Apple didn’t stick the brightness icons on the keys. I don’t know about you, but I couldn’t give a rat’s ass about having F14 and F15 keys. The fact that I only discovered this now shows how often I press them. But, stick those “sun” icons on there and all of a sudden, those keys are useful. Of course, that leaves F16 out there all alone though I’m sure they could have figured out something for it as well. Now, the newer keyboards extend the function keys all the way over and all the hardware functions are doing double-duty with them. God knows my computing experience has been seriously blunted by the lack of an F19 key.

I get the feeling many of you know about this already and that I’m late to the party. If so, my apologies. But if this is news to you, then you might want to consider breaking out that sharpie and re-labeling your F14 and F15 keys.

4 comments » | Hardware

Hazel on MacUpdate Promo

September 27th, 2007 — 12:14am

For today only, Hazel is on sale at MacUpdate Promo for 35% off. If you’ve been thinking about it and just haven’t gotten around to clicking the “Purchase” button then here’s your chance. And if you already have a copy (and a thanks to you), then forward the link above to a friend. And if you don’t have any friends, I can think of no better way of making a new friend than by walking up to a random Mac user in a cafe and pointing them to the link above. And if getting to the nearest Mac user requires you to be put in cryogenic stasis for the multi-lightyear journey, then click the link and leave a nice comment.

But please, do not spam people or forums. Practice responsible computing. Only you can prevent forest fires. Be cool, stay in school.

Comment » | Uncategorized

Animation in the Time of Tiger: Part 3

September 20th, 2007 — 12:22pm

In this final installment, we’ll go over some more advanced ways to do animation.

Now, you may find that the types of animations you want to do can’t be handled by NSViewAnimation or that you need better performance. The solution usually involves getting a bitmap of your view or window. Having a bitmap allows you to do all sorts of manipulations and tap into other technologies that you can’t do directly with views or windows.

To get a bitmap of your window there are a couple methods. The first is to use NSCopyBits(). If you go back to the first article in this series, you’ll see that I glossed over this, but the technique is being used there. The window’s pixels are grabbed and the resulting image is scaled in the animation using an alternate window that just looks like the original. You can check out the downloadable project there.

Now there is a potential issue. This technique will not work if the window device has not been created yet. This happens when you mark the window as deferred and it hasn’t been brought on screen yet. To circumvent this for deferred windows, I quickly order the window on and off screen to force creation of the window device. I don’t see a visible flicker but your mileage may vary. If you know of a better way to force creation of the window device on a deferred window, let me know.

The other method is getting the window’s contentView’s superview and grabbing its pixels using one of the methods below. I’m not sure if it’s a good idea or not to be mucking with the contentView’s superview but it’s an alternate way at getting the pixels.

For views, there are a few options:

- drawRect

You could just lock focus on an NSImage and call view’s drawRect:. This will work but only for the current view. Not really useful except for specific cases where you only want this view and none of its subviews.

- initWithFocusedViewRect:

This works for most cases but it does require that the view be installed in some window’s view hierarchy. lockFocus on your view (not the image), create an NSBitmapImageRep and init using the above method, and boom, you got your view’s pixels (and don’t forget to unlock focus).

- cacheDisplayInRect:toBitmapImageRep:

First get the NSBitmapImageRep by calling NSView’s bitmapImageRepForCachingDisplayInRect:. If your view is not opaque, you may want to clear the pixels in this buffer. Call NSView’s -cacheDisplayInRect:toBitmapImageRep: to actually get NSView to draw the pixels into the bitmap. Using this method, the view does not have to be plugged in, so you don’t have to pop the view into the view hierarchy just to take its picture. Useful in the case where you are swapping views in and out and want to animate the incoming view before it’s actually in. This was added in 10.4 so won’t be useful for pre-Tiger.

• • •

Ok, now you have some pixels, what can you do with them?

Well, you can composite the bitmaps yourself and move them around. In general, this should perform better but you have to do more code in general to coordinate the animation than if you used NSViewAnimation.

You can also pipe that bitmap into Core Image. There are all sorts of effects available including a whole class of filters just for transitions. Luckily, Apple already has a good example called Reducer. Check out the AnimatingTabView class.

Another example of using Core Image is Rainer Brockerhoff’s Flipr which flips windows like Dashboard does with widgets.

And lastly, you can use OpenGL. Create a texture out of the bitmap and slap it onto a surface. I’ve done an example demonstrating this. It does something similar to Flipr but it’s using OpenGL and it focuses on flipping views, not whole windows though Flipr’s technique can be used for views as well and this technique can be extended to windows.

For the dev tool impaired, here’s a movie demonstrating the effect:


<a href="https://www.noodlesoft.com/blog/uploads/2007/09/viewflipper.mov">Download movie</a>

The key step here is described in this technote. Basically, you get the view’s bitmap and then convert that into a texture. As pointed out on cocoadev.com here, textures end up being upside down so as described in that article, I flip it. The code on that page also has a more reliable calculation of the pixel row length than the example from Apple’s technote so make sure you use that. From there, I create a slab and map the textures onto the surfaces. I animate rotating on the y-axis and voila! A flipping animation between views.

Details to note:

  • I create a parent view which swaps in the NSOpenGLView subclass to do the animation then swaps it back out. This avoids having to deal with issues of having subviews of an NSOpenGLView.
  • I do a calculation and adjust the perspective/frustum to make sure the view takes up the full viewport when facing you.
  • Notice that the animation gets clipped. Since it extends out towards the viewer, the shape needs to extend beyond the bottom and top bounds. Basically, the parent flipper view and the OpenGL flipper need to be larger than the views to provide an extra buffer. Or you could do it in an overlay window. There are a few more details involved but feel free to email me if you are thinking of pursuing this.
  • To keep things simple and clear (and because I’m lazy), the code here assumes that the views are opaque (if you look in the nib, the views have opaque, tabless tabviews used to draw the background). One could fix the code to grab a bitmap from the nearest opaque ancestor view though it would require having the view installed in the hierarchy.

Keep in mind that the last time I touched these 3D APIs, it was called just GL, not OpenGL, and it was on an SGI machine. So, while this example may be useful for certain details, my OpenGL-fu is weak so you might be better off using other examples for OpenGL specific stuff. Also, if I am doing anything stupid, let me know.

Well, that wraps it up for this series. I hope you gleaned something useful from it.

Comment » | Cocoa, Downloads, OpenGL, Programming

Back to top