Category > geekstuff

Sony's Changes to GNUstep GUI Library: Adding Touch
Posted by postfuturist on 2010-11-27 01:21:27

When Sony announced and then promptly put the SNAP (Sony's Networked Application Platform) on hold, they left the SDK's available for download. I'm a big fan of open development platforms and I was keen to give this one a whirl, especially seeing that it is built on open technologies like the Linux kernel and GNUstep platform. I managed to download the latest version of SNAP (1.2.2) before they removed the download links. I'll be disappointed if the SNAP Developer Program gets killed for unknown internal reasons at Sony, but it won't be a complete loss, as Sony did distribute (albeit for a short time) modifications and additions to the GNUstep GUI library which is under LGPL.

Sony built on top of version 0.17.1 of the GNUstep GUI library. I found the original sources of the library and created a github repo with the original 0.17.1 version of the library as the first commit, with Sony's changes applied as the second commit, so you can easily see what they changed. That is available here: https://github.com/deliciousrobots/gnustep-gui-sony .

What did Sony add? Mostly they added touch interface related code. The files they added are prefixed with "SN" so they are easy to find:


$ find -name "SN*"
./Headers/AppKit/SNCheckmarkGestureRecognizer.h
./Headers/AppKit/SNRotationGestureRecognizer.h
./Headers/AppKit/SNLongPressGestureRecognizer.h
./Headers/AppKit/SNGestureRecognizer.h
./Headers/AppKit/SNSwipeGestureRecognizer.h
./Headers/AppKit/SNTouch.h
./Headers/AppKit/SNTapGestureRecognizer.h
./Headers/AppKit/SNPanGestureRecognizer.h
./Headers/AppKit/SNPinchGestureRecognizer.h
./Headers/AppKit/SNLassoGestureRecognizer.h
./Source/SNLassoGestureRecognizer.m
./Source/SNPinchGestureRecognizer.m
./Source/SNCheckmarkGestureRecognizer.m
./Source/SNPanGestureRecognizer.m
./Source/SNLongPressGestureRecognizer.m
./Source/SNGestureRecognizer.m
./Source/SNTapGestureRecognizer.m
./Source/SNRotationGestureRecognizer.m
./Source/SNTouch.m
./Source/SNSwipeGestureRecognizer.m

As you can see, mostly they added touch and multi-touch gesture recognition. I looked at the code, it is a bit rough in places, definitely a work-in-progress, but interesting and now an LGPL'ed library of gesture recognition code in Objective-C. I was impressed with how nice some of the comments on the code were. Take a look at this bit from the SNLassoGestureRecognizer class:

/* 
 * Returns whether or not a given point is inside the lasso.
 * This is a "Point in Polygon" problem, and we solve it by the
 * "winding number algorithm".
 *
 * We first translate all vertices of lasso by -p to make it the
 * new origin. Then, we traverse all verticies to see how many times
 * the polygon winds around the point, using the "Axis Crossing 
 * Method". If the winding number is 0, then the point is not inside
 * the polygon. Otherwise, the point is.
 *
 * Note: This algorithm works for convex/concave/complex polygons.
 * Detailed algorithm can be found here:
 * http://www.engr.colostate.edu/~dga/dga/papers/point_in_polygon.pdf
 *
 *            _____        __
 *      |    /   __\      |  \
 *      |   /   /   point |  | 
 *      |  |    \  *     /   | 
 *      |  |     \______/  __|
 *      |   \             /
 *      |    \__         /
 *      |       \______/
 *   ----------------------- 
 *      |
 *
 *
 *   ---> translate polygon by -p
 * 
 *
 *                 |
 *        II       |       I
 *            _____|       __
 *           /   __|      |  \
 *          /   /  |point |  | 
 *    -----|----\--*-----/---|--- 
 *         |     \_|____/  __|
 *          \      |      /
 *      III  \__   |     /  IV
 *              \__|___/
 *                 |
 *                 |
 * 
 *
 */
- (BOOL) pointInLasso: (NSPoint) point inView: (NSView *) view;
{
   NSPoint pointInWindow;

   // convert to window-based coordinate first, if necessary
   if (view)
      pointInWindow = [view convertPoint: point toView: nil];
   else
      pointInWindow = point;

   if (pointInWindow.x > maxX || pointInWindow.x < minX ||
       pointInWindow.y > maxY || pointInWindow.y < minY)
   {
      // point is not even in enclosing rectangle
      return NO;
   }

   /***
   NSEnumerator *enumerator = [vertices objectEnumerator];
   NSValue *value;
   NSPoint vertex;
   NSPoint translatedVertex;
   BOOL quadrant_I = NO, quadrant_II = NO, quadrant_III = NO, quadrant_IV = NO;
   
   while ((value = [enumerator nextObject]))
   {
      vertex = [value pointValue];
      printf("vertex = (%f, %f)\n", vertex.x, vertex.y);
      translatedVertex = NSMakePoint(vertex.x - pointInWindow.x, vertex.y - pointInWindow.y);

      if (translatedVertex.x > 0 && translatedVertex.y > 0)
         quadrant_I = YES;
      else if (translatedVertex.x < 0 && translatedVertex.y > 0)
         quadrant_II = YES;
      else if (translatedVertex.x < 0 && translatedVertex.y < 0)
         quadrant_III = YES;
      else if (translatedVertex.x > 0 && translatedVertex.y < 0)
         quadrant_IV = YES;

      if (quadrant_I && quadrant_II && quadrant_III && quadrant_IV)
         return YES;
   }
   ***/

   NSEnumerator *enumerator = [vertices objectEnumerator];
   NSValue *value1;
   NSValue *value2;
   NSPoint vertex1, vertex2;
   NSPoint initialVertex, translatedVertex1, translatedVertex2;

   value1 = [enumerator nextObject];
   value2 = [enumerator nextObject];
   vertex1 = [value1 pointValue];
   translatedVertex1 = NSMakePoint(vertex1.x - pointInWindow.x, vertex1.y - pointInWindow.y);
   initialVertex = translatedVertex1;

   winding = 0;
   do
   {
      vertex2 = [value2 pointValue];
      translatedVertex2 = NSMakePoint(vertex2.x - pointInWindow.x, vertex2.y - pointInWindow.y);

      winding += [self calculateWindingNumberFrom: translatedVertex1
                                               to: translatedVertex2];

      translatedVertex1 = translatedVertex2;
   }
   while ((value2 = [enumerator nextObject]));

   // last vertex to first vertex
   winding += [self calculateWindingNumberFrom: translatedVertex2
                                            to: initialVertex];

   if (winding == 0) 
      return NO;
   else 
      return YES;
}

- (float) calculateWindingNumberFrom: (NSPoint) v1 to: (NSPoint) v2
{
   float intersect;
   float x1, y1, x2, y2;
   x1 = v1.x;
   y1 = v1.y;
   x2 = v2.x;
   y2 = v2.y;

   if (y1 == 0 && y2 == 0)
   {
      // both v1 v2 are on x-axis, winding number unchanged
      return 0;
   }
   else if (y1 * y2 < 0) // line v1 -> v2 crosses x-axis
   {
      intersect = x1 + (y1*(x2-x1))/(y1-y2); // x-coordinate of intersection of line v1 -> v2 and x-axis
      if (intersect > 0) // line v1 -> v2 crosses positive x-axis
      {
         if (y1 < 0)  //counter-clockwise
            return 1;
         else         //clockwise
            return -1;
      }
   }
   else if (y1 == 0 && x1 > 0) // v1 on positive x-axis
   {
      if (y2 > 0) 
         return 0.5;
      else 
         return -0.5;
   }
   else if (y2 == 0 && x2 > 0) // v2 on positive x-axis
   {
      if (y1 < 0) 
         return 0.5;
      else 
         return -0.5;
   }

   return 0;
}

You've got to love the ASCII-art diagrams. None of this code is revolutionary and most of it is pretty boring except for a couple interesting algorithms like the one above. Sony added a good deal of code and changed some things around in the existing GUI module files, too, to incorporate all the multi-touch code into the rest of the system. I hope this code is of some use to the GNUstep team. Anyone implementing a multi-touch interface could also look at this code for a little inspiration.

For me, it's mostly just interesting. I was intrigued by the idea of another open platform to build interesting apps for. Here's hoping Sony moves forward with it.

Sony SNAP Development SDK Still Available
Posted by postfuturist on 2010-11-26 16:13:28

Sony recently announced and then promptly put on hold a software development program for networked devices called SNAP. Within hours, it seems the project was put on hold. Everyone seems to be reporting that the SDK is no longer available for download. It may not be linked from the main page anymore, but a quick search was all it took to find the SDK download page, which still seems to be working here.

EDIT: that page no longer has the SDK after all. I have a copy, but I don't want to distribute it if I don't have the right to. Instead, I did publish some of the LGPL'ed code on github here.

Delving Into Macros
Posted by postfuturist on 2010-11-03 22:41:50

I go through periods of obsession with different programming languages. I don't know why, I guess I get bored easily. I usually get stuck using the same 2 or 3 at my day job. Since I work in web development, that tends to be PHP, Python and JavaScript. When I hack for fun, I'm not very goal-oriented, and I tend to want to explore and try new and exciting things. Well, new for me at least. Lately, I've been on a Common Lisp kick again. I've been writing code. I got to a point where I wanted to be able to pop the "nth" element from a list. Strangely, this doesn't seem to exist in Common Lisp. In Python, the "pop" method on lists has an optional parameter for which element to remove and return:

x = [1,2,3,4]
y = x.pop(1)
print(x) # [1,3,4]
print(y) # 2

So I had to write one, which involved learning how macros work again. Here's my first attempt:

(defmacro popnth (n lst)
  (let ((tempvar (gensym)))
    `(if (eql ,n 0)
      (pop ,lst)
      (let ((,tempvar (nth ,n ,lst)))
        (setf (cdr (nthcdr ,(- n 1) ,lst)) (nthcdr ,(+ n 1) ,lst))
        ,tempvar))))

Unfortunately, that makes 1 call to "nth" and 2 calls to "nthcdr" making the whole thing probably a bit slower than necessary for larger lists. So here is a version that only iterates through the list once:

(defmacro popnth (n lst)
  (let ((t1 (gensym))(t2 (gensym)))
    `(if (eql ,n 0)
      (pop ,lst)
      (let* ((,t1 (nthcdr ,(- n 1) ,lst))
              (,t2 (car (cdr ,t1))))
        (setf (cdr ,t1) (cddr ,t1))
        ,t2))))

Of course, there's a subtle error in these examples, the unquoting is off in the subtraction. Here it is fixed:

(defmacro popnth (n lst)
  (let ((t1 (gensym))(t2 (gensym)))
    `(if (eql ,n 0)
      (pop ,lst)
      (let* ((,t1 (nthcdr (- ,n 1) ,lst))
              (,t2 (car (cdr ,t1))))
        (setf (cdr ,t1) (cddr ,t1))
        ,t2))))
Banshee not quite ready to replace Rhythmbox
Posted by postfuturist on 2010-11-01 17:02:33

First of all, I like the Banshee project. However, I've just been continually underwhelmed by its features compared to Rhythmbox. They both read and write tracks to my IPhone, which is very nice. They both monitor my music folder for new music. Great. They both integrate with the Ubuntu One music store, which I like.

There are some differences, though. Rhythmbox ships with a plugin on Ubuntu that allows DAAP sharing. With Banshee, I have to run Tangerine separately. Also, Rhythmbox seems to be able to list the songs in an album in the correct order more often than Banshee. I don't know why, but even albums that have proper tagging sometimes play in the wrong order in Banshee. Banshee leaks memory. I left it open over the weekend (default configuration, no extra plugins enabled) and when I got back it was using 1.3 GB of memory. Not only that, but I had to kill the application as it wouldn't exit cleanly. Rhythmbox, on the other hand, has a very low memory profile, rarely going above 80 MB even when left running for days.

I like Banshee, but version 1.7.6 that ships with Ubuntu 10.10 still doesn't quite seem ready to replace Rhythmbox. Maybe if I get bored enough, I'll D/L the source and poke around and see if I can't help fix these shortcomings. The idea of tracking down memory leaks in a C# app doesn't seem like a lot of fun, though. Mono is a fine platform, I just haven't done much with it in awhile.

UPDATE: Well, I've reviewed the situation, and there are a couple votes in the opposite direction. First of all Rhythmbox fails to transfer songs successfully to my IPhone, creating invalid or unplayable entries. Conversely, Banshee does this correctly. Also, Banshee has Amazon MP3 store integration that works nicely. You buy the tracks and they download into your collection instantly. That's nice. Also, the other day I noticed that Rhythmbox's memory usage managed to creep up to nearly 400 MB, so it obviously isn't perfect in this respect. For now, I think I'll try using Banshee, I'll just have to remember to restart it periodically to keep memory usage sane.

In Kauai and Python Class Notes Online
Posted by postfuturist on 2010-10-17 20:51:44

I'm in Kauai, on vacation. It's amazing. Everybody should come here.

Python Class Notes are available online, now. It is still a work in progress and will continue until I am done. If you don't like it, fork it on github, make it better, and send me a pull request. Content is Creative Commons licensed, code is BSD.

Better Python Text Input
Posted by postfuturist on 2010-10-10 22:29:05

I've got this habit of writing Python apps with the following form (when I say Python, I mean, of course, Python 3.x):

while True:
    command = input("enter command> ")
    if command == "quit":
        break
    elif command.startswith("something"):
        do_something() # and so on...

Well, I'm used to interactive shells like bash or the Python or Ruby interactive shells which have history (with up-arrow) and sometimes even tab-completion. Apparently, the readline module in Python provides this functionality without too much effort. Here's a little snippet which will turn on simple history (not saved between sessions, though that is possible, too) and tab-completion.

import readline

commands = [
    "help",
    "quit",
    ]

def completer(text, state):
    if state == 0:
        for command in commands:
            if command.startswith(text):
                return command
        return text

readline.set_completer(completer)
readline.parse_and_bind("tab: complete")

while True:
    command = input("#> ")
    if command == "quit":
        break
    elif command == "help":
        print("You've got the following commands to pick from:")
        for c in commands:
            print("   %s" % c)

Just importing readline does quite a bit of the work, transforming input into something you'd expect from normal Unix-like shells. In order to get tab completion, you have to write your own function to do it for you. This is a very simple one, showing basic command completion, using a list of commands. The completer function system is a bit odd. It will keep calling the function with incremented state values until you return a non-string. So, a simple implementation just checks if the state variable is zero and returns the tab completion if available.

The Great Laptop Search
Posted by postfuturist on 2010-10-07 22:15:08

I'm looking for a laptop. I just have a few requirements, and I'm wondering if I can get such a laptop for under $1000. Here are my requirements:

  • Portable: 12" to 14" screen.
  • Quiet.
  • Doesn't run hot. I need to be able to set it on various surfaces without overheating, like my legs.
  • Dual core, 64 bit processor. (I'm not interested in Atom processors)
  • I don't need an optical drive.
  • Mobile internet: 3G internet would be nice
  • SSD. Maybe this is optional, but the fewer spinning parts, the better.
  • Ubuntu Linux compatible
  • Webcam / Microphone
  • Ships with at least 2 GB of RAM, upgradeable to at least 4 GB.
  • Battery life: it's gotta have at minimum 5-6 hours life under normal load, 4 hours playing videos.
Rails Class Notes Available
Posted by postfuturist on 2010-09-30 22:30:16

I'm teaching a Ruby on Rails class this term at the Art Institute of Portland. I wanted to create a place to make my class notes available. Also, I wanted to be able to edit them at any time and to be able to edit them in an easy, simple markup language. My solution was this, create a simple Rails web application that serves up a list of documents which are merely files stored in folder that are written in Markdown syntax. Markdown is nice, because it looks pretty decent as plain text, and converts into decent, simple HTML with bold headings, italicized or bold text or preformatted code blocks as necessary. So, I did it, I put together a simple Rails 3.0 app that accomplishes that exact purpose. It only took about an hour (not counting the time actually spent writing the content.) The code is released under a BSD license and the content will be available under a Creative Commons Share-Alike license. The page is available right now, here: rails.deliciousrobots.com.

I got the Markdown plugins for Vim, which are fantastic and make it downright enjoyable to edit this text. I added Google's prettify to syntax-highlight the code blocks for me. It's the same JavaScript library I use on this blog. Instead of keeping the content in a volatile database, it is tracked through the Git repository. I also made the source available on github. Even if all you want to do is add to or update my content, or fix a bug in the code or add a feature to the web application, you can fork my git repository here : github.com/deliciousrobots/md_docs. Just send me a pull request and I can update my content or code with your changes. Neat, huh?

My Dotfiles Served Up With Git Daemon
Posted by postfuturist on 2010-09-19 18:25:40

I went to GitHub today to make a public mirror of a Git repository I use to track my dot files. You know, the unix configuration files in my home directory. Apparently, GitHub no longer lets me create public repositories on my free account (this was some temporary glitch, the "New Repository" button reappeared the next day). Fortunately, my Git repository is housed on my VPS and Git comes with a server built in that serves up your repositories using the git:// protocol. I have the server managed with supervisord. I created a file called /etc/supervisor/conf.d/gitd.conf:

[program:gitd]
command=/usr/bin/git daemon --base-path=/path/to/my/git/repos

By default, git-daemon serves up your repositories read-only, and only the ones with a file called 'git-daemon-export-ok' in them.

So my dotfiles repository is now available to the public, though this very server here: git://deliciousrobots.com/dotfiles.git . You can clone the repository like this:

$ git clone git://deliciousrobots.com/dotfiles.git

The next thing I would like to do is set up a web interface, so people can browse the repository at their leisure without having to clone it locally. I don't run apache, as a rule, on my VPS, just nginx. So, that might take a little figuring out.

UPDATE : The dotfiles repo is now available directly on GitHub.

Making Vim Awesomer
Posted by postfuturist on 2010-09-18 23:00:15

Right, so Abe Lincoln supposedly said, "Give me six hours to chop down a tree and I will spend the first four sharpening the axe." OK, sure, maybe he said that. Old Abe must have been a software programmer, because we love our tools. We start wars over them. As you probably didn't care to know, I changed employment recently. Let's just say that I moved from Company A to Company B. I realized that my Vim skills are a bit stiff, having built up some bad habits at my previous job. The issue is how much time it takes to get to a file in a directory structure. I was so familiar with the source trees that I knew where everything was most of the time, so I would just hit colon-e-space and then start typing folder names, tab completing them and the name of the file I wanted to edit. That alone is faster than moving to the mouse and just navigating the tree through clicks, but it doesn't really work out for all-new code bases.

Solution 1: Have another bash shell handy, use the unix tool 'find' or grep through file contents with ack, find the file name that way, then open it using the aforementioned 'slow' way. This solution is slow, takes lots of extra keystrokes and context switching.

Solution 2: I had another go with NERDTree. It's basically a file tree navigator plugin for Vim, even uses the mouse if you really want to suck. Trees suck. I used it with the keyboard. It's not bad, and I keep it around if I want to sort of visually explore the code base. It didn't really help me find files any faster. I was still switching to the shell to find them.

Solution 3: Command-T is a Vim plugin designed to emulate TextMate's supposedly magical file finder/opener thingy. Basically, it is magical. You invoke the plugin (it's backslash-t by default) and start typing, it does a fuzzy match on folder and file names to get to the file you want. It's really good. The tricky part is getting it installed. First of all you need the version of vim that has all the scripting extensions installed. On Ubuntu, you can install vim-nox instead of vim-basic. You'll also need the ruby and ruby-devel packages. After that you can pretty much install it like any other Vim plugin, except that you have to build a C component that the Ruby code uses to the fuzzy matching so quickly. Just read the README.

That's the happy ending... Oh, but you wanted more Vim goodness? OK, fair enough, snipMate is another bit of awesome stolen from TextMate and transmitted into the world of Vim. It's just the code snippets functionality. Go check it out, you'll thank me later.