OSX xscreensaver port

I've got a tricky problem doing the OSX xscreensaver port, and I'm looking for suggestions. Basically, the problem is that the Mac screen saver framework runs every saver in the same address space, and so, when you have two screen savers that share some common global names, they stomp on each other. I'm not sure how to fix this...

So here's the rough structure:

  1. qix.c defines draw_qix(), etc.
  2. deco.c defines draw_deco(), etc.
  3. XScreenSaverView.m defines a subclass of ScreenSaverView that invokes the appropriate draw_ routine.
  4. Qix.saver is built from qix.o and XScreenSaverView.o.
  5. Deco.saver is built from deco.o and XScreenSaverView.o.

Now, step 3 up there is the tricky bit. How do I find the appropriate draw routine?

My first attempt was, through the magic of macros, to have both qix.o and attraction.o define the same global variable, xscreensaver_function_table. That works when the screen saver activates for real, but doesn't work when switching savers in System Preferences: what happens is, the first bundle loaded wins. So if Qix is the selected saver, and you switch to Deco, you still get Qix's version of xscreensaver_function_table, and Deco doesn't run.

So then I thought, well, if the code in XScreenSaverView.m knew the name of the saver it was defining, then I could have it look up the symbol by name: it could look for qix_function_table or deco_function_table as appropriate, and both could co-exist in the same address space. CFBundleGetDataPointerForName() seems to be made for this: given a bundle and a string, it gives you the address of the variable of that name.

So, I have two instances of XScreenSaverView, and I want to know which bundle they were instantiated from. [NSBundle bundleForClass:[self class]] tells me which bundle defined the class, which is the first one loaded (and both instances get the same answer, and malfunction in the same familiar way).

The only idea I have at this point is to define a custom subclass of XScreenSaverView for each saver, that looked like:

    @interface XScreenSaverQixView : XScreenSaverView {}
    @implementation XScreenSaverQixView
    - (NSString *) whoami { return @"Qix"; }
    ...or, more directly:
    - (struct table *) table { return qix_function_table; }

But that's annoying because it means auto-generating 200+ source files, which just kind of rubs me the wrong way.

Any other suggestions?

Tags: , , , ,

Plane vs. Concrete Wall

Buckle up!
Tags: ,