Where’s this class from?

February 14th, 2008 by Joe Ranieri

Occasionally I want to know where a specific class is implemented. Today I wanted to know where iCal’s main calendar view was implemented, in hopes of stealing it for my own uses.

I don’t feel much like typing the description, so here’s a video “tutorial.”


Hijacking JavaScript Functions

February 11th, 2008 by Ryan Govostes

I spent several hours last week tracking down an obnoxious bug in WebKit JavaScriptCore’s Function.toString() implementation where multiple var declarations on a single line would get grouped with parentheses (Radar, Trac, Bugzilla). The incredible WebKit team made a working patch within 23 hours of my report, kudos to them.

Joe and I very much enjoy hijacking code. While this may become a recurring theme on this blog, right now I’m just going to share how to do it in JavaScript. Let’s say one of the .js files included from your page declares the function foo() as

function foo() {
    var x = "spinach";
    alert(x);
}

If you run foo(), it will obviously display a dialog reading “spinach”. But for some reason or other, you need it to say “eggplant” instead, but you can’t alter the original code. Furthermore, pretend we’re in a situation where it’s inconvenient to reimplement the function. No problem — we can just hijack it and modify the code:

// First, get the code to the function
// Here we strip off the "function foo() { ... }"
var c_foo = foo.toString().replace(/^[^{]*{/|>, '').replace(/}$/|>, '');
 
// Now perform whatever modifications we need
c_foo = c_foo.replace('spinach', 'eggplant');
 
// Now overwrite the function with a new Function object using our code
foo = new Function(c_foo);

Now whenever foo() is called, it will use our modified code. Of course, in this simple example we could have just redeclared foo(), but this becomes far more feasible with more complex code.

As an interesting aside, when you call toString() on a function, it’s not actually printing out the function as it was declared (hence, the bug I mentioned at the top of the post). In the case of JavaScriptCore (used by Safari), a function is broken into a graph of various nodes representing keywords, loops, strings constants, and so on. When you convert the function to a string, it traverses the graph and constructs a more familiar representation of it. As such, it’s kind of a handy way to reformat obfuscated (or just hard to read) code, but you’ll lose commenting.


An RB feature you didn’t know about

February 5th, 2008 by Joe Ranieri

Some of you might know that REALbasic will highlight URLs in comments and allow you to click them. But, how many of you knew that has a special “rb-feedback” url type to make linking to feedback reports even easier?

// working around rb-feedback://miokjjuu

Neat eh?


TextKit a3 Available

February 1st, 2008 by Jonathan Johnson

Following up Tuesday’s build, I’ve added a few more features and fixes to this release. I will be out of town for the next week, so it will be two weeks before a4. The changes are:

  • Cut, Copy, Paste, Select All, and Clear are all automatically enabled and handled. Currently only plain text is copied and pasted, but styled text will most likely be implemented in a4 or a5.
  • When clicking at the end of a line that ends with a line ending, the insertion point no longer is after the line ending, but rather directly after the last character on that line.
  • Clicking beyond the last line in the field now properly moves the insertion point to the end. Note that dragging from beyond the last line currently does not work.
  • When the insertion point is at the very end of the field, pressing a carriage return will insert a new line instead of adding a blank space to the last line.
  • The examples folder has been rearranged to help new people to the project understand the different components. A new example is in the works (the obvious one: a text editor).

To download the new version, visit the product page.

As always, we look forward to your feedback!


Window.FloaterProcess Fix for Mac OS X

February 1st, 2008 by Jonathan Johnson

Recently on the NUG, a question came up about making Window.FloaterProcess work correctly on Mac OS X. This property is designed to make it easy to have one of your global floating windows show up only “inside” of another application. After a lack of volunteers, I coded up a generic drop-in fix.

Module FloaterProcessFix
  Private Const kEventAppFrontSwitched = 7
  Private Const kEventClassApplication = 'appl'
 
  Protected Sub CheckOpenWindows()
    declare function GetFrontProcess lib "Carbon" (psn as Ptr) as Integer
    dim psn as new MemoryBlock(8)
    dim err as Integer = GetFrontProcess(psn)
    if err = 0 then
      declare function GetProcessInformation lib "Carbon" (psn as Ptr, _
        info as Ptr) as Integer
      dim info as new MemoryBlock(60)
      err = GetProcessInformation(psn, info)
      if err = 0 then
        dim p as Ptr = info
        dim type as String = p.OSType(20)
        HideShowFloaters(type)
      end if
    end if
  End Sub
 
  Protected Sub Install()
    declare function NewEventHandlerUPP lib "Carbon" (handler as Ptr) _
      as Integer
    declare function InstallEventHandler lib "Carbon" (target as Integer, _
      handler as Integer, itemCount as Integer, typeList as Ptr, _
      userData as Integer, outRef as Integer) as Integer
    declare function GetApplicationEventTarget lib "Carbon" () as Integer
 
    dim handler as Integer = _
      NewEventHandlerUPP(addressOf CarbonEventHandler)
    dim eventTypes as new MemoryBlock(8)
    eventTypes.Int32Value(0) = kEventClassApplication
    eventTypes.Int32Value(4) = kEventAppFrontSwitched
    dim err as Integer
    err = InstallEventHandler(GetApplicationEventTarget, _
      handler, 1, eventTypes, 0, 0)
 
    CheckOpenWindows
  End Sub
 
  Private Function CarbonEventHandler(inHandlerCallRef as Integer, _
      inEvent as Integer, inUserData as Integer) As Integer
    CheckOpenWindows
    return 0
  End Function
 
  Private Sub HideShowFloaters(frontAppCode as String)
    for i as integer = 0 to WindowCount - 1
      if strcomp(Window(i).FloaterProcess, frontAppCode, 0) = 0 then
        Window(i).Show
      elseif Window(i).FloaterProcess <> "" then
        Window(i).Hide
      end if
    next
  End Sub
End Module

How does the code work? There is a Carbon event that fires each time a new application is activated. By installing this handler, we can then find out what the creator code of the frontmost app is, loop over our windows, and hide/show them appropriately. Because Carbon events are fired only when the event happens, the CPU usage is nearly 0, and you can once again use FloaterProcess on OS X.

You can download a full example here.