view src/video/directfb/SDL_DirectFB_video.c @ 2364:e321b52dee8f gsoc2008_iphone

These files contain the audio support for iPhone. They are based on the CoreAudio audio driver for Mac OS X. The principle difference is that the iPhone doesn't seem to have a concept of audio devices ... it just has special units for audio in and audio out. Also had to change some functions to versions which seem to only exist on iPhone and will apparently exist in Mac OS X 10.6(!) There is currently no audio recording support -- my iPod Touch doesn't have a microphone to test this with.
author Holmes Futrell <hfutrell@umail.ucsb.edu>
date Fri, 18 Jul 2008 17:53:54 +0000
parents 1e690901ecd7
children e1da92da346c e82a0e3e9b0e
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2006 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Sam Lantinga
    slouken@libsdl.org

    SDL1.3 implementation by couriersud@arcor.de
	
*/

/* TODO: Various
 * Add Mouse support from 1.2 directfb driver
 * - Interface is defined in SDL_Mouse.c.h
 * - Default Cursor automatically created
 */

#include "SDL_config.h"

/* DirectFB video driver implementation.
*/

#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

#include <directfb.h>
#include <directfb_version.h>

#include "SDL_video.h"
#include "SDL_mouse.h"
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../events/SDL_events_c.h"
#include "SDL_DirectFB_video.h"
#include "SDL_DirectFB_events.h"

/* This is the rect EnumModes2 uses */
struct DirectFBEnumRect
{
    SDL_Rect r;
    struct DirectFBEnumRect *next;
};

struct DirectFB_GLContext
{
    IDirectFBGL *context;
};

/* Initialization/Query functions */
static int DirectFB_VideoInit(_THIS);
static void DirectFB_VideoQuit(_THIS);

static int DirectFB_CreateWindow(_THIS, SDL_Window * window);
static int DirectFB_CreateWindowFrom(_THIS, SDL_Window * window,
                                     const void *data);
static void DirectFB_SetWindowTitle(_THIS, SDL_Window * window);
static void DirectFB_SetWindowPosition(_THIS, SDL_Window * window);
static void DirectFB_SetWindowSize(_THIS, SDL_Window * window);
static void DirectFB_ShowWindow(_THIS, SDL_Window * window);
static void DirectFB_HideWindow(_THIS, SDL_Window * window);
static void DirectFB_RaiseWindow(_THIS, SDL_Window * window);
static void DirectFB_MaximizeWindow(_THIS, SDL_Window * window);
static void DirectFB_MinimizeWindow(_THIS, SDL_Window * window);
static void DirectFB_RestoreWindow(_THIS, SDL_Window * window);
static void DirectFB_SetWindowGrab(_THIS, SDL_Window * window);
static void DirectFB_DestroyWindow(_THIS, SDL_Window * window);
static SDL_bool DirectFB_GetWindowWMInfo(_THIS, SDL_Window * window,
                                         struct SDL_SysWMinfo *info);

static void DirectFB_GetDisplayModes(_THIS);
static int DirectFB_SetDisplayMode(_THIS, SDL_DisplayMode * mode);

static int DirectFB_SetDisplayGammaRamp(_THIS, Uint16 * ramp);
static int DirectFB_GetDisplayGammaRamp(_THIS, Uint16 * ramp);

#if SDL_DIRECTFB_OPENGL
static int DirectFB_GL_LoadLibrary(_THIS, const char *path);
static void DirectFB_GL_UnloadLibrary(_THIS);
static void *DirectFB_GL_GetProcAddress(_THIS, const char *proc);
static SDL_GLContext DirectFB_GL_CreateContext(_THIS, SDL_Window * window);
static int DirectFB_GL_MakeCurrent(_THIS, SDL_Window * window,
                                   SDL_GLContext context);
static int DirectFB_GL_SetSwapInterval(_THIS, int interval);
static int DirectFB_GL_GetSwapInterval(_THIS);
static void DirectFB_GL_SwapWindow(_THIS, SDL_Window * window);
static void DirectFB_GL_DeleteContext(_THIS, SDL_GLContext context);

#endif

/* DirectFB driver bootstrap functions */

static int
DirectFB_Available(void)
{
    return 1;
}

static void
DirectFB_DeleteDevice(SDL_VideoDevice * device)
{
    SDL_free(device->driverdata);
    SDL_free(device);
}

static SDL_VideoDevice *
DirectFB_CreateDevice(int devindex)
{
    SDL_VideoDevice *device;

    /* Initialize all variables that we clean on shutdown */
    SDL_DFB_CALLOC(device, 1, sizeof(SDL_VideoDevice));
    SDL_DFB_CALLOC(device->gl_data, 1, sizeof(*device->gl_data));

    /* Set the function pointers */

    /* Set the function pointers */
    device->VideoInit = DirectFB_VideoInit;
    device->VideoQuit = DirectFB_VideoQuit;
    device->GetDisplayModes = DirectFB_GetDisplayModes;
    device->SetDisplayMode = DirectFB_SetDisplayMode;
#if 0
    device->SetDisplayGammaRamp = DirectFB_SetDisplayGammaRamp;
    device->GetDisplayGammaRamp = DirectFB_GetDisplayGammaRamp;
#else
    device->SetDisplayGammaRamp = NULL;
    device->GetDisplayGammaRamp = NULL;
#endif
    device->PumpEvents = DirectFB_PumpEventsWindow;

    device->CreateWindow = DirectFB_CreateWindow;
    device->CreateWindowFrom = DirectFB_CreateWindowFrom;
    device->SetWindowTitle = DirectFB_SetWindowTitle;
    device->SetWindowPosition = DirectFB_SetWindowPosition;
    device->SetWindowSize = DirectFB_SetWindowSize;
    device->ShowWindow = DirectFB_ShowWindow;
    device->HideWindow = DirectFB_HideWindow;
    device->RaiseWindow = DirectFB_RaiseWindow;
    device->MaximizeWindow = DirectFB_MaximizeWindow;
    device->MinimizeWindow = DirectFB_MinimizeWindow;
    device->RestoreWindow = DirectFB_RestoreWindow;
    device->SetWindowGrab = DirectFB_SetWindowGrab;
    device->DestroyWindow = DirectFB_DestroyWindow;
    device->GetWindowWMInfo = DirectFB_GetWindowWMInfo;

#if SDL_DIRECTFB_OPENGL
    device->GL_LoadLibrary = DirectFB_GL_LoadLibrary;
    device->GL_GetProcAddress = DirectFB_GL_GetProcAddress;
    device->GL_MakeCurrent = DirectFB_GL_MakeCurrent;

    device->GL_CreateContext = DirectFB_GL_CreateContext;
    device->GL_SetSwapInterval = DirectFB_GL_SetSwapInterval;
    device->GL_GetSwapInterval = DirectFB_GL_GetSwapInterval;
    device->GL_SwapWindow = DirectFB_GL_SwapWindow;
    device->GL_DeleteContext = DirectFB_GL_DeleteContext;

#endif

    device->free = DirectFB_DeleteDevice;

    return device;
  error:
    if (device)
        free(device);
    return (0);
}

VideoBootStrap DirectFB_bootstrap = {
    "directfb", "DirectFB",
    DirectFB_Available, DirectFB_CreateDevice
};

static DFBEnumerationResult
EnumModesCallback(int width, int height, int bpp, void *data)
{
    SDL_VideoDisplay *this = (SDL_VideoDisplay *) data;
    DFB_DisplayData *dispdata = (DFB_DisplayData *) this->driverdata;
    SDL_DisplayMode mode;

    mode.w = width;
    mode.h = height;
    mode.refresh_rate = 0;
    mode.driverdata = NULL;
    mode.format = 0;

    if (dispdata->nummodes < DFB_MAX_MODES) {
        dispdata->modelist[dispdata->nummodes++] = mode;
    }

    SDL_DFB_DEBUG("w %d h %d bpp %d\n", width, height, bpp);
    return DFENUM_OK;
}

static int
DFBToSDLPixelFormat(DFBSurfacePixelFormat pixelformat, Uint32 * fmt)
{
    switch (pixelformat) {
    case DSPF_ALUT44:
        *fmt = SDL_PIXELFORMAT_INDEX4LSB;
        break;
    case DSPF_LUT8:
        *fmt = SDL_PIXELFORMAT_INDEX8;
        break;
    case DSPF_RGB332:
        *fmt = SDL_PIXELFORMAT_RGB332;
        break;
    case DSPF_ARGB4444:
        *fmt = SDL_PIXELFORMAT_ARGB4444;
        break;
    case SDL_PIXELFORMAT_ARGB1555:
        *fmt = SDL_PIXELFORMAT_ARGB1555;
        break;
    case DSPF_RGB16:
        *fmt = SDL_PIXELFORMAT_RGB565;
        break;
    case DSPF_RGB24:
        *fmt = SDL_PIXELFORMAT_RGB24;
        break;
    case DSPF_RGB32:
        *fmt = SDL_PIXELFORMAT_RGB888;
        break;
    case DSPF_ARGB:
        *fmt = SDL_PIXELFORMAT_ARGB8888;
        break;
    case DSPF_YV12:
        *fmt = SDL_PIXELFORMAT_YV12;
        break;                  /* Planar mode: Y + V + U  (3 planes) */
    case DSPF_I420:
        *fmt = SDL_PIXELFORMAT_IYUV;
        break;                  /* Planar mode: Y + U + V  (3 planes) */
    case DSPF_YUY2:
        *fmt = SDL_PIXELFORMAT_YUY2;
        break;                  /* Packed mode: Y0+U0+Y1+V0 (1 plane) */
    case DSPF_UYVY:
        *fmt = SDL_PIXELFORMAT_UYVY;
        break;                  /* Packed mode: U0+Y0+V0+Y1 (1 plane) */
    default:
        return -1;
    }
    return 0;
}

static DFBEnumerationResult
cbScreens(DFBScreenID screen_id, DFBScreenDescription desc,
          void *callbackdata)
{
    DFB_DeviceData *devdata = (DFB_DeviceData *) callbackdata;

    devdata->screenid[devdata->numscreens++] = screen_id;
    return DFENUM_OK;
}

DFBEnumerationResult
cbLayers(DFBDisplayLayerID layer_id, DFBDisplayLayerDescription desc,
         void *callbackdata)
{
    DFB_DeviceData *devdata = (DFB_DeviceData *) callbackdata;

    if (desc.caps & DLCAPS_SURFACE) {
        if ((desc.type & DLTF_GRAPHICS) && (desc.type & DLTF_VIDEO)) {
            if (devdata->vidlayer[devdata->aux] == -1)
                devdata->vidlayer[devdata->aux] = layer_id;
        } else if (desc.type & DLTF_GRAPHICS) {
            if (devdata->gralayer[devdata->aux] == -1)
                devdata->gralayer[devdata->aux] = layer_id;
        }
    }
    return DFENUM_OK;
}

static int
DirectFB_VideoInit(_THIS)
{
#if (DIRECTFB_MAJOR_VERSION == 0) && (DIRECTFB_MINOR_VERSION == 9) && (DIRECTFB_MICRO_VERSION < 23)
    DFBCardCapabilities caps;
#else
    DFBGraphicsDeviceDescription caps;
#endif
    DFBDisplayLayerConfig dlc;
    struct DirectFBEnumRect *rect;
    IDirectFB *dfb = NULL;
    IDirectFBDisplayLayer *layer = NULL;

    SDL_VideoDisplay display;
    DFB_DisplayData *dispdata;
    DFB_DeviceData *devdata;
    SDL_DisplayMode mode;
    SDL_Keyboard keyboard;
    int i;
    DFBResult ret;
    int tcw[DFB_MAX_SCREENS];
    int tch[DFB_MAX_SCREENS];

    SDL_zero(keyboard);

    SDL_DFB_CHECKERR(DirectFBInit(NULL, NULL));
    SDL_DFB_CHECKERR(DirectFBCreate(&dfb));

    SDL_DFB_CALLOC(devdata, 1, sizeof(*devdata));
    devdata->numscreens = 0;
    for (i = 0; i < DFB_MAX_SCREENS; i++) {
        devdata->gralayer[i] = -1;
        devdata->vidlayer[i] = -1;
    }
    SDL_DFB_CHECKERR(dfb->EnumScreens(dfb, &cbScreens, devdata));
    for (i = 0; i < devdata->numscreens; i++) {
        IDirectFBScreen *screen;

        SDL_DFB_CHECKERR(dfb->GetScreen(dfb, devdata->screenid[i], &screen));

        devdata->aux = i;
        SDL_DFB_CHECKERR(screen->
                         EnumDisplayLayers(screen, &cbLayers, devdata));
        screen->GetSize(screen, &tcw[i], &tch[i]);
        screen->Release(screen);
    }

    /* Query card capabilities */

    dfb->GetDeviceDescription(dfb, &caps);

    SDL_DFB_DEBUG("SDL directfb video driver - %s %s\n", __DATE__, __TIME__);
    SDL_DFB_DEBUG("Using %s (%s) driver.\n", caps.name, caps.vendor);
    SDL_DFB_DEBUG("Found %d screens\n", devdata->numscreens);

    for (i = 0; i < devdata->numscreens; i++) {
        //SDL_DFB_CHECKERR( dfb->GetDisplayLayer (dfb, DLID_PRIMARY, &layer) );
        SDL_DFB_CHECKERR(dfb->
                         GetDisplayLayer(dfb, devdata->gralayer[i], &layer));
        //SDL_DFB_CHECKERR( dfb->CreateInputEventBuffer (dfb, DICAPS_ALL, DFB_FALSE, &events) );

        SDL_DFB_CHECKERR(layer->
                         SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE));
        layer->EnableCursor(layer, 1);
        SDL_DFB_CHECKERR(layer->SetCursorOpacity(layer, 0xC0));
        SDL_DFB_CHECKERR(layer->SetCooperativeLevel(layer, DLSCL_SHARED));

        /* Query layer configuration to determine the current mode and pixelformat */
        layer->GetConfiguration(layer, &dlc);

        DFBToSDLPixelFormat(dlc.pixelformat, &mode.format);

        mode.w = dlc.width;
        mode.h = dlc.height;
        mode.refresh_rate = 0;
        mode.driverdata = NULL;

        SDL_DFB_CALLOC(dispdata, 1, sizeof(*dispdata));

        dispdata->layer = layer;
        dispdata->pixelformat = dlc.pixelformat;
        dispdata->cw = tcw[i];
        dispdata->ch = tch[i];

        /* YUV - Video layer */

        dispdata->vidID = devdata->vidlayer[i];

        SDL_zero(display);

        display.desktop_mode = mode;
        display.current_mode = mode;
        display.driverdata = dispdata;

        /* Enumerate the available fullscreen modes */
        SDL_DFB_CALLOC(dispdata->modelist, DFB_MAX_MODES,
                       sizeof(SDL_DisplayMode));
        SDL_DFB_CHECKERR(dfb->
                         EnumVideoModes(dfb, EnumModesCallback, &display));

        SDL_AddVideoDisplay(&display);
    }

    devdata->initialized = 1;
    devdata->dfb = dfb;
    devdata->firstwin = NULL;

    _this->driverdata = devdata;


#if SDL_DIRECTFB_OPENGL
    /* Opengl */
    _this->gl_data->gl_active = 0;
    _this->gl_data->gl_context = NULL;
#endif

    DirectFB_AddRenderDriver(_this);
    DirectFB_InitMouse(_this);
    //devdata->mouse = SDL_AddMouse(&mouse, -1);
    devdata->keyboard = SDL_AddKeyboard(&keyboard, -1);
    DirectFB_InitOSKeymap(_this);

    return 0;


  error:
    //FIXME: Cleanup not complete, Free existing displays
    SDL_DFB_FREE(dispdata);
    SDL_DFB_FREE(dispdata->modelist);
    SDL_DFB_RELEASE(layer);
    SDL_DFB_RELEASE(dfb);
    return -1;
}

static void
DirectFB_VideoQuit(_THIS)
{
    DFB_DeviceData *devdata = (DFB_DeviceData *) _this->driverdata;
    SDL_DisplayMode tmode;
    DFBResult ret;
    int i;

    tmode = _this->displays[0].desktop_mode;
    tmode.format = SDL_PIXELFORMAT_UNKNOWN;
    DirectFB_SetDisplayMode(_this, &tmode);
    tmode = _this->displays[0].desktop_mode;
    DirectFB_SetDisplayMode(_this, &tmode);

    for (i = 0; i < devdata->numscreens; i++) {
        DFB_DisplayData *dispdata =
            (DFB_DisplayData *) _this->displays[i].driverdata;
        if (dispdata->layer) {
            SDL_DFB_CHECK(dispdata->layer->
                          SetCooperativeLevel(dispdata->layer,
                                              DLSCL_ADMINISTRATIVE));
            SDL_DFB_CHECK(dispdata->layer->
                          SetCursorOpacity(dispdata->layer, 0x00));
            SDL_DFB_CHECK(dispdata->layer->
                          SetCooperativeLevel(dispdata->layer, DLSCL_SHARED));
        }
        SDL_DFB_RELEASE(dispdata->layer);

        /* Free video mode list */
        if (dispdata->modelist) {
            SDL_free(dispdata->modelist);
            dispdata->modelist = NULL;
        }
        // Done by core
        //SDL_free(dispdata);
    }

    //SDL_DFB_RELEASE(devdata->eventbuffer);

    SDL_DFB_RELEASE(devdata->dfb);

    SDL_DelMouse(devdata->mouse);
    SDL_DelKeyboard(devdata->keyboard);

#if SDL_DIRECTFB_OPENGL
    DirectFB_GL_UnloadLibrary(_this);
#endif

    devdata->initialized = 0;
}


static DFBSurfacePixelFormat
SDLToDFBPixelFormat(Uint32 format)
{
    switch (format) {
    case SDL_PIXELFORMAT_INDEX4LSB:
        return DSPF_ALUT44;
    case SDL_PIXELFORMAT_INDEX8:
        return DSPF_LUT8;
    case SDL_PIXELFORMAT_RGB332:
        return DSPF_RGB332;
    case SDL_PIXELFORMAT_RGB555:
        return DSPF_ARGB1555;
    case SDL_PIXELFORMAT_ARGB4444:
        return DSPF_ARGB4444;
    case SDL_PIXELFORMAT_ARGB1555:
        return DSPF_ARGB1555;
    case SDL_PIXELFORMAT_RGB565:
        return DSPF_RGB16;
    case SDL_PIXELFORMAT_RGB24:
        return DSPF_RGB24;
    case SDL_PIXELFORMAT_RGB888:
        return DSPF_RGB32;
    case SDL_PIXELFORMAT_ARGB8888:
        return DSPF_ARGB;
    case SDL_PIXELFORMAT_YV12:
        return DSPF_YV12;       /* Planar mode: Y + V + U  (3 planes) */
    case SDL_PIXELFORMAT_IYUV:
        return DSPF_I420;       /* Planar mode: Y + U + V  (3 planes) */
    case SDL_PIXELFORMAT_YUY2:
        return DSPF_YUY2;       /* Packed mode: Y0+U0+Y1+V0 (1 plane) */
    case SDL_PIXELFORMAT_UYVY:
        return DSPF_UYVY;       /* Packed mode: U0+Y0+V0+Y1 (1 plane) */
    case SDL_PIXELFORMAT_YVYU:
        return DSPF_UNKNOWN;    /* Packed mode: Y0+V0+Y1+U0 (1 plane) */
    case SDL_PIXELFORMAT_INDEX1LSB:
        return DSPF_UNKNOWN;
    case SDL_PIXELFORMAT_INDEX1MSB:
        return DSPF_UNKNOWN;
    case SDL_PIXELFORMAT_INDEX4MSB:
        return DSPF_UNKNOWN;
    case SDL_PIXELFORMAT_RGB444:
        return DSPF_UNKNOWN;
    case SDL_PIXELFORMAT_BGR24:
        return DSPF_UNKNOWN;
    case SDL_PIXELFORMAT_BGR888:
        return DSPF_UNKNOWN;
    case SDL_PIXELFORMAT_RGBA8888:
        return DSPF_UNKNOWN;
    case SDL_PIXELFORMAT_ABGR8888:
        return DSPF_UNKNOWN;
    case SDL_PIXELFORMAT_BGRA8888:
        return DSPF_UNKNOWN;
    case SDL_PIXELFORMAT_ARGB2101010:
        return DSPF_UNKNOWN;
    default:
        return DSPF_UNKNOWN;
    }
}

static void
CheckSetDisplayMode(_THIS, DFB_DisplayData * data, SDL_DisplayMode * mode)
{
    DFBDisplayLayerConfig config;
    DFBDisplayLayerConfigFlags failed;

    config.width = mode->w;
    config.height = mode->h;
    config.pixelformat = SDLToDFBPixelFormat(mode->format);
    config.flags = DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT;
    failed = 0;
    data->layer->TestConfiguration(data->layer, &config, &failed);
    if (failed == 0)
        SDL_AddDisplayMode(_this->current_display, mode);

}

static void
DirectFB_GetDisplayModes(_THIS)
{
    //SDL_DisplayData *data = (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    //SDL_DisplayMode mode;
    //SDL_AddDisplayMode(_this->current_display, &mode);

    SDL_DFB_DEVICEDATA(_this);
    DFB_DisplayData *data = (DFB_DisplayData *) SDL_CurrentDisplay.driverdata;
    int i;
    SDL_DisplayMode mode;

    for (i = 0; i < data->nummodes; ++i) {
        mode = data->modelist[i];
        //mode.format = SDL_PIXELFORMAT_UNKNOWN;

        mode.format = SDL_PIXELFORMAT_INDEX8;
        CheckSetDisplayMode(_this, data, &mode);
        mode.format = SDL_PIXELFORMAT_RGB565;
        CheckSetDisplayMode(_this, data, &mode);
        mode.format = SDL_PIXELFORMAT_RGB24;
        CheckSetDisplayMode(_this, data, &mode);
        mode.format = SDL_PIXELFORMAT_RGB888;
        CheckSetDisplayMode(_this, data, &mode);
    }
}

int
DirectFB_SetDisplayMode(_THIS, SDL_DisplayMode * mode)
{
    SDL_DFB_DEVICEDATA(_this);
    DFB_DisplayData *data = (DFB_DisplayData *) SDL_CurrentDisplay.driverdata;
    DFBDisplayLayerConfig config, rconfig;
    DFBDisplayLayerConfigFlags fail = 0;
    DFBResult ret;

    SDL_DFB_CHECKERR(data->layer->
                     SetCooperativeLevel(data->layer, DLSCL_ADMINISTRATIVE));

    SDL_DFB_CHECKERR(data->layer->GetConfiguration(data->layer, &config));
    config.flags = DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_BUFFERMODE;
    if (mode->format != SDL_PIXELFORMAT_UNKNOWN) {
        config.flags |= DLCONF_PIXELFORMAT;
        config.pixelformat = SDLToDFBPixelFormat(mode->format);
        data->pixelformat = config.pixelformat;
    }
    config.width = mode->w;
    config.height = mode->h;

    config.buffermode = DLBM_BACKVIDEO;

    //config.pixelformat = GetFormatForBpp (bpp, HIDDEN->layer);

    data->layer->TestConfiguration(data->layer, &config, &fail);
    if (fail & (DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT)) {
        SDL_DFB_DEBUG("Error setting mode %dx%d-%x\n", mode->w, mode->h,
                      mode->format);
        return -1;
    }
    SDL_DFB_DEBUG("Trace\n");
    config.flags &= ~fail;
    SDL_DFB_CHECKERR(data->layer->SetConfiguration(data->layer, &config));
    SDL_DFB_CHECKERR(data->layer->
                     SetCooperativeLevel(data->layer, DLSCL_ADMINISTRATIVE));

    /* Double check */
    SDL_DFB_CHECKERR(data->layer->GetConfiguration(data->layer, &rconfig));

    if ((config.width != rconfig.width) ||
        (config.height != rconfig.height) ||
        (config.pixelformat != rconfig.pixelformat)) {
        SDL_DFB_DEBUG("Error setting mode %dx%d-%x\n", mode->w, mode->h,
                      mode->format);
        return -1;
    }

    return 0;
  error:
    return -1;
}

static int
DirectFB_SetDisplayGammaRamp(_THIS, Uint16 * ramp)
{
    return -1;
}

static int
DirectFB_GetDisplayGammaRamp(_THIS, Uint16 * ramp)
{
    return -1;
}

static int
DirectFB_CreateWindow(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_DISPLAYDATA(_this, window);
    DFB_WindowData *windata;
    DFBWindowOptions wopts;
    DFBWindowDescription desc;
    int ret, x, y;

    SDL_DFB_DEBUG("Trace x %d y %d w %d h %d\n", window->x, window->y,
                  window->w, window->h);
    window->driverdata = NULL;
    SDL_DFB_CALLOC(window->driverdata, 1, sizeof(DFB_WindowData));
    windata = (DFB_WindowData *) window->driverdata;

    SDL_DFB_CHECKERR(devdata->dfb->
                     SetCooperativeLevel(devdata->dfb, DFSCL_NORMAL));
    SDL_DFB_CHECKERR(dispdata->layer->
                     SetCooperativeLevel(dispdata->layer,
                                         DLSCL_ADMINISTRATIVE));

    /* Fill the window description. */
    if (window->x == SDL_WINDOWPOS_CENTERED) {
        x = (dispdata->cw - window->w) / 2;
    } else if (window->x == SDL_WINDOWPOS_UNDEFINED) {
        x = 0;
    } else {
        x = window->x;
    }
    if (window->y == SDL_WINDOWPOS_CENTERED) {
        y = (dispdata->ch - window->h) / 2;
    } else if (window->y == SDL_WINDOWPOS_UNDEFINED) {
        y = 0;
    } else {
        y = window->y;
    }
    if (window->flags & SDL_WINDOW_FULLSCREEN) {
        x = 0;
        y = 0;
    }

    desc.flags =
        DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS | DWDESC_PIXELFORMAT |
        DWDESC_SURFACE_CAPS;
    if (!(window->flags & SDL_WINDOW_FULLSCREEN)
        && window->x != SDL_WINDOWPOS_UNDEFINED
        && window->y != SDL_WINDOWPOS_UNDEFINED) {
        desc.flags |= DWDESC_POSX | DWDESC_POSY;
        desc.posx = x;
        desc.posy = y;
    }

    desc.width = window->w;
    desc.height = window->h;
    desc.pixelformat = dispdata->pixelformat;
    desc.caps = 0;              //DWCAPS_DOUBLEBUFFER;
    desc.surface_caps = DSCAPS_DOUBLE | DSCAPS_TRIPLE;  //| DSCAPS_PREMULTIPLIED;

    /* Create the window. */
    SDL_DFB_CHECKERR(dispdata->layer->
                     CreateWindow(dispdata->layer, &desc, &windata->window));

    windata->window->GetOptions(windata->window, &wopts);
#if (DIRECTFB_MAJOR_VERSION == 1) && (DIRECTFB_MINOR_VERSION >= 0)

    if (window->flags & SDL_WINDOW_RESIZABLE)
        wopts |= DWOP_SCALE;
    else
        wopts |= DWOP_KEEP_SIZE;
#else
    wopts |= DWOP_KEEP_SIZE;    // if not we will crash ...
#endif

    if (window->flags & SDL_WINDOW_FULLSCREEN)
        wopts |= DWOP_KEEP_POSITION | DWOP_KEEP_STACKING | DWOP_KEEP_SIZE;

    windata->window->SetOptions(windata->window, wopts);
    /* Get the window's surface. */
    SDL_DFB_CHECKERR(windata->window->
                     GetSurface(windata->window, &windata->surface));
    windata->window->SetOpacity(windata->window, 0xFF);
    SDL_DFB_CHECKERR(windata->window->
                     CreateEventBuffer(windata->window,
                                       &(windata->eventbuffer)));
    SDL_DFB_CHECKERR(windata->window->
                     EnableEvents(windata->window,
                                  DWET_POSITION | DWET_SIZE | DWET_CLOSE |
                                  DWET_ALL));

    if (window->flags & SDL_WINDOW_FULLSCREEN)
        windata->window->SetStackingClass(windata->window, DWSC_UPPER);
    /* Make it the top most window. */
    windata->window->RaiseToTop(windata->window);

    windata->window->GetID(windata->window, &windata->windowID);
    windata->id = window->id;

#if SDL_DIRECTFB_OPENGL
    if (window->flags & SDL_WINDOW_OPENGL) {
        if (!_this->gl_config.driver_loaded) {
            /* no driver has been loaded, use default (ourselves) */
            if (DirectFB_GL_LoadLibrary(_this, NULL) < 0) {
                goto error;
            }
        }
        _this->gl_data->gl_active = 1;
    }
#endif

    /* Add to list ... */

    windata->next = devdata->firstwin;
    windata->opacity = 0xFF;
    devdata->firstwin = windata;

    //SDL_DFB_CHECKERR( windata->surface->GetPalette(windata->surface, &windata->palette) );

    return 0;
  error:
    SDL_DFB_RELEASE(windata->window);
    SDL_DFB_RELEASE(windata->surface);
    return -1;
}

static int
DirectFB_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    SDL_Unsupported();
    return -1;
}

static void
DirectFB_SetWindowTitle(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    SDL_Unsupported();
    //return -1;

}
static void
DirectFB_SetWindowPosition(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    if (!(window->flags & SDL_WINDOW_FULLSCREEN))
        windata->window->MoveTo(windata->window, window->x, window->y);
}

static void
DirectFB_SetWindowSize(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    if (!(window->flags & SDL_WINDOW_FULLSCREEN))
        windata->window->Resize(windata->window, window->w, window->h);
}
static void
DirectFB_ShowWindow(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    windata->window->SetOpacity(windata->window, windata->opacity);

}

static void
DirectFB_HideWindow(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    windata->window->GetOpacity(windata->window, &windata->opacity);
    windata->window->SetOpacity(windata->window, 0);

}
static void
DirectFB_RaiseWindow(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    windata->window->Raise(windata->window);

}

static void
DirectFB_MaximizeWindow(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    SDL_Unsupported();

}
static void
DirectFB_MinimizeWindow(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    SDL_Unsupported();

}

static void
DirectFB_RestoreWindow(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    SDL_Unsupported();

}
static void
DirectFB_SetWindowGrab(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    SDL_Unsupported();

}

static void
DirectFB_DestroyWindow(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);
    DFB_WindowData *p;

    SDL_DFB_DEBUG("Trace\n");

    SDL_DFB_RELEASE(windata->palette);
    SDL_DFB_RELEASE(windata->eventbuffer);
    SDL_DFB_RELEASE(windata->surface);
    SDL_DFB_RELEASE(windata->window);

    /* Remove from list ... */

    p = devdata->firstwin;
    while (p && p->next != windata)
        p = p->next;
    if (p)
        p->next = windata->next;
    else
        devdata->firstwin = windata->next;
    SDL_free(windata);
}

static SDL_bool
DirectFB_GetWindowWMInfo(_THIS, SDL_Window * window,
                         struct SDL_SysWMinfo *info)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);

    SDL_Unsupported();
    return SDL_FALSE;
}

#if SDL_DIRECTFB_OPENGL

#define OPENGL_REQUIRS_DLOPEN
#if defined(OPENGL_REQUIRS_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
#include <dlfcn.h>
#define GL_LoadObject(X)	dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
#define GL_LoadFunction		dlsym
#define GL_UnloadObject		dlclose
#else
#define GL_LoadObject	SDL_LoadObject
#define GL_LoadFunction	SDL_LoadFunction
#define GL_UnloadObject	SDL_UnloadObject
#endif

static int
DirectFB_GL_LoadLibrary(_THIS, const char *path)
{
    SDL_DFB_DEVICEDATA(_this);
#
    void *handle = NULL;

    SDL_DFB_DEBUG("Loadlibrary : %s\n", path);

    if (_this->gl_data->gl_active) {
        SDL_SetError("OpenGL context already created");
        return -1;
    }


    if (path == NULL) {
        path = SDL_getenv("SDL_VIDEO_GL_DRIVER");
        if (path == NULL) {
            path = "libGL.so";
        }
    }

    handle = GL_LoadObject(path);
    if (handle == NULL) {
        SDL_DFB_ERR("Library not found: %s\n", path);
        /* SDL_LoadObject() will call SDL_SetError() for us. */
        return -1;
    }

    SDL_DFB_DEBUG("Loaded library: %s\n", path);

    /* Unload the old driver and reset the pointers */
    DirectFB_GL_UnloadLibrary(_this);

    _this->gl_config.dll_handle = handle;
    _this->gl_config.driver_loaded = 1;
    if (path) {
        SDL_strlcpy(_this->gl_config.driver_path, path,
                    SDL_arraysize(_this->gl_config.driver_path));
    } else {
        *_this->gl_config.driver_path = '\0';
    }

    devdata->glFinish = DirectFB_GL_GetProcAddress(_this, "glFinish");
    devdata->glFlush = DirectFB_GL_GetProcAddress(_this, "glFlush");
    return 0;
}

static void
DirectFB_GL_UnloadLibrary(_THIS)
{
    SDL_DFB_DEVICEDATA(_this);

    int ret;

    if (_this->gl_config.driver_loaded) {

        ret = GL_UnloadObject(_this->gl_config.dll_handle);
        if (ret)
            SDL_DFB_ERR("Error #%d trying to unload library.\n", ret);
        _this->gl_config.dll_handle = NULL;
        _this->gl_config.driver_loaded = 0;
    }
}

static void *
DirectFB_GL_GetProcAddress(_THIS, const char *proc)
{
    SDL_DFB_DEVICEDATA(_this);
    int ret;
    void *handle;

    SDL_DFB_DEBUG("Trace %s\n", proc);
    handle = _this->gl_config.dll_handle;
    return GL_LoadFunction(handle, proc);
}

static SDL_GLContext
DirectFB_GL_CreateContext(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);
    int ret;
    IDirectFBGL *context = NULL;

    SDL_DFB_DEBUG("Trace\n");
    SDL_DFB_CHECKERR(windata->surface->GetGL(windata->surface, &context));
    SDL_DFB_CHECKERR(context->Unlock(context));

    if (DirectFB_GL_MakeCurrent(_this, window, context) < 0) {
        DirectFB_GL_DeleteContext(_this, context);
        return NULL;
    }

    return context;

  error:
    return NULL;
}

static int
DirectFB_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);
    IDirectFBGL *dfb_context = (IDirectFBGL *) context;
    int ret;

    if (dfb_context) {
        dfb_context->Unlock(dfb_context);
        SDL_DFB_CHECKERR(dfb_context->Lock(dfb_context));
    }
    if (windata)
        windata->gl_context = dfb_context;

    return 0;
  error:
    return -1;
}

static int
DirectFB_GL_SetSwapInterval(_THIS, int interval)
{
    SDL_DFB_DEVICEDATA(_this);

    SDL_Unsupported();
    return -1;

}

static int
DirectFB_GL_GetSwapInterval(_THIS)
{
    SDL_DFB_DEVICEDATA(_this);

    SDL_Unsupported();
    return -1;

}

static void
DirectFB_GL_SwapWindow(_THIS, SDL_Window * window)
{
    SDL_DFB_DEVICEDATA(_this);
    SDL_DFB_WINDOWDATA(window);
    SDL_DFB_DISPLAYDATA(_this, window);
    int ret;
    void *p;
    int pitch;
    DFBRegion region;

    region.x1 = 0;
    region.y1 = 0;
    region.x2 = window->w;
    region.y2 = window->h;

    if (devdata->glFinish)
        devdata->glFinish();
    else if (devdata->glFlush)
        devdata->glFlush();

    SDL_DFB_CHECKERR(windata->gl_context->Unlock(windata->gl_context));
    SDL_DFB_CHECKERR(windata->surface->
                     Flip(windata->surface, &region, DSFLIP_ONSYNC));
    SDL_DFB_CHECKERR(windata->gl_context->Lock(windata->gl_context));

    return;
  error:
    return;
}

static void
DirectFB_GL_DeleteContext(_THIS, SDL_GLContext context)
{
    IDirectFBGL *dfb_context = (IDirectFBGL *) context;
    SDL_DFB_DEVICEDATA(_this);

    dfb_context->Unlock(dfb_context);
    dfb_context->Release(dfb_context);
}

#endif