XScreenSaver 5.35

XScreenSaver 5.35 is out now!

Yup, this is the first release with a pre-built Android application. Note: it's flaky. Consider the Android port an early beta. About 2/3rds of the savers are included, and not all of them are working properly. But more on that in a minute.

This is a pretty long post. I guess I don't usually talk much about the process that goes into xscreensaver, so, why not. I'm pretty proud of this release so there's kind of a lot to say. It's a big one, because xscreensaver tends to get a lot of attention when my business is doing badly. So my misery is your gain.

First, the new screenhacks:


RaverHoop: It may surprise you to learn that I spend a lot of time at DNA Lounge. Over the last few years we've had quite a few more "rave"-like parties, and those always attract the fuzzy-boots crowd with their light-up hula hoops. When I'm hanging out at the bar watching people goofing around with toys that make blinky persistence-of-vision vapor trails, one of the things my brain does is try to figure out the motion model necessary to simulate it. "I can replace you with a screen saver" is something nobody wants to hear but it's where the brainmeats go. Well that one percolated for a couple of years, and then I finally got it mentally worked out, and wrote it in about half a day. I cracked it when I stopped thinking about inverse kinematics and just came up with a set of simple chained oscillators that kinda matched the physical reality (the term of art for this is "cheating").

That's one of my longest ratios between those two ends of the process, I think. The cool insight I had in this one was the way I manage the decaying after-images as a particle system. I use the traditional GL matrix manipulations to rotate and translate the disk, driven by those randomized oscillators, but then I don't actually render anything while I'm down that matrix stack! Instead I just reverse the matrix to convert the resultant points back to world coordinates and put them on a stack where they decay away. The actual rendering takes place back at the top level. So basically I'm using GL as a matrix library, but then not actually drawing with it. I thought that was neat.

DymaxionMap came together pretty easily too; matching up the triangles with the texture coordinates was the hard part. I admit that there are some magic constants in the unfolding code. I cheated and eyeballed a few things instead of doing it in pure trig. I really enjoy how it stellates out into an object closer to a sphere. The one thing that I'm disappointed in, though, is that I had to use a Dymaxion-shaped texture map for it, instead of starting with a Mercator projection. I'd like to change it so generate the Dymaxion texture on the fly from the same texture that GLPlanet uses, because then (by regenerating the texture a few times a second) I could combine the day and night maps and show where the terminator would be, and show its progression. That would look incredibly freaky when it was folded out flat. But the function F(x,y) that converts Dymaxion Cartesian coordinates to Mercator latitude and longitude... that's a really complicated function, that is.

So I kept having this conversation. "What's up?" "Well, I wrote a thing. Look." And I show them my phone running DymaxionMap, and they say, "Wow, that's freaky!" And I ask, "Do you recognize it?", and they say "No." And I ask, "Do you know who Buckminster Fuller was?" "No." (They always say no. Nobody knows who he was.) "Well, he was this brilliant and kooky mathematician and engineer who invented all of these amazing things, with this very sincere social agenda behind them all, like, he invented the geodesic dome and tensegrity structures and it was with the explicit goal of making inexpensive prefab housing to make homelessness impossible. And this map -- which distorts the relative size of the land masses less than most other projections -- whose political goal was to make everyone realize that all the contintents are more or less connected, and that north and south are political constructs, and it's really one big island that we're all stuck on together. But he was a huge proto-hippie and it wasn't convenient or familiar and nobody cared. So he had these huge ideas, invented all of these incredible things, almost none of which ever actually became relevant or important. He died a fairly tragic figure like, I dunno, Tesla, except that we actually use AC current, and nobody uses a geodesic dome outside of god damned Burning Man, and everything he devoted his life to kind of came to nothing. And then it occurs to me that maybe I'm not talking about Buckminster Fuller at all any more and I get another drink. So. I hope you like the screen saver.

Hydrostat: I ported some Javascript code for this one, and spiced it up by sprinkling more 3D on it. Well, 2½D, more like. When you run it on your phone, pick one of them up and drag it. Spin it in a circle really fast to make it dizzy. They love that.


About that Android port: Let me remind you of the layers of software archaeology going on here:

I started writing XScreenSaver in 1991, using the then-relevant vintage-1985 X11 API. A couple years later, I added the first 3D hacks, targetting the vintage-1992 OpenGL API.

When porting XScreenSaver to other platforms, my goal is to keep a single code base that compiles for multiple platforms. That is, I don't want to end up with two different files that implement "Decayscreen" using different APIs or different languages.

So when I ported it to MacOS, I did that by implementing most of X11 in terms of Cocoa.

That was, you know, kind of a lot of work.

Then I wanted to port it to iOS. Well, iOS supports something kind of like Cocoa, so I got to re-use a lot of that work, but it doesn't have OpenGL, it has OpenGLES instead -- which, despite the similar name, doesn't have much in common with its namesake. Which is incredibly stupid. I talked about that at length here.

So I implemented most of OpenGL in terms of OpenGLES.

That was, you know, kind of a lot of work.

So then Dennis made a first pass at porting XScreenSaver to Android. Now, Android really, really wants you to write your programs in Java. But, there is a "native interface" where Java code can call out to C code. It's a hairy, finicky pain in the ass. So he got a chunk of the xscreensaver C code to compile on Android (cross-compiling for like 16 different architectures, since the Android ecosystem is so amazingly fragmented). He was able to use my OpenGLES implementation of OpenGL to get some of the hacks up and running. (The interface between C and Java is completely maniacal. Transferring objects between the two languages is incredibly verbose, and extremely persnickety about object lifetimes, what's running in what thread, and exceptions. I recommend avoiding JNI if at all possible.)

So then Dave took a crack at getting the X11 hacks working. Instead of doing what I had done the first time and implementing X11 in terms of android.graphics.Canvas or something, he decided to start implementing X11 in terms of OpenGL... Which is altogether a more portable and reasonable idea, and some day we might end up replacing the Cocoa implementation with the OpenGL implementation. But it's not quite complete or up to speed yet.

This is so many layers it's almost like we've built a stack of emulators to run these old programs.

For me this is yet another exercise in "writing programs for hardware you don't own", since I don't have an Android device. That's because I think the Android mobile UI is just monumentally shitty, and I would never inflict that kind of pain on myself in my daily life. I need an appliance that works, not one whose UI feels like it was designed by Linux kernel hackers -- which, in fact, it was. Plus it has all of the security you've come to expect from desktop Linux -- "Oh, I'm sorry Sir, I didn't realize you were root." Pre-jailborken for your botnet and surveillance convenience! I have a lot of issues with Apple and their lock-everything-down gatekeeper business practices, but... "Say what you want about the tenets of National Socialism, at least it's an ethos."

Anyway. It's been a long-assed time since I've written any Java code, and man, it was kind of like slipping into a warm bath. Just so mellow and pleasant. I said this in conversation the other day and my friend said, "What, even after your Java rant?" And I said, "Remember that that thing began with, 'It's is the best language going out of the set bagbiting loser languages that we have to work with!'" He said, "How do you remember the exact words you wrote two decades ago?" That's what I do, I drink and I remember things. Anyway, probably all of those complaints are still true, and I still think it's dumb that they force you to wed your class hierarchy to your directory hierarchy, but it's all just so easy in Java. I think I enjoy Objective C more, though. Objective C just feels more honest about what it is. It's C with a pretty decent Smalltalk sheen on top (but shitty memory safety), whereas Java is really trying to be a Lisp but it is overall a swing and a miss.

I do think it's kind of awesome, though, that my team totally won and these days basically all languages have the Lambda Nature. Remember when I used to have to argue with people about how garbage collection was a good idea, bounds checking was a good idea, intrinsic types were a good idea, and everyone disagreed, I mean, you had to actually argue with people about that, but now every language has garbage collection, bounds checking and intrinsic types? Ha ha, screw you guys.

Hey, pop quiz! Which of these languages is the best Lisp dialect?

  1. Java
  2. Objective C
  3. Perl
  4. PHP
  5. Emacs

The answer, of course, is Perl, because it's the only one of those languages that has both lexical closures and first class anonymous functions. And how sad is that?

And -- yes -- Dear Debian, please stop shipping xscreensaver.

As for the rest of you, I hope you enjoy them!

Tags: , , , , , , , , , ,

55 Responses:

  1. dan mcanulty says:

    Oooh, thanks! I'm really loving RaverHoop a lot already, I have been tweaking its options and am especially enjoying it slowed down with a long decay.

    I broke DymaxionMap by selecting a jpeg of Frank Sidebottom to try to display and now whenever I select it from the screen saver list System Preferences crashes (Mac OS 10.11.5). I've tried deleting that screensaver and reinstalling to see if that would erase the preference changes I made, but it seems like preferences are preserved . Any suggestions where I would go to change those manually? I've got the screensavers installed with the default settings (for all users).

    • jwz says:

      "defaults -currentHost delete org.jwz.xscreensaver.Dymaxionmap", but first email me
      "defaults -currentHost read org.jwz.xscreensaver.DymaxionMap"

  2. Mihai says:

    Two small problems:
    · on the Downloads page, the source code link is named: xscreensaver-5.34.tar.gz; the target file is correct version.
    · compilation fails on (Slackware) Linux with gcc 4.8.2 seemingly because of // style comments in utils/grabclient.c
    Relevant error messages:

    grabclient.c:130:53: error: operator '/' has no right operand
    # if !defined(USE_IPHONE) && !defined(HAVE_COCOA) // Real X11
    ^
    grabclient.c:134:53: error: operator '/' has no right operand
    # if !defined(USE_IPHONE) && defined(HAVE_COCOA) // Desktop OSX

    Replacing the comments solves the problem:

    130c130
    < # if !defined(USE_IPHONE) && !defined(HAVE_COCOA) /* Real X11 */
    ---
    > # if !defined(USE_IPHONE) && !defined(HAVE_COCOA) // Real X11
    134c134
    < # if !defined(USE_IPHONE) && defined(HAVE_COCOA) /* Desktop OSX */
    ---
    > # if !defined(USE_IPHONE) && defined(HAVE_COCOA) // Desktop OSX

    • jwz says:

      I just feel like c99 might be too advanced a standard to hold ourselves to, portability-wise. I mean, it was the mid-90s before I switched from K&R to ANSI, and honestly I'm not sure if it even compiles on VMS any more.

      • Mihai says:

        Now I'm sure it doesn't compile on VMS but I'm working on it.

        (2 days later, since the phrase above would have made a lousy comment):
        It took a while and it wasn't easy, but at least some of the hacks are working on VMS now. More on Alpha than on VAX.

        Of course, I had to modify the DCL command files and the config.h-vms.

        Some of the unsolved problems:
        grabclient (now) uses fork() - VMS doesn't have it, maybe revert it to using system() on VMS?
        Why is m6502.h generated on make? I haven't yet tried to copy the header file from the Linux to see what happens.
        recanim.c seems to require GDK_PIXBUF; I'm not sure where is recanim used (it doesn't appear in LINK procedures).

        It's a good learning experience, in both VMS C and xscreensaver :)

        Thanks for the idea! (and for xscreensaver, and for the stories and...)

        Things you didn't think you would see again:
        int _I_dont_care_that_ISO_C_forbids_an_empty_source_file_ = 1;
        ....^
        %CC-W-LONGEXTERN, The external identifier name exceeds 31 characters; truncated
        to "_I_DONT_CARE_THAT_ISO_C_FORBIDS".

        Good truncation! Also, appropriately while compiling bsod.c on the VAX:

        %CLI-F-TEXT, Compiler abort - virtual memory limits exceeded.
        %SYSTEM-F-ABORT, abort

        Speaking of bsod (that doesn't yet work), vms is reserved word on VMS :)

  3. rc says:

    Oh man. I love xscreensaver, and I love even more the background thought process and tech behind it.

    I probably shouldn't mention this, as I have nothing to show (I didn't even save any screenshots!) but for a week during early 2015, I tried rewriting xscreensaver to JS/WebGL. Looking through the C code did feel like a bit of an archaeological dig. I agree with the "stack of emulators" feeling.

    But, xscreensaver's well documented and the code was virtually clear enough for me to grope around. I could understand it with little-to-no C experience of my own (not that that hasn't stopped me before). I thought your GLES shim was really clever. I got as far as porting Greynetic using canvas2d and halfway through Dangerball. I even made a xscreensavers-settings out of HTML/CSS (just view; no logic. I think I styled it after the Motif toolkit).

    I since lost the project but.. reading this blog post makes me want to try again. Thank you for this post and your continued work on xscreensaver!

  4. Dave says:

    Thanks for your continued work on this and the interesting writeup. Can't get enough of XScreensaver, fuzzy-boot raver replacement strategy notwithstanding.

  5. Jonathan says:

    Yup, this is the first release with a pre-built Android application. Note: it's flaky.

    It'll fit right in.

  6. Buckyballs says:

    If only Buckminster Fuller were around today. He'd have a totally complete welldocumented LinkedIn profile with 500+ followers. And a personal .org website documenting projects.

    Too bad he ephemeralized.

    • James says:

      Yeah, well, it turns out that tensegrity construction methods are the only way to make the 121 square mile microwave transmitter you need to get the "megawatt out of a soccer field" that Paul Jaffee at the Naval Research Laboratory claimed to be able to get out of space solar power when the brass was trying to avoid synthetic fuel, so hey why not go with that.

  7. Eric H says:

    Which of "lexical closures" and "first-class anonymous functions" does Emacs lack? Note that lexical scope is pretty new (24.4 was the first release that had it).

    • jwz says:

      Nah, I still can't accept that any version of GNUmacs has lexical scope. You must have been hallucinating. Next thing you know you'll be telling me that he took the thing about parrots out of his tour rider.

  8. J. Peterson says:

    Many(!) years ago at college I got to see Bucky Fuller speak. Even in his eighties, he packed the house. I'll never forget the end of the lecture. He drew

    on a chalkboard. He points to the first figure "How many triangles?" "One!" the crowd responds. He points to the next "How many?" "Four!", then "Nine!", "Sixteen!"

    "You say trianguling instead of squaring... If you go out of this room saying 'squaring' ever again, humanity is all through!"

  9. Ben says:

    Good lord, what is that spinning up in the background of the videos? I'm having flashbacks to mid-90's server rooms.

    • jwz says:

      The videos are completely silent, I have no idea what you're talking about.

    • ssl-3 says:

      Sounds like an XT, with an ST-419 or some other full-height hard drive and some manner of 5.25" double-density floppy. There is no 3.5" floppy drive in that soundtrack

      It lacks a beep, though.

    • Tobermory says:

      I'm hoping this version of XScreenSaver is all backwards-compatible with the TIS-100 computer.

  10. I got to see Bucky too. Also Tim Leary. C-MU had a good guest lecturer program.

    Nowhere near as involved, but I'm currently re-implementing some 1980s PostScript hacks in HTML5 Canvas just because the drawing models are similar. And I needed an excuse to learn HTML5 Canvas.

    • Lloyd says:

      Can you rewrite the firefox pdf renderer while you're at it? I'm now at the stage of HERE IS MY BUGZILLA REPORT WITH A PHOTO OF WHAT I PRINTED OUT FROM ACROBAT READER AND ANOTHER PHOTO OF WHAT I PRINTED OUT FROM FIREFOX AND DEAR GOD IT'S NOT EVEN CLOSE.

      yeah, there's a sucky timewasting emulation stack with graphical glitches for you.

  11. Phil says:

    This was a great read. "Bag biting loser languages" has been sealed in my personal lexicon since the day I first read it. Same with your Groupware rant, which anticipated the primary use case of social media.

  12. Chas. Owens says:

    I just got a OS X machine again after many years away. I am getting

    "Install Everything" can't be opened because it is from an unidentified developer.

    I assume this means the code isn't signed with a key issued by Apple. Is this something you are not doing on purpose (ie you have a problem with the security mechanism, the cost for the key is too high, etc)?

    • Chas. Owens says:

      Nevermind, apparently if you open the app with a right click and say open it bypasses the security.

    • jwz says:

      I already pay Apple $109/year in order to have the iOS version be installable at all.

      To make it so that you can just click, instead of right-clicking, would cost me an additional $109/year, because iOS development accounts and MacOS development accounts are separate and can't share the same signing keys.

      For $109/year, you can just right click.

      • James says:

        How do you feel about Kivy? It seems to be the only cross-platform framework with "audiostreams" for microphone input.

      • Colin says:

        FWIW I'm pretty sure Apple recently changed it so the developer accounts cover all platforms now.

        • Not watching tv says:

          they're desperate for watch and tvos developers.

          I swear, it's like watching Windows Everywhere.

          They built the hockey puck mouse of remotes, and they built a calculator watch. A calculator watch with a lipstick cosmetics display interface.

        • jwz says:

          Oh, cool!

          Well, I've figured out how to properly sign things with a "Mac Developer" key, so this stupid right-click thing will be gone in the next release. I don't think it's worth re-spinning the DMG just for that, since that would cause the auto-updater to tell everyone there was a new version.

          Fun fact: until MacOS 10.11.5, code-signing a .saver bundle just flat-out didn't work. Fun fact addendum: MacOS 10.11.5 was released yesterday.

          Maybe for the next release I'll publish it in the Mac Store too, since that should be easy/free now. I dunno.

        • jwz says:

          So, I think it's actually not possible to distribute xscreensaver through the Mac App Store. I think the store only allows distribution of singular .app bundles, meaning there's no way to distribute more than one (non-nested) bundle, or a bundle that is not of type .app, or an installer, or even an app that behaved as an installer.

          This makes some amount of sense, in that the App Store party line is "everything must be sandboxed", and .saver bundles can't be sandboxed because they run directly in the address space of ScreenSaverEngine, without memory protection let alone privilege separation. So the elephant in the room here is, "the design of the MacOS screen saver framework is fantastically insecure." To the surprise of nobody.

          For different reasons, I think jwzlyrics won't be accepted in the store, either. It has the ability to put Growl-like notifications on the screen, and because of the way spaces and full-screen windows work, that has to be done by invoking an embedded helper app -- and if that embedded helper is sandboxed and codesigned, the parent process can't launch it with NSTask. It bombs out because it's trying to double-sandbox. It works if the helper is not sandboxed (meaning it will run in the sandbox of the parent) but I'm pretty sure that will trigger a store rejection.

          I can probably get Dali Clock in there, though. But only the .app, not the .saver or the .wdgt.

          • Nick Lamb says:

            "the design of the MacOS screen saver framework is fantastically insecure."

            See, this is how you know you're getting old. In your youth you would have tried to fix this, but now you have the benefit of experience. Nobody cares about security, they just want to see dancing pigs. What we need is a Dancing Pigs screensaver in tribute to the wisdom of age.

            If only Honest Achmed had named his CA the Dancing Pigs Certification Authority I'm sure he'd have had more luck, maybe he'd be in the code signing business by now and you could ask one of his cousins for a discount cert.

            • James says:

              It's still fixable by shaming the ineffective designers. You could make a "STI@phone" (like SETI@home) screensaver which summarizes the vocabulary level of people's outgoing messages and puts them up on a leaderboard, showing them the other people with the greatest vocabulary level in their outgoing messages geographically closest to them. You wouldn't even have to write it, just show that it's possible and shame them with vaporware.

              P.S. Off topic; please be advised.

  13. Philip Guenther says:

    I watched DymaxionMap, continuously** hoping that it would take alternative seams, showing random unfoldings of the world. But the canonical unfolding here isn't simply along a subset of the edges of the icosahedron, so you would be faced with either special casing (specifically choosing to show the canonical form) or vastly increasing the set of possible seams and decision points, producing more fine-grained unfoldings many of which would be just unrecognizable bug splatters of brown and blue, kind of a nihilist reinterpretation of Bucky.

    ** or, give the context, connectedly

    • Buckyballs says:

      I think we need a manifolding of the world of Charlie Stross's Missile Gap.

  14. Ben Nied says:

    Weirdly enough, the double-click-to-install method doesn't work for 5.35. All screensavers report a "Could not install [SCREENSAVER_NAME] screen saver."

    Installing via cp /Volumes/XScreenSaver\ 5.35/Screen\ Savers/[SCREENSAVER_NAME].saver ~/Library/Screen\ Savers works, and all of the 5.34 savers work without issue.

    • jwz says:

      There is a README that wants you to read me.

      • Ben Nied says:

        I did. This part:
        To install only some of them:

        Open the "Screen Savers" folder in this disk image and double-click each saver that you want to install.

        does not work as of 5.35; you get a "Could not install [SCREENSAVER_NAME] screen saver." error in System Preferences. My security settings are already set to allow everything.

        Are you referring to a separate README from the one you include in the DMG?

        • jwz says:

          This time try reading the whole README.

          • Mark says:

            When I opened the dmg I was sure at first that one of the files was named README.rtfm.

          • dzm says:

            I have read the whole README.rtf.

            Double-Click on RaverHoop.saver gets the "Could not install" error.
            Control-Click (or Right-Click) and selecting Open gets the "Could not install" error.
            Setting "Security settings" to "Allow from anywhere" does not make this problem go away.

            In Finder opening the "Screen Savers" folder from your DMG and copying RaverHoop.saver to "/Library/Screen Savers" makes RaverHoop now show up in the Screen Saver pref panel. It appears to work. I suspect using the CLI with "cp" would also work, and using rsync --exists certainly worked for updating the visualizations I already had installed.

            Since I don't want all 200+ hacks I have not run "Install everything" and can't speak to whether it works as expected or not.

            This is all on OS X 10.11.6 Beta (15G7a).

  15. Mark says:

    Forgive my asking a question that's really a MacOS question and not an xscreensaver question, but:

    If I've told MacOS (10.9.5, if it matters) to pick a screensaver at random, is there a way I can find out which one was just running? I knew how to do this on X11...

    • jwz says:

      Not with the default setup. However, there is a saver called "RandomExtra" which is a replacement for "Random" that gives you more control over which savers get picked and how frequently, and it does show the last one that was run at the top of its preferences panel. (It used to be here but no longer.)

  16. Lloyd says:

    but if debian stops shipping xscreensaver, then ubuntu stops shipping xscreensaver, and there is no xscreensaver when ubuntu ships on Windows 10.

    we need a secure active directory password dialog!

  17. Tom Flynn says:

    installing on CentOS7 seems to not include xscreensaver-demo.

    bash-4.2$ xscreensaver-command -version
    XScreenSaver 5.35
    bash-4.2$ xscreensaver-command -demo
    xscreensaver-command: could not exec xscreensaver-demo: No such file or directory

  18. MetaRZA says:

    I had a dream about RaverHoop. You had implemented it as a physical object, some sort of large black tube with addressable leds running around it. You then had to build a box to ship it to Montreal for some exposition.

    And yes, melatonin produces the best dreams.

  19. rrp says:

    Building on a Mac(10.11.5, xCode 7.3.1) targeting Mac fails: jwxyz-timers.c and jwxyz-common.c can't find config.h, and running configure manually fails without a config.h being emitted, complaining that it can't find the X11 headers.

    I last built from source 5.33, but your jwxyz code has changed since then.

    It looks like removing that include and manually defining HAVE_COCOA would work, but that seems ugly.

  20. Karellen says:

    I love DymaxionMap, but we do seem to spend a lot of time looking at the back of the unfolded map. Which is boring. Would it be possible to have the map "show through" in reverse on the back, instead?

    Also, I don't know if one exists, but if there is an unfolding the stellated dodecahedron that doesn't cut up land masses too badly, that would probably be really cool to see.