Archive for the 'Cocoa' Category

Fun With PyObjc: Growl Notification Hell

Most of the time PyObjc is wonderful to work in, I love the python libraries and language.

Other times it just makes me angry.

It seems, at least initially, that PyObjc (2.2b3, the default installation with 10.6 snow leopard) does not work with the Growl framework. You can register your application with growl fine, but if you try to push notifications to growl nothing happens.

Here is what I tried initially to post a growl notification in pyobjc:

GrowlApplicationBridge.notifyWithTitle_description_notificationName_iconData_priority_isSticky_clickContext_(u"Notification", "A description.", u"Notification", objc.nil, 0, objc.NO, objc.nil)

This does not work, and for a minute I thought I was the only one experiencing this problem (all open source pyobjc projects using growl had almost identical growl notification code) until I found this commit message on github. I found an associated discussion on the growl discussion group and was disheartened that the developer resorted using a command line version of growl to post notifications. However I decided to try one last thing, and checked the className of python objects passed through the objc bridge.

Here is a table of the objc className of different string creation methods in python:

  • unicode(“a string”) or u”a string”: OC_PythonUnicode
  • str(“a string”) or “a string”: OC_PythonString
  • r”a string”: OC_PythonString

Interestingly enough a python string (unicode, str, raw) is not ‘toll free’ bridged like CFString & NSString are. I guess this is to be expected and shouldn’t cause any problems since both OC_PythonString and OC_PythonUnicode are subclasses of NSString, the documentation even states “A Python unicode may be used anywhere a NSString is expected”. It seems that this is not always the case though. I tried one last thing before resorting to rewriting the code in objc:

GrowlApplicationBridge.notifyWithTitle_description_notificationName_iconData_priority_isSticky_clickContext_(NSString.stringWithString_("Notification"), NSString.stringWithString_("A description."), NSString.stringWithString_("Notification"), objc.nil, 0, objc.NO, objc.nil)

And it worked. Note that the created NSString’s don’t get converted by the bridge into a OC_PythonString object, they pass through as regular NSString’s. Note that you also write the above as the more python native:

GrowlApplicationBridge.notifyWithTitle_description_notificationName_iconData_priority_isSticky_clickContext_(NSString.stringWithString_("Notification"), NSString.stringWithString_("A description."), NSString.stringWithString_("Notification"), False, 0, False, None)

One other interesting that I found is that bridge throws a memory leak warning when running NSString.alloc().initWithString_("Notification"):

UninitializedDeallocWarning: leaking an uninitialized object of type NSPlaceholderString

My only guess is that because initWithString is called instead of init the bridge sees it as a uninitialized object (so I would guess that this warning is falsely thown). Unfortunately the PyObjc documentation is too sparse for me to able to determine what the real cause of the error is.

Create TGZ Automator Service

With Snow Leopard came some nice refinements to automator actions. However, all existing automator actions had to be recreated as services in order to be accessed through the Finder’s contextual menu. One automator action which I used fairly often was the create tgz workflow. I always found that action to be fairly useful so I recreated it as an action.

Another unfortunate change with Snow Leopard was the elimination of input managers. This eliminated the convenient F-Script injection functionality that was present in F-Script anywhere. Luckily this functionality has been recreated using an automator service. Nice work!

Jump To A HTML Anchor in a WebView

This isn’t something that is as straightfoward as you would think. There is no real ‘cocoa native’ way to acomplish this, and there seemed to be no information anywhere on how to acomplish this until I found this post. So it seems the only way to scroll to an anchor is to resort to evaluating javascript code:

- (void) jumpToAnchor:(NSString *)anchor {
    [oWebView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"var anchor = document.anchors[\"%@\"];window.scrollTo(anchor.offsetLeft, anchor.offsetTop);", anchor]];
}

Don’t Forget To Flush…

No, not the toilet, your file streams.

I was recently working on a project that involved creating a child process and reading its stdout to update the user inteface. Everything was working great until I sent it off to some testers who reporting that it ‘wasn’t working’ – the interface wasn’t updating correctly. I first thought it was a problem with the shell command itself, maybe it wasn’t performing the operation correctly and thus wasn’t sending the correct message through stdout but as far as I could tell everything was working perfectly. After about 3 hours of banging my head against the wall trying random things I finally thought to flush the stdout after sending my status message. It fixed it! But why would it would fine on my laptop (intel), my desktop (ppc), but not my old laptop (ppc)? The problem arose from the fact that right after sending the data to stdout the child process would call a function that would block indefinitely. I learned my lesson, always flush the stream if you are depending on reading that output in a timely manner!

XTrace 1.1

At last XTrace 1.1 is out the door! This has been a long time coming, and has alot of changes & new features:

  • CMD+Shift+C now clears the log window
  • XTrace now automatically starts the trace server
  • Added the Sparkle (auto updating) framework
  • Added the ability to disable wrapping in the log window
  • Added the option for window auto-close (log window will close when the SWF it is connected to closes)
  • New icon thanks to Ale!
  • Log message coloring/formatting thanks to Daniel Giribet
  • Compiled & tested as a universal binary

I’ve recorded a quick tutorial on how XTrace works. If you’re new to XTrace, or just want a quick refresher I encourage you to take a look.

If you would like to get involved with development, please send me an email! If you have a feature you want added contact me and I’ll give you SVN access you so you can contribute to the project!

I want to give a big thanks to everyone who contributed ideas/code to this update, it’s great to see other people using my software and contributing time & effort to make it better for the flash community.

Actionscript 3

A lot of people have asked about Actionscript 3 support. Although I don’t use AS3 yet, someone is working on a port of my debug class to AS3 which will allow XTrace to work with AS3.

Zeroi Support

The folks over at Zeroi have created a plugin (modified debug class) that allows XTrace to work with Zeroi. If your a Zeroi user, or even if you aren’t, you may want to check it out.

mach_override on Intel Macs

I was disappointed last month when after a hour or two of hacking I couldn’t get mach_override (evil, I know) to work on my new MacBook Pro even though it had been ported to intel macs. I added myself to the procmod group and tried everything that google could come up with, but I could only get it to succesfully override local functions, it wouldn’t override any library/system functions no-matter what i did.

Today I’ve found the solution on the ExtendAMac mailing list hosted on sourceforge: this simple post contains a small patch that seems to fix all the issues I’ve been having. There doesn’t seem to be any replies to the post on the mailing list, and the post wont come up on any google searched related to mach_override on intel macs – pretty frusterating when you don’t know about the ExtendAMac mailing list. The solution is very simple, replace this block of code:

static AsmInstructionMatch possibleInstructions[] = {
    { 0x1, {0xFF}, {0x90} },                    // nop
    { 0x1, {0xFF}, {0x55} },                    // push %esp
    { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },            // mov %esp,%ebp
    { 0x1, {0xFF}, {0x53} },                    // push %ebx
    { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} }, // sub 0x??, %esp
    { 0x0 }
};

with this:

static AsmInstructionMatch possibleInstructions[] = {
    { 0x1, {0xFF}, {0x90} },    // nop
    { 0x1, {0xF8}, {0x50} },     // push %eax | %ebx | %ecx | %edx | %ebp | %esp | %esi | %edi
    { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },        // mov %esp,%ebp
    { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} }, // sub 0x??, %esp
    { 0x0 }
};

Hopefully this helps someone who was banging their head against the wall trying to figure this out like I was!