private function updateBackground($data)
    {
        $this->updatedAt = microtime(true);

        $this->image = imagecreatetruecolor($this->get('image_width'), $this->get('image_height'));
        imageantialias($this->image, true);

        $this->initializeColors();
        imagefill($this->image, 0, 0, $this->get('background_color'));

        $numProject = 0;
        foreach ($data['projects'] as $project => $builds) {
            // the most recent build is always shown on top
            rsort($builds);

            $x1 = $this->get('horizontal_padding') + (($this->get('bar_width') + $this->get('horizontal_gutter')) * $numProject);
            $x2 = $x1 + $this->get('bar_width');

            // plot each project slug
            $this->addTextToImage(
                substr($project, 0, $this->get('max_number_letters')),
                $x1,
                $this->get('vertical_padding') - 0.2 * $this->get('font_size')
            );

            foreach ($builds as $i => $build) {
                $y1 = $this->get('vertical_padding') + $this->get('font_size') + (($this->get('bar_height') + $this->get('vertical_gutter')) * $i);
                $y2 = $y1 + $this->get('bar_height');
                $color = 'ok' == $build ? $this->get('success_color') : $this->get('failure_color');

                // plot a bar for each project build
                imageFilledRectangle($this->image, $x1, $y1, $x2, $y2, $color);
            }
            $numProject++;
        }

        $this->addTextToImage(
            'Last update: '.$data['last_update'],
            $this->get('horizontal_padding'),
            $this->get('image_height') - $this->get('font_size')
        );

        // Hack: two different images are needed to update the wallpaper
        // One holds the current wallpaper and the other is the new one
        // If you use just one image and modify it, the OS doesn't reload it
        if (file_exists($this->evenBackgroundImagePath)) {
            $this->imagePath = $this->oddBackgroundImagePath;
            unlink($this->evenBackgroundImagePath);
        } elseif (file_exists($this->oddBackgroundImagePath)) {
            $this->imagePath = $this->evenBackgroundImagePath;
            unlink($this->oddBackgroundImagePath);
        } else {
            $this->imagePath = $this->oddBackgroundImagePath;
        }

        imagepng($this->image, $this->imagePath);
        imagedestroy($this->image);

        // Wallpaper is reloaded via AppleScript
        $scriptPath = $this->dir.'/update-background.scpt';

        file_put_contents($scriptPath, <<<END
tell application "System Events"
    tell current desktop
        set picture to POSIX file "file://localhost/$this->imagePath"
    end tell
end tell
END
);
        system("osascript $scriptPath");
    }