Unity/Coherence for non-virtual PC?

I use a Mac at home and want to have the ability to run PC software. I wish I could use only a Mac, but I still do some development on Windows and I have some weird legacy hardware that can’t be put on/into the Mac but works fine on the ol’ PC. Boot Camp is too disruptive and Parallels or VMWare don’t let me use those strange hardware devices and they are slower than real hardware (which I already have).

For some time I’ve used multiple monitors and have one on the Mac, one on the PC with Synergy. That leaves me with less screen real estate for either machine and I end up using the Mac most of the time anyway.

I would just like to banish my PC to the closet without a head (monitor) and just use it over the network when I need to. VNC and remote desktop (RDP) are great for accessing the banished PC, but it obscures a lot of my beautiful Mac when I am connected. What would make it so much more seamless is having technology like VMWare’s Unity or Parallels' Coherence but against a real, not a virtual, PC. I mean, they did it, it is useful, someone has probably made that, right? Not really…

I tried searching for just a rootless VNC viewer (rootless is what you call it in X windows when you don’t have a background). No luck. Hmm, maybe X is the right track though, since X windows can display any client (application) on a display (server) running anywhere. Yes, I found a great thread of someone looking for just what I was on slashdot. That lead me to find a bunch of discussion by David Fraser and his XOpenWin project that was meant to capture a Window’s application’s display commands and translate them to be displayed on an X server (which the Mac has built in!). He, unfortunately, never got it working, but was beat to it by Sawanaka who made a wrapper using a Microsoft technology called Detours to capture the display of an application and sent it to X using the display layer from a project called PEACE from NetBSD. This project was called cygpeace. Since then, cygwin has changed a lot and has destabilized his code which hasn’t been updated in a few years. I managed to get it to compile with some minor modifications to headers (especially for freetype) and removing a few function prototypes that have changed in Windows. Unfortunately it still didn’t work.

After that long tale of searches, I grew sad and weary, but came to discover that Matthew Chapman had developed an open source client for the Microsoft Remote Desktop/Terminal Services protocol (RDP) called rdesktop. At least I won’t have to use Microsoft’s RDP client (which it turns out isn’t as horrible as it used to be). Is that all the silver lining to this tale? As it happens, no, there exists a fantastic little hack contributed to the community from Cendio called SeamlessRDP. With the help of a small wrapper on the PC, you can display any application’s windows to a remote X server! Perfect! It looks just as good as Coherence (you sometimes see glitches while moving things, but perfectly reasonable).

This is great, except on any normal person’s Windows install you don’t get unlimited RDP connections, so that means you get to run only one application remotely. Arrg, so close.

But wait! These nice fellows at Fontis have a further patch to SeamlessRDP that lets you run more than one application at once! Perfect! A real, usable solution.

I just had one issue, the domain socket they opened from the master rdesktop process had an off-by-one error in the name, this patch should fix the “not a socket” errors that would surely come up if you try this (as of January, 2008).

diff -c seamless.c ../rdesktop/seamless.c
*** seamless.c	2008-01-17 18:57:27.000000000 -0600
--- ../rdesktop/seamless.c	2008-01-11 18:17:19.000000000 -0600
***************
*** 608,614 ****
saun.sun_family = AF_UNIX;
strncpy(saun.sun_path, socket_name, sizeof(saun.sun_path));
unlink(socket_name);
! 	if (bind(sock, (struct sockaddr *) &saun, sizeof(struct
sockaddr_un)) < 0)
{
perror("Error binding to socket: bind");
exit(1);
--- 608,614 ----
saun.sun_family = AF_UNIX;
strncpy(saun.sun_path, socket_name, sizeof(saun.sun_path));
unlink(socket_name);
! 	if (bind(sock, (struct sockaddr *) &amp;saun, strlen(saun.sun_path) +
sizeof(saun.sun_family) + 1) < 0)
{
perror("Error binding to socket: bind");
exit(1);
***************
*** 651,657 ****
/* Connect to server */
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, socket_name);
! 	len = sizeof(saun.sun_family) + strlen(saun.sun_path);
if (connect(s, (struct sockaddr *) &amp;saun, len) < 0)
{
perror("Error connecting to socket: connect");
--- 651,657 ----
/* Connect to server */
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, socket_name);
! 	len = sizeof(saun.sun_family) + strlen(saun.sun_path) + 1;
if (connect(s, (struct sockaddr *) &amp;saun, len) < 0)
{
perror("Error connecting to socket: connect");