Tag Archives: Mac OS X

TT: Uni-directional file synchronization between different hosts with Unison

When you work with at least two computers on the same project on a daily basis you might have a problem. You need to get changed files from host A to host B and vice versa. The problem getting bigger when you work in addition on different operation systems or use more than two hosts. On UNIX/Linux the preferred tool for such a task is Rsync. Unfortunately Rsync synchronize only in one direction, it doesn’t work very well when more than two hosts are involved (and it isn’t really comfortable to set up on Windows) and can’t use a secure communication channel. Another approach is to check-in changed source files into a version control system, like CVS. On host A you check it in and on host B you check it out afterwards. But this means you always need a more or less stable variant of your code, so that other developer can, at least compile, or much better use it. That is not always the case (especially when you leave the office at 11:00 p.m.) and it also doesn’t cover files which aren’t handled by a version control system. Luckily there is a solution for all the problems mentioned which is called Unison. So here comes the second post in the ToolTips series, which covers an easy and portable way for file synchronization.

Installing Unison

Most modern Linux distributions include Unison in their package manage system. On Mac OS X you can use MacPorts. Alternatively you could download a binary version for Mac OS X or Windows here. To prevent surprises and unnecessary trouble it might be a good idea to make sure that every involved system use the same version of Unison. At least on Linux and Mac OS X it is relatively easy to compile Unison from the sources.

Setting up public/private key authentication for ssh

One advantage of Unison over Rsync is that you can use different communication channels for the file transfers. One is ssh. As I always prefer/demand encrypted communication this is a big plus of course. In the default setup you can just use ssh. But for a little bit more comfort I suggest to create a public/private key pair for the authentication.
The following creates public/private keys without a password. Although this is much more easier to use, it should be only used on hosts which are trusted. If you are in doubt, use the normal password approach or even better create a public/private key pair with a password. Create a new public/private key pair with the following command:

user@host-a ~ $ ssh-keygen -t rsa

When you are asked for a password just hit Enter twice. The command creates the private key in ~/.ssh/id_rsa and the public key in ~/.ssh/id_rsa.pub. Now copy the public key to host B:

user@host-a ~ $ scp ~/.ssh/id_rsa.pub host_B:.ssh/authorized_keys

If you already have some public keys on host B, make sure you append the new key and not overwrite the file by the above command. Make the file accessible by the user only with:

user@host-b ~ $ chmod 600 ~/.ssh/authorized_keys

Now you should be able to connect to host B without any interaction needed.

Configuring Unison

Like in the long UNIX tradition, Unison is configured using text files. The files are located in the ~/.unison directory. You can configure more than one synchronization target by choosing a meaningful name. There exists one default target which is configured in the file default.prf. Because I have more than one target I prefer to split the configuration into several files. You can include other project files with the include statement as shown here:

# directory on host a (this is where Unison will be executed)
root       = /mnt/data/projects
# directory on host b (this is the remote host)
root       = ssh://host-b//mnt/data/projects
# which directories to sync?
include projects_files.prf
# options
include options.prf
ignorecase = false
# unison executable on the server
servercmd  = /usr/local/bin/unison

We setup the root directories on both machines, including the configuration file for the project target and some generic option file. We also overwriting the default unison location, because this is a self compiled version. The file options.prf looks like this:

# No staled nfs and mac store files
ignore  = Name .nfs*
ignore  = Name .DS_Store
# options
log     = true
rsrc    = true
auto    = true
#debug   = verbose
#logfile = ~/.unison/unison.log

This just set some generic options which are valid for all my targets. For the specific target projects the file projects_files.prf contains mainly the directories and files which should be ignored:

# No ISOs
ignore    = Path vms/ISO
# Ignore VBox branches
ignore    = Path vbox-*
# No binary output from the other platforms
ignore    = Path vbox*/out/*
# One exception:
ignorenot = Path vbox/out/linux.amd64.additions
# No wine stuff
ignore    = Path vbox*/wine.*
# Tools
ignore    = Name vbox*/tools/{FetchDir,freebsd*,os2*}

So in general, you configure the directory to synchronize and later define directories or files which should be ignored. As you see, you can include or exclude paths as you like. Even simple bash wildcards are possible. As shown in this example I exclude all binary files of a VirtualBox build, because they are useless on another platform. Understanding how Unison decide which directories or files should be synchronized is sometimes difficult. So I suggest to carefully read the documentation and just use the “try and failure” approach ;). Another reason for splitting up the configuration files is you can synchronize these files as well. I have another target which synchronize several configuration files, e.g. .bashrc, .profile, .vim* and the sub-project files of Unison like the projects_files.prf. You can’t synchronize e.g. default.prf, cause the root directories are different from host to host, but the general configuration is always the same. My home target looks like this:

# Which directories/files to sync?
path = .bashrc
path = .ion3
path = .gdbinit
path = .cgdb
path = .valgrind-vbox.supp
path = .vim
path = .vimrc
path = .gvimrc
path = .Xdefaults
path = .gnupg
path = .unison/options.prf
path = .unison/home_files.prf
path = .unison/projects_files.prf
# Do not sync:
ignore = Path .vim/.netrwhist
ignore = Path .ion3/default-session*
ignore = Path .cgdb/readline_history.txt

One of the strengths over other synchronization tools is, you can do this for others host as well. So if you synchronize between host a and host b you can also synchronize between host c and host b. However, a little bit of discipline is necessary. There should be one host which all other host synchronize again.
If you now execute unison the project target will be used. If you execute unison home the files of the home target will be synchronized.

Conclusion

Unison is a very powerful tool. You can synchronize between more than two hosts (OS independent), in a secure way and uni-directional. Currently there is no better tool and I use it on a daily basis.

TT: Console navigation the easy way with Apparix

Today I will start a new series where I present small tools which I use on a daily basis and considered very useful. These tools haven’t to be killer applications, but doing the task they are written for, very well. Therefor also the name of this series: TT, which stands for ToolTips. Most of this applications are open source, so I will take the opportunity to say “Thank you” to all the people out there, which create such cool stuff in there free time.

We start with a tool called Apparix.

Console?

As you may know, I’m a keyboard addict. My preferred OS is Linux, I use Ion3 as the window manager, rxvt-unicode as terminal application and (g)Vim as the preferred editor. On the other side I have a MacBook Pro as laptop and love the possibilities of Mac OS X. How does this come together? Well, all these tools are available on Mac OS X as well. The X11 port of Mac OS X is getting better with each release and using it in fullscreen is good enough. Mac OS X is based on BSD and together with MacPorts, there is nothing I missed until today. As I have to work really platform independent, there is Windows. Vim is available, but working console based (read: command.com) isn’t really much fun. There is of course mingw, but I never managed it to create a work environment like on Linux/UNIX. Anyway, I work not that much on Windows, so I can live with other tools there as well (a really good free editor is Notepad++ and if you hate Explorer have a look at Altap Salamander). So the question remains: Console? I have the feeling using the keyboard within a console application is much faster than clicking around with the mouse. This doesn’t mean I like to type every single character when starting an application or changing the current working directory. Many modern command interpreters, like the Bash, have built in word expansion. This allows you to use the tabulator key for fast expansion of typed characters for a given set of commands. Of course this makes the console life much more easier. But there is more!

Bookmarking important directories

Usually, I’m working on projects. One project is VirtualBox. Other might be some private stuff, like personal letters or other development I do. As the regular user organize his projects in directory trees it make sense to bookmark them. Most people believe bookmarking is something Internet specific, but this isn’t true. Bookmarking means getting access to an important information very fast, without remembering the exact location of this information. This is exactly what Apparix does. It bookmarks directories and make these bookmarks easy accessible on the console. So I have bookmarks for sub-projects within VirtualBox, like the GUI or Main. Getting there is as easy as writing to vgui. It’s the same as writing cd /bin and it even provide word expansion of the available bookmarks. In this case the bookmark is vgui and it expand to the GUI directory within the VirtualBox source tree.

How does this work?

Installing Apparix is pretty simple. You will find all the information on the website. The important part is the integration within your shell. You need to extent your .bashrc. One way is to add the functions you need into .bashrc. Alternatively you can download the file .bash_apparix and source it in your .bashrc. When you have done this and start a new shell, you should navigate to a directory you like to bookmark. There you type bm to create your first bookmark. Afterwards, regardless what your current working directory is, you could execute to DIR_NAME to get there. Of course you can name the bookmark other than the current directory name, by using bm MY_NAME. By executing als all bookmarks are shown. There is much more possible of course. See the documentation for more information. Anyway, this is the main use case for Apparix, so there is not much more to say. Really?

Using the Apparix database for other applications

The cool thing on many Linux applications is, they are saving their data in simple text files. Also Apparix. The bookmark “database” is saved in a file called .apparixrc. It’s a simple text file, which is easy to parse. It looks like this:

j,vbox,/Users/poetzsch/projects/vbox
j,VirtualBox,/Users/poetzsch/projects/vbox/src/VBox/Frontends/VirtualBox
j,Main,/Users/poetzsch/projects/vbox/src/VBox/Main
j,Runtime,/Users/poetzsch/projects/vbox/src/VBox/Runtime
j,Installer,/Users/poetzsch/projects/vbox/src/VBox/Installer/darwin
j,cv,/Users/poetzsch/projects/private/office/latex/cv
j,dow,/Users/poetzsch/Downloads

This allows the usage of this information in other contexts as well. One example is Vim. As I mentioned earlier, this is my main editor. So it would be cool to use the bookmarks, I already have, there as well. To easy change the current directory in Vim, add the following to your .vimrc:

command! -complete=custom,BmCe -nargs=1 To :call BmTo('<args>')
fun BmCe(A,L,P)
 return system("awk 'BEGIN{FS=","}/j,/{print $2}' ~/.apparixrc")
endfun
fun BmLs(dir)
 return system('apparix '.a:dir.' | tr -d "n"')
endfun
fun BmTo(dir)
 execute ':cd '.BmLs(a:dir)
endfun

After restarting Vim, it is possible to navigate with :To MY_BOOKMARK to any directory known by Apparix.

Conclusion

One simple task, getting to a directory where you are often have to be, with one simple solution. Thats all to say about Apparix. It does this in a very simple way, which is fully integrated into the Bash and the saved information could be used by other applications as well.

Adding a badge to the unified toolbar on Mac OS X

Mac OS X and the applications running on it are known for being sometimes unusual in the look and feel. For some reason developer on Mac OS X seems to be more creative than on other platforms. For an application developer which deals with user input it is important to make any user interaction as useful as possible and present this information in a way which is on the one side as much less annoying as possible but also attractive and informative on the other side. Lastly I was thinking about how to show the users they are using a beta version, which should remind them that this is not production ready software, but on the same time make it easy to respond to bugs they find in this pre-release. The solution, I came up with, was a badge in the toolbar which shows this is a release which is definitely in a testing phase, but also allows the user to double-click to give a respond to this particular version. In the following post I will show how to do this.

Getting the superview

In Cocoa all user displayed content is a NSView (most of the time; forget about the Dock). This is really nice, cause you could manipulate them. Although there are no public methods for getting the NSView of the toolbar or even the titlebar, they exist as an NSView. The NSView of the toolbar could be accessed by a private method. As always in Objective C you could ask for a particular method by using the respondsToSelector statement like in the following:

NSToolbar *tb = [pWindow toolbar];
if ([tb respondsToSelector:@selector(_toolbarView)])
{
 NSView *tbv = [tb performSelector:@selector(_toolbarView)];
 if (tbv)
 {
  /* do something with tbv */
 }
}

This return the NSView of the toolbar at least until 10.6. But be warned this is a private method and of course this could be changed in a future version of Mac OS X. At least the shown method will correctly fail in the case Apple change his mind which will result in doing nothing. Anyway this will not include the area of the titlebar. To get the NSView which covers both the title bar and the toolbar you need another trick. The titlebar usual has a close, minimize or maximize button. These buttons are NSButton’s and added by the system depending of the window type. As a NSButton is also a NSView it also has a parent. This dependency allows us to access the view which is responsible for displaying the unified titlebar and the toolbar. The following code shows how to get the responsible view and how to add an additional NSImageView to it:

NSView *wv = [[pWindow standardWindowButton:NSWindowCloseButton] superview];
if (wv)
{
 /* We have to calculate the size of the title bar for the center case. */
 NSSize s = [pImage size];
 NSSize s1 = [wv frame].size;
 NSSize s2 = [[pWindow contentView] frame].size;
 /* Correctly position the label. */
 NSImageView *iv = [[NSImageView alloc] initWithFrame:
        NSMakeRect(s1.width - s.width - (fCenter ? 10 : 0),
                   fCenter ? s2.height + (s1.height - s2.height - s.height) / 2 : s1.height - s.height - 1,
  	           s.width, s.height)];
 /* Configure the NSImageView for auto moving. */
 [iv setImage:pImage];
 [iv setAutoresizesSubviews:true];
 [iv setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
 /* Add it to the parent of the close button. */
 [wv addSubview:iv positioned:NSWindowBelow relativeTo:nil];
}

This code needs a NSWindow, a NSImage as label and the flag fCenter for deciding if the image is vertically centered within the titlebar. Also the badge is pinned on the right side by setting the AutoresizingMask. The following shows how this could be look like:

Adding functionality to the badge

First we should add some information about this release by using the setToolTip method of an NSView. Simply add this call to the code:

 [iv setToolTip:@"Some info about the beta version."];

To make this beta hint more useful, we should make it clickable. Getting mouse down events in Cocoa is only possible by handling the mouseDown event of the NSResponder sub-class. Also the view must accept first responder events. How to do this is shown in the following code:

@interface BetaImageView: NSImageView
{}
- (BOOL)acceptsFirstResponder;
- (void)mouseDown:(NSEvent *)pEvent;
@end
@implementation BetaImageView
- (BOOL)acceptsFirstResponder
{
 return YES;
}
- (void)mouseDown:(NSEvent *)pEvent
{
 if ([pEvent clickCount] > 1)
  [[NSWorkspace sharedWorkspace] openURL:
        [NSURL URLWithString:@"http://www.virtualbox.org/"]];
 else
  [super mouseDown:pEvent];
}
@end

Replace NSImageView with BetaViewImage in the allocation call in listing 2 and you are done. Change the URL to one where the user can respond to the beta questions, like a bug tracker or forum.

Conclusion

This post showed how to add an nice looking badge to the unified toolbar on Mac OS X. The user is reminded he is using some pre-release software all the time, but at the same time has an easy way to report problems with this release. Of course could such a badge used for anything else.

Creating file shortcuts on three different operation systems

As you may know, developing for multiple platforms is one of my strengths. Strictly speaking, it’s a basic requirement if you are involved in such a product like VirtualBox, which runs on every major (and several minor) platform available today. Beside the GUI, which uses Qt and therewith is portable without any additional cost (which isn’t fully true if you want real native look and feel on every platform, especially on Mac OS X), all the rest of VirtualBox is written in a portable way. This is done by using only C/C++ and Assembler when necessary. Everything which needs a different approach, because of the design of the OS (and the API’s which are available there), is implemented in a platform dependent way. In the history of VirtualBox, several modules are created and grown by the time, which makes it really easy to deal with this differences. For stuff like file handling, paths, strings, semaphores or any other basic functionality, you can just use the modules which are available. On the other side it might be necessary, for a new feature we implement, to write it from the ground. In the following post I will show how to create a file shortcut for the three major operation systems available today.

Why do you want to use file shortcuts

On the classical UNIX systems you have hard and soft links. These are implemented by the filesystem and make it possible to link to another file or folder without any trouble. Most of the time soft links are used, but it really depends on the use case. Unfortunately these kind of links are not available on Windows (yes, I know there are also hard links and junctions on NTFS, but they are not common and difficult to handle), these links doesn’t allow any additional attributes. For example one like to add a different icon to the link or provide more information through a comment field. Beside on Mac OS X, shortcuts can also be work as an application launcher, where the link contain the information what application should be started and how. In contrast to filesystem links which are handled by the operation system, these shortcuts are handled by the window system (or shell) running on the host (which doesn’t mean there is no filesystem support for it). On Windows this is the Explorer, on Mac OS X the Finder and on Linux a freedesktop.org conforming file manager.

Creating a Desktop file on Linux

Desktop files on Linux (or any other UNIX system which conforms to freedesktop.org) is easy. It’s a simple text file which implement the Desktop Entry Specification. In version 1.0 there are 18 possible entries, where not all of them are mandatory. In the following example I use Qt to write these files, but it should be no problem to use any other toolkit or plain C.

bool createShortcut(const QString &strSrcFile,
                    const QString &strDstPath,
                    const QString &strName)
{
 QFile link(strDstPath + QDir::separator() + strName + ".desktop");
 if (link.open(QFile::WriteOnly | QFile::Truncate))
 {
  QTextStream out(&link);
  out.setCodec("UTF-8");
  out << "[Desktop Entry]" << endl
      << "Encoding=UTF-8" << endl
      << "Version=1.0" << endl
      << "Type=Link" << endl
      << "Name=" << strName << endl
      << "URL=" << strSrcFile << endl
      << "Icon=icon-name" << endl;
  return true;
 }
 return false;
}

Replace icon-name by a registered icon on the system and you are done.

Creating a Shell link on Windows

Windows provides an interface for IShellLink since Windows XP. The following example shows how to use it:

bool createShortcut(LPCSTR lpszSrcFile,
                    LPCSTR lpszDstPath,
                    LPCSTR lpszName)
{
 IShellLink *pShl = NULL;
 IPersistFile *pPPF = NULL;
 HRESULT rc = CoCreateInstance(CLSID_ShellLink,
                               NULL,
                               CLSCTX_INPROC_SERVER,
                               IID_IShellLink,
                               (void**)(&pShl));
 if (FAILED(rc))
  return false;
 do
 {
  rc = pShl->SetPath(lpszSrcFile);
  if (FAILED(rc))
   break;
  rc = pShl->QueryInterface(IID_IPersistFile, (void**)&pPPF);
  if (FAILED(rc))
   break;
  WORD wsz[MAX_PATH];
  TCHAR path[MAX_PATH] = { 0 };
  lstrcat(path, lpszDstPath);
  lstrcat(path, "\");
  lstrcat(path, lpszName);
  lstrcat(path, ".lnk");
  MultiByteToWideChar(CP_ACP, 0, buf, -1, wsz, MAX_PATH);
  rc = pPPF->Save(wsz, TRUE);
 } while(0);
 if (pPPF)
  pPPF->Release();
 if (pShl)
  pShl->Release();
 return SUCCEEDED(rc);
}

As you may noticed this uses COM. Many API’s on Windows using the COM interface to communicate between processes. If you don’t use COM in your application you have to initialize it first. This is achieved by adding the following call to the front of the function:

 if (FAILED(CoInitialize(NULL))
  return false;

Depending on your application it might be worth to unitialize COM after usage by appending the following to the function:

 CoUninitialize();

The function itself isn’t any magic. It gets a COM interface to the IShellLink interface and then work with it, by setting the source path and adding a target path by using the IPersistFile interface. As I wrote before you could do much more. Providing a path to a specific application or adding your own parameters is no problem. Have a look at the documentation.

Creating an Alias file on Mac OS X

Shortcut files on Mac OS X are a little bit different. At first, they aren’t one. There are the classical filesystem links and Alias files. Alias files are links which targeting a specific file, but they haven’t all the possibilities of shortcuts like on Windows or Linux. As the name suggest they are really only an alias for another file or directory. So specifying an application to start or things like that aren’t possible. Anyway they allow changing the icon and they are more persistent than on Window or Linux cause they are working with several attributes of the target file. Even if you rename or move the target, an Alias file will resolve the target correctly (if it is possible). On the other side, being such special means also being hard to create. In principle there are two possibilities. The first one is, creating a file which is no file at all, but has several resources forks attached. Therefor you need to know exactly how Alias files are built of and make sure with every release of Mac OS X you are following the development. There is a free project which does exactly that: NDAlias. If you are like me and a little bit more lazy, you ask someone who should know how to create Alias files. This is Finder. Although writing the files itself isn’t easy, asking the Finder to do the job is not really easier, cause the information about doing exactly that are really rare. The following code shows how to achieve it:

bool createShortcut(NSString *pstrSrcFile,
                    NSString *pstrDstPath,
                    NSString *pstrName)
{
 /* First of all we need to figure out which process Id the Finder
  * currently has. */
 NSWorkspace *pWS = [NSWorkspace sharedWorkspace];
 NSArray *pApps = [pWS launchedApplications];
 bool fFFound = false;
 ProcessSerialNumber psn;
 for (NSDictionary *pDict in pApps)
 {
  if ([[pDict valueForKey:@"NSApplicationBundleIdentifier"]
         isEqualToString:@"com.apple.finder"])
  {
   psn.highLongOfPSN = [[pDict
                          valueForKey:@"NSApplicationProcessSerialNumberHigh"] intValue];
   psn.lowLongOfPSN  = [[pDict
                          valueForKey:@"NSApplicationProcessSerialNumberLow"] intValue];
   fFFound = true;
   break;
  }
 }
 if (!fFFound)
  return false;
 /* Now the event fun begins. */
 OSErr err = noErr;
 AliasHandle hSrcAlias = 0;
 AliasHandle hDstAlias = 0;
 do
 {
  /* Create a descriptor which contains the target psn. */
  NSAppleEventDescriptor *finderPSNDesc = [NSAppleEventDescriptor
                                            descriptorWithDescriptorType:typeProcessSerialNumber
                                            bytes:&psn
                                            length:sizeof(psn)];
  if (!finderPSNDesc)
   break;
  /* Create the Apple event descriptor which points to the Finder
   * target already. */
  NSAppleEventDescriptor *finderEventDesc = [NSAppleEventDescriptor
                                              appleEventWithEventClass:kAECoreSuite
                                              eventID:kAECreateElement
                                              argetDescriptor:finderPSNDesc
                                              returnID:kAutoGenerateReturnID
                                              transactionID:kAnyTransactionID];
  if (!finderEventDesc)
   break;
  /* Create and add an event type descriptor: Alias */
  NSAppleEventDescriptor *osTypeDesc = [NSAppleEventDescriptor descriptorWithTypeCode:typeAlias];
  if (!osTypeDesc)
   break;
  [finderEventDesc setParamDescriptor:osTypeDesc forKeyword:keyAEObjectClass];
  /* Now create the source Alias, which will be attached to the event. */
  err = FSNewAliasFromPath(nil, [pstrSrcFile fileSystemRepresentation], 0, &hSrcAlias, 0);
  if (err != noErr)
   break;
  char handleState;
  handleState = HGetState((Handle)hSrcAlias);
  HLock((Handle)hSrcAlias);
  NSAppleEventDescriptor *srcAliasDesc = [NSAppleEventDescriptor
                                           descriptorWithDescriptorType:typeAlias
                                           bytes:*hSrcAlias
                                           length:GetAliasSize(hSrcAlias)];
  if (!srcAliasDesc)
   break;
  [finderEventDesc setParamDescriptor:srcAliasDesc
    forKeyword:keyASPrepositionTo];
  HSetState((Handle)hSrcAlias, handleState);
  /* Next create the target Alias and attach it to the event. */
  err = FSNewAliasFromPath(nil, [pstrDstPath fileSystemRepresentation], 0, &hDstAlias, 0);
  if (err != noErr)
   break;
  handleState = HGetState((Handle)hDstAlias);
  HLock((Handle)hDstAlias);
  NSAppleEventDescriptor *dstAliasDesc = [NSAppleEventDescriptor
                                           descriptorWithDescriptorType:t ypeAlias
                                           bytes:*hDstAlias
                                           length:GetAliasSize(hDstAlias)];
  if (!dstAliasDesc)
   break;
  [finderEventDesc setParamDescriptor:dstAliasDesc
    forKeyword:keyAEInsertHere];
  HSetState((Handle)hDstAlias, handleState);
  /* Finally a property descriptor containing the target
   * Alias name. */
  NSAppleEventDescriptor *finderPropDesc = [NSAppleEventDescriptor recordDescriptor];
  if (!finderPropDesc)
   break;
  [finderPropDesc setDescriptor:[NSAppleEventDescriptor descriptorWithString:pstrName]
    forKeyword:keyAEName];
  [finderEventDesc setParamDescriptor:finderPropDesc forKeyword:keyAEPropData];
  /* Now send the event to the Finder. */
  err = AESend([finderEventDesc aeDesc],
               NULL,
               kAENoReply,
               kAENormalPriority,
               kNoTimeOut,
               0,
               nil);
 } while(0);
 /* Cleanup */
 if (hSrcAlias)
  DisposeHandle((Handle)hSrcAlias);
 if (hDstAlias)
  DisposeHandle((Handle)hDstAlias);
 return err == noErr ? true : false;
}

Although the code above looks a little bit scary, it does not much. It fetch the process serial number of the current Finder process, creates an Application event for creating an Alias file and send this event to the Finder.

Conclusion

Beside showing how to create file shortcuts on different platforms, this article also shows which work is necessary to create platform independent code. It’s a simple example. But it also makes clear that one simple solution for platform one, not necessarily mean it’s such simple on platform two.

Making this easy accessible to any developer is the next step. I will leave this exercise to the reader, but have a look at the platform code of the VirtualBox GUI and the corresponding Makefile.

Understanding some of the mysteries of launchd

Have you ever wondered how Mac OS X knows which file type belongs to which application? On Windows there is the registry. An installer writes the necessary info into it. Most applications on Mac OS X doesn’t come with an installer, they are just moved from the downloaded DMG file to the /Applications folder. So a developer doesn’t have the ability to take action when the user “install” the application. Anyway there is no need to provide an installer for just this task, cause Mac OS X register file type associations on the first start of the application. In the following post, I will show how to do this, but furthermore I will show where this information is stored and how it could be reseted.

Providing the necessary information to Mac OS X

Applications on Mac OS X need some defined structure. They are so-called bundles, which means on the filesystem layer they are directories. You can prove this by checking the Applications directory within the Terminal.app. You could also right-click on an application and select “Show Package Contents”. The content of the bundle directory is usually hidden from the user when he works with the Finder or any other high level function of Mac OS X (like the open dialog). Additional to this layout on the filesystem, an application provide information about itself to the system with a plist file. This file has to be named Application.app/Content/Info.plist. The following shows exemplary the content of the Tunnelblick application:

<xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>CFBundleDevelopmentRegion</key>     <string>English</string>
 <key>CFBundleExecutable</key>            <string>Tunnelblick</string>
 <key>CFBundleIconFile</key>              <string>tunnelblick.icns</string>
 <key>CFBundleIdentifier</key>            <string>com.openvpn.tunnelblick</string>
 <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
 <key>CFBundlePackageType</key>           <string>APPL</string>
 <key>CFBundleShortVersionString</key>    <string>3.1beta20 (build 2132)</string>
 <key>CFBundleSignature</key>             <string>OVPN</string>
 <key>CFBundleVersion</key>               <string>2132</string>
 <key>NSMainNibFile</key>                 <string>MainMenu</string>
 <key>NSPrincipalClass</key>              <string>NSApplication</string>
 <key>NSUIElement</key>                   <string>1</string>
 <key>SUEnableSystemProfiling</key>       <true/>
 <key>SUFeedURL</key>                     <string>http://tunnelblick.net/appcast.rss</string>
 <key>SUPublicDSAKeyFile</key>            <string>dsa_pub.pem</string>
</dict>
</plist>

The keys are mostly self explaining, you can find a full list here.

To register a file type association you have to add an array of the type CFBundleDocumentTypes. Again, here is an extraction of the Tunnelblick application, which shows the registration of the tblk extension:

 <key>CFBundleDocumentTypes</key>
 <array>
  <dict>
   <key>CFBundleTypeExtensions</key>   <array><string>tblk</string></array>
   <key>CFBundleTypeIconFile</key>     <string>tunnelblick_package.icns</string>
   <key>CFBundleTypeName</key>         <string>Tunnelblick VPN Configuration</string>
   <key>CFBundleTypeRole</key>         <string>Editor</string>
   <key>LSTypeIsPackage</key>          <true/>
   <key>NSPersistentStoreTypeKey</key> <string>Binary</string>
  </dict>
 </array>

You have to provide a file extension or mime-type, can add an icon and give a hint what your application can do with this type of file (viewer, editor or nothing).

Beside this passive way of announcing this information, there is also an active way (e.g. for use in an installer). See here for further information.

Where is this information stored

Although Mac OS X hasn’t a registry like windows, some information are stored in global databases, too. Applications are registered at the launchd. The launchd is the central place for starting all kind of programs, from a background service to any common application, like Thunderbird. E.g. background services can register itself and even made their start depending on different events. VirtualBox has an example configuration included, which let launchd start the vbox webservice on activity on a certain port. Although this isn’t used by many users out there (and therefore disabled by default), it shows some generic usage of this functionality.

If you look around in Mac OS X you have the tool launchctl, which allows you to start jobs or register background services with launchd. But it seems there is no tool which is able to get some information about the knowledge of launchd. Well, there is one. It’s a little bit hidden in /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister. To be more comfortable with it, we should include it into the user path by linking it to a known path, like this:

sudo ln -s /Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister /usr/local/bin/lsregister

With this tiny tool we are able to dump the launchd database. lsregister -dump | grep -n10 Tunnelblick displays something like this for Tunnelblick:

10823---------------------------------------------------------------------------------
10824-bundle    id:            6984
10825:  path:          /Applications/Tunnelblick.app
10826-  name:
10827-  identifier:    com.openvpn.tunnelblick (0x800097b8)
10828-  version:       2132
10829-  mod date:      10/31/2010 12:37:08
10830-  reg date:      11/19/2010 11:13:39
10831-  type code:     'APPL'
10832-  creator code:  'OVPN'
10833-  sys version:   0
10834-  flags:         relative-icon-path  ui-element
10835-  item flags:    container  package  application  extension-hidden  native-app  ppc  i386
10836-  icon:          Contents/Resources/tunnelblick.icns
10837:  executable:    Contents/MacOS/Tunnelblick
10838-  inode:         3800129
10839-  exec inode:    3800213
10840-  container id:  32
10841-  library:
10842-  library items:
10843-  --------------------------------------------------------
10844-  claim   id:            17864
10845:          name:          Tunnelblick VPN Configuration
10846-          rank:          Default
10847-          roles:         Editor
10848-          flags:         relative-icon-path  package
10849-          icon:          Contents/Resources/tunnelblick_package.icns
10850-          bindings:      .tblk
10851---------------------------------------------------------------------------------

As you see, all the information provided by the plist file is registered. Beside other information, it also has the registration and modification times stored. To let launchd reread the plist file, usual its only necessary to change the modification time of the application. This could be done by simply executing touch /Applications/Application.app. Anyway, it’s sometimes necessary to reset the content of this database for the own application. This could be done by executing the following:

lsregister -u /Applications/Application.app

To register the application again, just remove the -u parameter. You should also check if your application isn’t registered more than once, with different paths, by using the -dump parameter. To fully reset the launchd database, you could use -kill. This will remove any file type association and registered application. You have been warned.

Conclusion

This article shows how Mac OS X handle informations about installed applications. With this knowledge a developer is able to register the own application into the launchd ecosystem and see how launchd interpret this information. Furthermore, the usage of lsregister allows a developer to analyze the content of the launchd database and make changes to it.

Using suppression files with Valgrind

Valgrind is one of the great tools in the long list of freely available applications for development. Beside several profiling tools it also contains a memory checker. Leaking memory is one of the more common errors a programmer could step into. Basically it means to forget freeing memory (or in a more general sense: any resource) a program has acquired. If you are a perfect developer, this will never happen to you. If you are a good developer it may happen and that’s where Valgrind will save you some trouble. As most of the developers out there are more or less good developers, their programs produce memory leaks, too ;). The right solution for this, is of course to write a bug report. But there are times where this isn’t possible or you are in hurry and don’t want to see all the errors of a third-party library you link against.

In the following post, I will show how to suppress such unwanted error messages to make it much more easier to analyze the output of Valgrind for your own application.

Installing Valgrind

On Mac OS X you can use MacPorts to install Valgrind. You have to use valgrind-devel if you are on Snow Leopard, because Snow Leopard is supported in the current development version only. It’s as simply as typing sudo port install valgrind-devel.

On Gentoo it can become a bit harder. The current stable version is 3.5 (like in MacPorts). If you try this version (at least on an unstable Gentoo like mine) with valgrind ls, you will get the following error:

valgrind:  Fatal error at startup: a function redirection
valgrind:  which is mandatory for this platform-tool combination
valgrind:  cannot be set up.  Details of the redirection are:
valgrind:
valgrind:  A must-be-redirected function
valgrind:  whose name matches the pattern:      strlen
valgrind:  in an object with soname matching:   ld-linux-x86-64.so.2
valgrind:  was not found whilst processing
valgrind:  symbols from the object with soname: ld-linux-x86-64.so.2
valgrind:
valgrind:  Possible fixes: (1, short term): install glibc's debuginfo
valgrind:  package on this machine.  (2, longer term): ask the packagers
valgrind:  for your Linux distribution to please in future ship a non-
valgrind:  stripped ld.so (or whatever the dynamic linker .so is called)
valgrind:  that exports the above-named function using the standard
valgrind:  calling conventions for this platform.
valgrind:
valgrind:  Cannot continue -- exiting now.  Sorry.

The reason is a striped glibc. To work properly, Valgrind needs to overwrite some of the system functions the glibc provide. It does this by getting the symbols by name out of this library. This is of course not possible if all the symbol names are removed. You can prove this by executing nm /lib/ld-linux-x86-64.so.2. Gentoo provides a FEATURE=splitdebug, which adds debug libraries to the installation. Unfortunately setting this feature in /etc/make.conf, means setting it global. Gentoo is known as being configurable as no other distribution out there and of course we can set a feature for one program only. To do so, create a file called glibc in /etc/portage/env/sys-libs/ and add the following content to it.

FEATURES="splitdebug"

After a rebuild of glibc by executing emerge --oneshot glibc, we have a working Valgrind.

As all programs, Valgrind isn’t perfect. Version 3.5 shows many false/positive hits on my system, but fortunately the development goes on. Currently there is no newer version available in the Gentoo tree. Anyway it is not necessary to build one yourself, to get a more recent version. Using layman and the overlay tree of Flameeyes will let you integrate the development version of Valgrind seamlessly into your system. For a general How-to of layman check out this Users’ guide. In short, something like the following should be sufficient:

layman -a flameeyes-overlay
layman -s flameeyes-overlay
echo "=dev-util/valgrind-9999 **" >> /etc/portage/package.keywords
emerge valgrind

Installing the development version of Valgrind is optional of course.

Know your tools

One usage of Valgrind could be look like this:

valgrind --leak-check=full --leak-resolution=high ./VirtualBox

Beside other errors it also shows this error message on my system:

==27174==    at 0x4C26C09: memalign (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==27174==    by 0x4C26CB9: posix_memalign (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==27174==    by 0xBA8967F: ??? (in /usr/lib64/libglib-2.0.so.0.2400.2)
==27174==    by 0xBA89E9D: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2400.2)
==27174==    by 0xBA89F86: g_slice_alloc0 (in /usr/lib64/libglib-2.0.so.0.2400.2)
==27174==    by 0xC204847: g_type_create_instance (in /usr/lib64/libgobject-2.0.so.0.2400.2)
==27174==    by 0xC1EB8A5: ??? (in /usr/lib64/libgobject-2.0.so.0.2400.2)
==27174==    by 0xC1ECE5D: g_object_newv (in /usr/lib64/libgobject-2.0.so.0.2400.2)
==27174==    by 0xC1ED494: g_object_new (in /usr/lib64/libgobject-2.0.so.0.2400.2)
==27174==    by 0x72A495F: ??? (in /usr/lib64/qt4/libQtGui.so.4.6.3)
==27174==    by 0x72A0D4F: ??? (in /usr/lib64/qt4/libQtGui.so.4.6.3)
==27174==    by 0x7289264: QGtkStyle::QGtkStyle() (in /usr/lib64/qt4/libQtGui.so.4.6.3)
==27174==    by 0x7215DB6: QStyleFactory::create(QString const&) (in /usr/lib64/qt4/libQtGui.so.4.6.3)
==27174==    by 0x6F5B7FC: QApplication::style() (in /usr/lib64/qt4/libQtGui.so.4.6.3)
==27174==    by 0x6F61DFF: QApplicationPrivate::initialize() (in /usr/lib64/qt4/libQtGui.so.4.6.3)
==27174==    by 0x6F61E88: QApplicationPrivate::construct(_XDisplay*, unsigned long, unsigned long) (in /usr/lib64/qt4/libQtGui.so.4.6.3)
==27174==    by 0x6F61FF3: QApplication::QApplication(_XDisplay*, int&, char**, unsigned long, unsigned long, int) (in /usr/lib64/qt4/libQtGui.so.4.6.3)
==27174==    by 0x44BC38: TrustedMain (main.cpp:371)
==27174==    by 0x44C649: main (main.cpp:651)

If you analyze the backtrace, you see that something in libQtGui is leaking memory. I don’t want to blame someone for it or make a statement if this is right or wrong, I just want to get rid of it, to be able to easily spot errors VirtualBox itself produce. To do so, add --gen-suppressions=all to the Valgrind call. This will produce something similar like this:

{
 Memcheck:Leak
 fun:memalign
 fun:posix_memalign
 obj:/usr/lib64/libglib-2.0.so.0.2400.2
 fun:g_slice_alloc
 fun:g_slice_alloc0
 fun:g_type_create_instance
 obj:/usr/lib64/libgobject-2.0.so.0.2400.2
 fun:g_object_newv
 fun:g_object_new
 obj:/usr/lib64/qt4/libQtGui.so.4.6.3
 obj:/usr/lib64/qt4/libQtGui.so.4.6.3
 fun:_ZN9QGtkStyleC1Ev
 fun:_ZN13QStyleFactory6createERK7QString
 fun:_ZN12QApplication5styleEv
 fun:_ZN19QApplicationPrivate10initializeEv
 fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm
 fun:_ZN12QApplicationC1EP9_XDisplayRiPPcmmi
 fun:TrustedMain
 fun:main
}

To let Valgrind ignore this error in the future, copy the text into a file vbox.supp and start Valgrind with --suppressions=vbox.supp. Viola, this specific error isn’t shown anymore. The format used there is easy to understand and you can of course tweak this much more. E.g. you could replace some of the fun: entries by “...“. This is a placeholder for one or more functions calls with any name. Beside making suppression rules more general you can of course add as much as you like. Adding a name at the top make it easy to identify the different rules. For all the possibilities have a look at the documentation. Just for the curious, Valgrind is using such a file itself. Have a look at /usr/lib/valgrind/default.supp. You may also have noted that the function names in the normal error message differ from the one in the suppression list. The former is in the demangled form and the later in the saved form. You could force Valgrind to print mangled function names by adding the --demangle=no parameter to the call. This becomes handy if you manually create suppression lists.

Conclusion

By using suppression rules for the own application, unimportant errors could be eliminated in the output of Valgrind. With this is in mind there is no excuse anymore for memory leaks in the self developed applications. Beside memory leaks, Valgrind also finds places where uninitialized variables are in use or where memory is used which isn’t allocated by the application. Also these tests could be filtered out by suppression rules.

Changing the default behavior of built-in Cocoa controls

Apple has many task specific controls built into Cocoa. They are all well designed and have most of the functionality a user and a developer expect. One of this controls is the NSSearchField. This control has a special design which allows the user to recognize the provided functionality with ease. It is so well-known that Apple uses the design even on there website. It has support for menus (e.g. for recent search items), auto completion, a cancel button, and so one. Although this is mostly feature complete, there are sometimes cases where you like to extend it. In this post, I will show how to add another visual hint to this control when a search term isn’t found. The aim is to change the background of the underlying text edit to become light red to visual mark the failed search.

Understanding how Cocoa works

The NSSearchField class inherits from an NSControl. NSControls are responsible for the interaction with the user. This implies displaying the content in a NSView, reacting to user input like mouse or keyboard events and sending actions to other objects in the case the status of the control has changed. Usually a control delegate the first two tasks to a NSCell. The main reasons for this are to persist on good performance even if there are many cells of the same type (like in the case of a table) and to be able to exchange the behavior of the control easily (like in the case of a combobox which also allow typing in a text field). With this information in mind we know that we need to overwrite the drawing routine of the cell (NSSearchFieldCell) to achieve our goal. The implementation is straight forward and shown in the following:

@interface MySearchFieldCell: NSSearchFieldCell
{
  NSColor *m_pBGColor;
}
- (void)setBackgroundColor:(NSColor*)pBGColor;
@end

@implementation MySearchFieldCell
-(id)init
{
  if (self = [super init])
    m_pBGColor = Nil;
  return self;
}
- (void)setBackgroundColor:(NSColor*)pBGColor
{
  if (m_pBGColor != pBGColor)
  {
    [m_pBGColor release];
    m_pBGColor = [pBGColor retain];
  }
}
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
  if (m_pBGColor != Nil)
  {
    [m_pBGColor setFill];
    NSRect frame = cellFrame;
    double radius = MIN(NSWidth(frame), NSHeight(frame)) / 2.0;
    [[NSBezierPath bezierPathWithRoundedRect:frame
          xRadius:radius yRadius:radius] fill];
  }
  [super drawInteriorWithFrame:cellFrame inView:controlView];
}
@end

The user can set a custom background color by using setBackgroundColor. Also it is possible to reset the background color by passing Nil to this method. The method drawInteriorWithFrame draws a rounded rectangle on the background and forwards the call to the super class afterward.

Replacing the cell class of a control

The next step is tell the control to use our own cell class and not the default one. Although there is a setCell method defined in NSControl it is not as easy as one might think. Creating an instance of MySearchFieldCell and passing it to setCell after the NSSearchField is created will not have the expected effect. The reason for this comes from the fact that the cell is initialized when the control is created. This includes setting all properties and targets for the actions. If one replaces the cell afterward these setting will be get lost. Later on, I will show a method how to keep this configuration, but for now we will start with an easier approach.

When the control creates a cell object it asks a static method for the class name to use. This method is called cellClass. If we overriding this method with our own one, we are able to return MySearchFieldCell. The following code demonstrates this:

@interface MySearchField: NSSearchField
{}
@end

@implementation MySearchField
+ (Class)cellClass
{
  return [MySearchFieldCell class];
}
@end

Now, if you use MySearchField instead of NSSearchField when creating search fields, you are done. Unfortunately this isn’t always possible. First you may not be able to inherit from NSSearchField for whatever reason and second this will not work when you are use the Interface Builder (IB) from Xcode. There you can’t easily use your own version of NSSearchField, but you have to stick with the original one. Before we proceed the obligatory screenshot:

The power of Archives

What we need is a method of setting our own cell class even when the control is already instantiated. In Cocoa it is possible to Archive and Serialize any object which implements the NSCoding protocol. Archiving means that the whole class hierarchy, with all properties and connections, is saved into a stream. Xcode makes heavy use of this in the nib file format where all the project data of the IB is written in. This alone doesn’t help us much, but additional to the archiving and unarchiving work, it is possible to replace classes in the decoding step. The relevant classes are NSKeyedArchiver and NSKeyedUnarchiver. NSKeyedUnarchiver has a method setClass:forClassName which allow this inline replacement and the following code shows how to use it:

NSSearchField *pSearch = [[NSSearchField alloc] init];
/* Replace the cell class used for the NSSearchField */
[NSKeyedArchiver setClassName:@"MySearchFieldCell"
      forClass:[NSSearchFieldCell class]];
[pSearch setCell:[NSKeyedUnarchiver
      unarchiveObjectWithData: [NSKeyedArchiver
        archivedDataWithRootObject:[pSearch cell]]]];
/* Get the original behavior back */
[NSKeyedArchiver setClassName:@"NSSearchFieldCell"
      forClass:[NSSearchFieldCell class]];

Basically this creates an archive of the current NSSearchFieldCell of the NSSearchField, which is instantly unarchived, but with the difference that the NSSearchFieldCell class is replaced by MySearchFieldCell. Because the archiving preserve all settings the new created class will have the same settings like the old one. The last call to NSKeyedArchiver will restore the default behavior.

Conclusion

This post should have removed some of the mysteries of the control and cell relationship in Cocoa. Additional to a simple derivation approach, a much more advanced way for setting the cell of a control was shown. This allows the replacement of any class hierarchy without loosing any runtime settings. If you need such replacements much more often or working with the IB, you should have a look at Mike’s post which shows a more generic way of the archive/unarchive trick.

Installing Linux on a USB hard disk for the MacBook Pro

One of the features of Mac OS X I love, is the possibility to install Mac OS X on any attached removable media, like a FireWire or USB hard disk. This makes it really easy for me to test VirtualBox on the several versions of Mac OS X we support (formerly Tiger, now Leopard and Snow Leopard). The advantage of this setup is that I don’t waste disk space for operation systems I usually don’t use very often. Currently I have a 150GB hard disk in my MacBook Pro which is really not that much if you deal in the virtualization business. There are several test VM’s of any kind of guest operation systems and of course the ISO’s to install them. The second main OS, I do much of my work, is Linux. For this I have a standard PC with Gentoo on it, which have all that I need. Unfortunately this doesn’t really help when I on travel. As I soon be away for some time, I decided I need, at least for testing, the same flexibility mentioned above for a Linux installation. And here the problems start to arise. Of course Apple didn’t really support installing other OS’s than Mac OS X on Apple hardware. Yes, there is Boot Camp, but this is mainly for Windows, is very inflexible and doesn’t really help if you try to install something on another place than the integrated hard disk. There are projects like rEFIt, which even makes Boot Camp superfluous, but this project has really bad USB boot support. In the following I will explain how it is even possible to install Ubuntu 9.10 on a USB hard disk.

The hardware used, as already said, is a MacBook Pro 3,1 and a Western Digital My Passport Essential 500GB USB hard disk. Other combination may work, but I don’t guarantee this, as always. Also you should be warned that anything I describe here could destroy your existing installation and I’m not responsible for that. Doing some kind of backup might be a good idea. Time Machine is easy to use ;).

Before we start, as usual, the credits for some sites I get my information from. This is mainly the Produnis blog, the Blog of Chris, the Ubuntu wiki and of course the guys around the Grub2 development.

Creating the EFI boot loader

Apple doesn’t use the legacy BIOS to boot their machines, they use the Extensible Firmware Interface (EFI). This new way of booting operation systems is very flexible, as the name suggest, but has several drawbacks, like most of the standard operation system doesn’t speaks it language. Although Linux can be configured to use EFI directly we will emulate a legacy BIOS in the following. For this we need a connector which makes EFI and Linux happy and let them both work smoothly together. This connector is Grub2, which is in development for several years now. It’s the successor of Grub and is the standard in many popular Linux distributions these days. We have to build a version our self, for which an existing Linux installation is really helpful. I used my 64-bit Gentoo installation. First you have to find out if the EFI installation on your target Apple machine is 64 or 32-bit. You can do this by executing:

ioreg -l -p IODeviceTree | grep firmware-abi

This will return EFI64 or EFI32 respectively. In my case I need the 64-bit version, which is a little bit surprising when I consider that my MacBook Pro isn’t able to boot a 64-bit Snow Leopard. Anyway, grab the latest version of Grub2 and unpack it on the Linux machine. Please note that you need a gcc with multilib support if you are targeting an architecture which isn’t the same as the host one. Use the following to configure Grub2 and to build it. Of course you have to adjust the target architecture if it is a different one.

./configure --with-platform=efi --target=x86_64 --disable-werror
make

When this is finished you create the EFI package by executing

./grub-mkimage -d . -o bootx86.efi *.mod

Here I included all modules which are available. If size matter for you, you could of course make a selective choice on the modules included. I didn’t test this myself, so you have to find out yourself which one are important.

Whipping the USB hard disk into shape

Next we have to prepare the USB hard disk for the new installation. In the following I assume your USB hard disk doesn’t contain any valid data and could be reformatted without data lose. Make a backup of your data first if this isn’t the case on your side. Apple uses the GUID Partition Table scheme to organize their partitions on a hard disk. This specification is part of EFI and remove many limitations of the Master boot record (MBR) scheme, which is widely used in the PC world. That is e.g. the disk size limitation of 2TB or the maximum of 4 primary partitions. You reformat your disk, using the Disk Utility application of Mac OS X. Make sure all existing partitions on the disk are unmounted. When necessary, change the partition scheme from MBR to GUID in the Options dialog of the Partitions window. Select the partitions count you want to use. You need at least 3 partitions to make Linux works fine. My partition scheme looks like in the following: As you can see I have 5 partitions configured. The first one is an additional Snow Leopard installation for testing. I also added a Data partition at the end for making the data transfer between the different operation systems as easy as possibly. LINUXBOOT is a small partition which will contain the EFI boot loader (size it 50MB or something like that). Linux Swap, obviously, will become the swap partition of the Linux installation. DISK1S5 is the Linux root partition itself. The Data partition has to be formated as Mac OS Extended. Don’t use the Journaled version of HFS+, cause this makes trouble on the Linux side. The other partitions have to be formatted as MS-DOS (FAT).

After applying the changes we can add the EFI boot loader to the LINUXBOOT partition. The Apple EFI implementation is searching for a file with the efi extensions on all bootable hard disks. Mount LINUXBOOT and create a efi/boot directory on the root path. Copy the bootx86.efi file into the boot/ directory. As bootx86.efi is a Grub2 boot loader we need a valid Grub2 configuration file. The following grub.cfg shows the configuration for a Ubuntu 9.10 i386 installation. For the 64-bit version or any other version of Ubuntu the settings might be slightly different.

menuviewer="text"
timeout=10
default=0
set F1=ctrl-x
menuentry "ubuntu-9.10-desktop-i386"
{
 fakebios
 search --set -f /boot/vmlinuz-2.6.31-14-generic
 linux /boot/vmlinuz-2.6.31-14-generic root=UUID=4e140981-4ab3-41a2-a2fb-26b1287beb87 ro quiet splash noefi video=efifb
 initrd /boot/initrd.img-2.6.31-14-generic
}
menuentry "ubuntu-9.10-desktop-i386 single"
{
 fakebios
 search --set -f /boot/vmlinuz-2.6.31-14-generic
 linux /boot/vmlinuz-2.6.31-14-generic root=UUID=4e140981-4ab3-41a2-a2fb-26b1287beb87 ro noefi video=efifb single
 initrd /boot/initrd.img-2.6.31-14-generic
}
menuentry "ubuntu-9.10-desktop-i386 text"
{
 fakebios
 search --set -f /boot/vmlinuz-2.6.31-14-generic
 linux /boot/vmlinuz-2.6.31-14-generic root=UUID=4e140981-4ab3-41a2-a2fb-26b1287beb87 ro noefi vga=normal
 initrd /boot/initrd.img-2.6.31-14-generic
}
menuentry "Mac OS X"
{
 search --set -f /usr/standalone/i386/boot.efi
 chainloader /usr/standalone/i386/boot.efi
}
menuentry "CD"
{
 appleloader CD
}
menuentry "mbr"
{
 appleloader HD
}
menuentry "reboot"
{
 reboot
}

You have to change the root UUID to the one the Ubuntu installer will assign to your hard disk after installation. Just check the fstab file when the installation has finished. The first entry boots Linux with a splash image enabled. The second one is for the single user mode in the case something went wrong. Please note the video=efifb option, which enables the graphical mode in the boot phase.

Installing Ubuntu

Most of the installation process is straight forward and doesn’t need any special attention. Download the version of your choice from one of the mirrors, burn it on CD and start the installation. You can select the CD as boot medium by pressing Alt when your Mac starts. When the installer ask for the partition scheme, you have to switch to “manual choice”. Select the DISK1S5 (your what it is in your case) as the root / partition and change the filesystem type to ext3. Also remember the path to the system partition, cause you will need it later again. Select the swap partition and change its type to swap. Proceed with the rest of the installation until the last dialog. There select “advanced settings” and change the boot loader target from hd0 to /dev/sdXX, where you replace XX to the path you used previously in the partition tool.

If all went right you should be able to select the LINUXBOOT partition by pressing Alt when your Mac starts. After that Grub2 should shows up, you will be able to boot into your freshly installed Ubuntu.

Conclusion

In this post I showed how to easily add the possibility to boot Linux on your MacBook Pro. With the external USB hard disk solution, no internal valuable space is wasted. Of course the speed isn’t the same as if the OS would be installed on the internal drive, but for testing software on different operation systems this is satisfactory. To increase the speed a little bit more, an external FireWire hard disk could be used.

FRITZ!Box tuning part 3: Using the VoIP phone line from everywhere

The contract with my Internet service provider includes a VoIP connection. Together with the FRITZ!Box 7270 all phone calls are done over the Internet, an additional conventional phone connection isn’t necessary anymore. One of the benefits of this is that you can connect to your registrar from everywhere in the world. But that’s theory, cause e.g. my provider doesn’t allow a connection if you are not in the network of the provider itself. Of course there are free services like sipgate or even Skype. There you could make free calls within the services itself, but as soon as you like to call a real phone number you have to pay. They are cheap, no question, but my contract includes a flat rate within Germany. That’s even cheaper. So what I like to do is to use my VoIP phone connection even when I’m not at home. In the following third part of the FRITZ!Box tuning series, I will explain how to achieve this. As already said in the first two post, where you at least should read the first one, I’m not responsible for anything happens to your FRITZ!Box after you have tried what is described here.

Adding a softphone to the FRITZ!Box

The FRITZ!Box fully supports softphones in its basic configuration. Adding new softphones is done in the web frontend in the extended configuration section. There is a wizard for this, where you have to answer some question about your new device. Select phone as device, LAN/WLAN (IP-Phone) for the connection type, choose a name and a password. You get a new internal phone number which usually starts at 620 for the first created device. The FRITZ!Box try’s than to connect to the new device. You can skip this for now. After that you have to select which official phone number the new device should use. This is important cause this will be displayed as the caller id when you make a call. Now you could choose if the new softphone should react on all incoming calls, regardless of the phone number called, or only on a specific one.

Configuring the client software

I will explain the client setup with the help of a free VoIP software called Telephone. It’s only available for Mac OS X, but there are many other VoIP clients out there which also works for other operation systems. After downloading and installing it you have to create a new account. Select a descriptive name for the account. For the domain use fritz.box, as username you have to use the internal number the FRITZ!Box selected above. Lets use 620 for now. The password is the one you chose previously. After the account is created, I had to select Substitute “00” for “+” in the advanced settings, cause the phone numbers in my address book are all saved with the international phone prefix of Germany which is +49. Assuming you are working in your home network right now, you should be able to connect with Telephone to your FRITZ!Box. Some simple tests like making an outgoing and incoming call with an additional mobile phone should verify a working setup. Some nice features like the Mac OS X Address Book integration, which also transfers incoming caller id’s to real names if they are found in the address book, making Telephone a really useful application. For further phone call management functionality on Mac OS X, I can advice you to take a look at the also free software Frizzix.

Allowing calls from everywhere

All the previously isn’t any magic, cause it uses build in support of the FRITZ!Box. But this article is about allowing connections to the VoIP part of the FRITZ!Box from everywhere. To make this happen we have to edit an internal configuration file of the FRITZ!Box. This time we aren’t change the ar7.cfg file, but a file called /var/flash/voip.cfg. As the name suggest there is most of the VoIP configuration included. Use nvi to edit it and search for a section called extensions. There should be a newly created one which have a value extension_number with 620. Change the value reg_from_outside from no to yes. This section should then look like the following:

extensions {
    enabled = yes;
    username = "$$$$SSFSDFSOPKSFDOPK;LWE§REWSDFMKFSLDF3232SDFSDFSDF";
    authname = "";
    passwd = "$$$$DFS342ASDFSDFDSFDS§344WLKKHMSJHAJHASDAHQASLKADJSA";
    extension_number = 620;
    reg_from_outside = yes;
    tx_packetsize_in_ms = 0;
}

Save the file and reboot your FRITZ!Box by typing reboot. Next we have to tell Telephone to use a proxy when connecting to the FRITZ!Box. Go to the advanced settings and add your DynDNS name, in this example it would be xtestx.dyndns.org, to the proxy field. That’s all. Now you should be able to make calls from every network you are currently logged in.

Conclusion

This simple change to the internal configuration of the FRITZ!Box allows you to use your VoIP account from everywhere over the world. As nice this feature is, I like to add some words of caution at the end. First you need a good download and especially a good upload connection speed in your home setup, cause all phone calls are routed over the FRITZ!Box. Secondly I didn’t know if VoIP transfers are encrypted in any way, so be aware that there is the possibility someone monitor your calls. And as last note you should understand that you opened a port on your FRITZ!Box for everyone, which in the case your password is stolen, could be abused. In the worst case someone use your account to SPAM other people or call expensive service numbers.

Integrating native Cocoa controls into Qt

Making applications looking and feeling as native as possible on every supported platform is one of my main responsibilities within the VirtualBox development. Most of the work therefor is done by the Qt framework which we are using for our GUI. Qt does a nice job for Windows and most of the currently popular X11 window toolkits used under Unix and Linux. They are behaving and looking similar in many ways which make it easy to develop for both architectures. Unfortunately this doesn’t count in any case for Mac OS X, which often uses very different approaches or uses very specialized controls to reach a specific aim. One of this controls is the Mac OS X help button who every Mac user is familiar with. If an Mac OS X application doesn’t use this help button, it breaks the design rules and the application, lets say, smells a little bit “under designed”. The following little example shows how to integrate a NSButton seamlessly into your Qt application.

Qt make it easy

Nokia added the QMacCocoaViewContainer class with Qt 4.5. This class make it easy to integrate any NSView or deviate of the NSView class into the QWidget hierarchy of an application. The best integration is archived if one deviate from QMacCocoaViewContainer. To use Cocoa code and C++ classes at once the Objective-C++ compiler is necessary. The gcc uses the Objective-C++ compiler automatically if the source file ends with mm. We start with the C++ interface which looks like the following:

ADD_COCOA_NATIVE_REF(NSButton);
class CocoaHelpButton: public QMacCocoaViewContainer
{
    Q_OBJECT
public:
    CocoaHelpButton(QWidget *pParent = 0);
    QSize sizeHint() const;
    void onClicked();
signals:
    void clicked();
private:
    NativeNSButtonRef m_pButton;
};

For any Qt programmer this class definition is easy to understand. The only unusual is the ADD_COCOA_NATIVE_REF macro call and the NativeNSButtonRef type itself. One could say NativeNSButtonRef should be NSButton* and you are done, but it’s not that easy. The reason for this is that the include file will be included first in the Objective-C++ source code file, where the NSButton* definition wouldn’t be a problem, but secondly in every C++ source file which will use the CocoaHelpButton, where on the other side any Cocoa code is forbidden. The ADD_COCOA_NATIVE_REF macro avoid this problem by expanding NativeNSButtonRef to NSButton* if Objective-C++ code is compiled and to void* if C++ code is compiled. The macro itself looks like this:

#ifdef __OBJC__
# define ADD_COCOA_NATIVE_REF(CocoaClass) 
    @class CocoaClass; 
    typedef CocoaClass *Native##CocoaClass##Ref
#else /* __OBJC__ */
# define ADD_COCOA_NATIVE_REF(CocoaClass) typedef void *Native##CocoaClass##Ref
#endif /* __OBJC__ */

The advantage of using such a macro is that one can use all methods of the NSButton in the Cocoa part of the source code without any casting.

A little bit of Cocoa

The initialization of the CocoaHelpButton class is straight forward as seen in the next code part:

CocoaHelpButton::CocoaHelpButton(QWidget *pParent /* = 0 */)
  :QMacCocoaViewContainer(0, pParent)
{
    m_pButton = [[NSButton alloc] init];
    [m_pButton setTitle: @""];
    [m_pButton setBezelStyle: NSHelpButtonBezelStyle];
    [m_pButton setBordered: YES];
    [m_pButton setAlignment: NSCenterTextAlignment];
    [m_pButton sizeToFit];
    NSRect frame = [m_pButton frame];
    frame.size.width += 12; /* Margin */
    [m_pButton setFrame:frame];
    /* We need a target for the click selector */
    NSButtonTarget *bt = [[NSButtonTarget alloc] initWithObject: this];
    [m_pButton setTarget: bt];
    [m_pButton setAction: @selector(clicked:)];
    /* Make sure all is properly resized */
    resize(frame.size.width, frame.size.height);
    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}

QSize CocoaHelpButton::sizeHint() const
{
    NSRect frame = [m_pButton frame];
    return QSize(frame.size.width, frame.size.height);
}

void CocoaHelpButton::onClicked()
{
    emit clicked(false);
}

This set up the NSButton object and make sure that everything has the right size. As shown there, to make a standard button a help button the bezel style has been set to NSHelpButtonBezelStyle. To get the click notification the wrapper class NSButtonTarget is necessary.  As highlighted in the code above the target action is set to the selector “clicked”.  The NSButtonTarget class looks as follow:

@interface NSButtonTarget: NSObject
{
    CocoaHelpButton *m_pTarget;
}
-(id)initWithObject:(CocoaHelpButton*)object;
-(IBAction)clicked:(id)sender;
@end
@implementation NSButtonTarget
-(id)initWithObject:(CocoaHelpButton*)object
{
    self = [super init];
    m_pTarget = object;
    return self;
}
-(IBAction)clicked:(id)sender;
{
    m_pTarget->onClicked();
}
@end

If you put all this together and add the CocoaHelpButton class to your project you will get some output like this:

More integration could be reached by adding wrapper methods for e.g. setting the tooltip, but this is left out as an exercise for the reader.

Conclusion

For more complex controls like a NSSearchField more interaction with Cocoa will be necessary. On the other hand this little excursion to the Cocoa world should make it easy for everyone to add shiny new Mac OS X controls to the own Qt application.