Archive for August, 2009

F-Script Anywhere is this amazing utility that lets you dynamically inject a complete F-Script environment into any Cocoa application at run-time. Kind of the ultimate tool to explore and take control of applications from the inside.

Unfortunately, the current version does not work on Snow Leopard… But we have a workaround! It is included in a new distribution that has just been made available: F-Script 2.0.1 (download).

It is very simple to use. I’ll show you how it works and how to automate it.

Injecting F-Script into an application

  1. Locate the F-Script framework on your disk. The F-Script framework is part of the F-Script distribution and is named “FScript.framework”. In the following, we assume you put it in /Library/Frameworks/
  2. Open the UNIX terminal and launch gdb by typing:

    Note that if gdb is not on your system, you can get it by installing the Xcode package provided on the installation DVD of Mac OS X.

  3. Attach gdb to the target application, using the “attach” instruction. For example, to attach to TextEdit type:
    attach TextEdit
  4. Load the F-Script framework into the target application by typing the following (we assume the F-Script framework is located at /Library/Frameworks/FScript.framework. Modify the command if this is not the case):
    p (char)[[NSBundle bundleWithPath:@"/Library/Frameworks/FScript.framework"] load]
  5. Add an F-Script menu to the target application by typing:
    p (void)[FScriptMenuItem insertInMainMenu]
  6. Let the application run by typing:

An F-Script menu should now appear in the menu bar of the target application. Using it, you can access the injected F-Script environment and play with the application from the inside.

Automating the injection procedure

Those steps are easy to automate by defining a new gdb command. To have this new command permanently available in gdb, you can add its definition to a .gdbinit file (a text file) that you put in your home directory. Your .gdbinit file is automatically executed each time gdb is launched. Here is the command definition that you can put in your .gdbinit file:

define loadfs 
    attach $arg0
    p (char)[[NSBundle bundleWithPath:@"/Library/Frameworks/FScript.framework"] load]
    p (void)[FScriptMenuItem insertInMainMenu]

This defines a command named loadfs that takes the name of the application you want to inject into as argument.

For example, to inject F-Script into TextEdit you can type the following in gdb:

loadfs TextEdit

This automates steps 3 to 6.

Thanks to Ken Ferry for suggesting this injection technique.

Read Full Post »

F-Script 2.0

F-Script 2.0 is now available.

Companion article: Welcome to F-Script 2.0.


Read Full Post »

Also on oyasuhisa, a cool demo of animating views into crazy transparent windows, making use of Cocoa’s animation techniques. (download).


I reproduce the code below (slightly modified), so you just have to copy and paste in your F-Script console to play with it:

DURATION := 0.5.
WIDTH    := 800.
HEIGHT   := 360.

window := NSWindow alloc initWithContentRect:(120<>60 extent:WIDTH<>(HEIGHT + TOOLBOX_HEIGHT))
                                   styleMask:NSTexturedBackgroundWindowMask + NSTitledWindowMask + NSClosableWindowMask
window setOpaque:NO;
       setBackgroundColor:NSColor clearColor;

make_box := [:frame |
             | box |
             box := NSBox alloc initWithFrame:frame.
             box setBoxType:NSBoxCustom;

toolbox := make_box value:(0<>0 extent:WIDTH<>TOOLBOX_HEIGHT).
toolbox setFillColor:(NSColor colorWithCalibratedWhite:0.5 alpha:0.3);
        setContentViewMargins:(NSValue sizeWithWidth:0 height:0).
window contentView addSubview:toolbox.

field := make_box value:(0<>TOOLBOX_HEIGHT extent:WIDTH<>HEIGHT).
field setFillColor:(NSColor colorWithCalibratedWhite:1.0 alpha:0.1);
      setContentViewMargins:(NSValue sizeWithWidth:0 height:0).
window contentView addSubview:field.

SIZE := (WIDTH min:HEIGHT) / 10 floor.
boxes := {}.
box_frame := ((WIDTH - SIZE) / 2)<>HEIGHT extent:BOX_EXTENT.
NUM_OF_BOXES timesRepeat:[boxes addObject:(make_box value:box_frame)].
setFillColors := [boxes setFillColor:(NSColor colorWithCalibratedHue:@(boxes count iota / boxes count)
setFillColors value.
field addSubview:@boxes.

animationContext := [:block :duration |
                     NSAnimationContext beginGrouping.
                     NSAnimationContext currentContext setDuration:duration.
                     block value.
                     NSAnimationContext endGrouping].

rules := {{'left', 120<>15,
           [:count |
            | iota base |
            iota := count iota.
            base := (HEIGHT / SIZE) floor min:(count raisedTo:0.5) floor.
            (  (           (iota   / base) integerPart     * SIZE)
             <>(           (iota rem:base)                 * SIZE))]},
          {'top', 200<>30,
           [:count |
            | iota base |
            iota := count iota.
            base := (WIDTH / SIZE) floor.
            (  (           (iota rem:base)                 * SIZE )
             <>(HEIGHT - @((iota   / base) integerPart + 1 * SIZE)))]},
          {'bottom', 200<>0,
           [:count |
            | iota base height |
            base   := (WIDTH / SIZE) floor.
            height := (count / base) ceiling.
            iota := count iota + (height * base - count).
            height := height * SIZE.
            (  (WIDTH  - @((iota rem:base)             + 1 * SIZE))
             <>(height - @((iota   / base) integerPart + 1 * SIZE)))]},
          {'right' , 280<>15,
           [:count |
            | iota base |
            iota := count iota.
            base := (HEIGHT / SIZE) floor.
            (  (WIDTH - @((iota   / base) integerPart + 1 * SIZE))
             <>(          (iota rem:base)                 * SIZE ))]},
          {'random', 20<>15,
           [:count |
            | array |
            array := {}.
            count timesRepeat:[array addObject:((WIDTH - SIZE) random)<>((HEIGHT - SIZE) random)].
animate := [:make_origins |
            | origins frames |
            origins := make_origins value:boxes count.
            frames  := origins extent:BOX_EXTENT.
            animationContext value:[boxes animator setFrame:frames]
make_targets := [:make_origins | 
                 [last_rule := make_origins.
                  animate value:make_origins]].
rules@ at:2 put:@(make_targets value:@(rules@ at:2)).

removed_box := nil.
REMOVED_BORDER_COLOR := NSColor colorWithCalibratedWhite:0.0 alpha:0.0.
rules addObject:{'add', (WIDTH - 240)<>30,
                 [| box |
                  box := make_box value:((WIDTH - 240 + 40)<>0 extent:BOX_EXTENT).
                  field addSubview:box.
                  boxes addObject:box.
                  animate value:last_rule.
                  setFillColors value]};
      addObject:{'remove', (WIDTH - 240)<>0,
                 [| count |
                  count := boxes count.
                  (removed_box ~~ nil)
                  ifTrue:[removed_box removeFromSuperview.
                          removed_box := nil].
                  (0 < count)
                  ifTrue:[| frame |
                          removed_box := boxes at:(boxes count random).
                          removed_box setBorderColor:REMOVED_BORDER_COLOR.
                          frame := (removed_box frame origin x)<>(-1 * SIZE) extent:BOX_EXTENT.
                          boxes removeObject:removed_box.
                          setFillColors value.
                          animate value:last_rule.
                          animationContext value:[removed_box animator setFrame:frame]
                                           value:DURATION * 2]]}.

button_frames := (rules@ at:1) extent:80<>30.
buttons := [:frame | NSButton alloc initWithFrame:frame] value:@button_frames.
buttons setTitle:(rules@ at:0);
        setTarget:(rules@ at:2);
toolbox addSubview:@buttons.

window orderFront:nil.
((rules at:((rules@ at:0) ! 'random')) at:2) value. "Initialize last_rule"

Read Full Post »

Posted on oyasuhisa, a package that integrates F-Script and Emacs (download).

Read Full Post »

F-Script 2.0 Release Candidate 1 is now available for download at http://www.fscript.org/download/F-Script20090809.zip

Enjoy! (and don’t forget to report issues)

Read Full Post »