view src/video/photon/SDL_photon.c @ 3168:6338b7f2d024

Hi, I have prepared a set of patches to readd WindowsCE support to SDL 1.3. I've created a new GAPI/Rawframebuffer and a DirectDraw renderer. Both renderers are work in progress and there are several unimplemented cases. (Notably RenderLine/RenderPoint/RenderFill/QueryTexturePixels/UpdateTexture and texture blending ) Nevertheless I am successfully using these renderers together with the SDL software renderer. (On most devices the SDL software renderer will be much faster as there are only badly optimized vendor drivers available) I send these patches now in this unpolished state because there seems to be some interest in win ce and someone has to start supporting SDL 1.3 Now on to the patches: wince_events_window_fixes.patch fixes some wince incompatibilities and adds fullscreen support via SHFullScreen. NOTE: This patch shouldn't have any side effects on Windows, but I have NOT tested it on Windows, so please double-check. This patch doesn't dependent on the following ones. wince_renderers_system.patch This patch does all necessary modifications to the SDL system. - it adds the renderers to the configure system - it adds the renderers to win32video SDL_ceddrawrender.c SDL_ceddrawrender.h SDL_gapirender_c.h SDL_gapirender.c SDL_gapirender.h these files add the new render drivers and should be placed in src/video/win32 Some notes to people who want to test this: - I have only compiled sdl with ming32ce, so the VisualC files are not up to date - As mingw32ce has no ddraw.h this file must be taken from the MS SDK and modified to work with gcc - I had to modify line 2611 in configure.in to EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lcoredll -lcommctrl -lmmtimer -Wl,--image-base -Wl,0x10000" otherwise GetCPinfo wouldn't link. If someone knows whats causing this I'd be happy to hear about it. It would be great if these patches could make their way into SVN as this would make collaboration much much easier. I'm out of office for the next week and therefore will be unavailable via email. Regards Stefan
author Sam Lantinga <slouken@libsdl.org>
date Sun, 07 Jun 2009 02:44:46 +0000
parents 7f684f249ec9
children 44d5474c2c8a
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2009 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

    QNX Photon GUI SDL driver
    Copyright (C) 2009 Mike Gorchak
    (mike@malva.ua, lestat@i.com.ua)
*/

/* SDL internals */
#include "SDL_config.h"
#include "../SDL_sysvideo.h"
#include "SDL_version.h"
#include "SDL_syswm.h"
#include "SDL_loadso.h"
#include "SDL_events.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_keyboard_c.h"

/* Photon declarations */
#include "SDL_photon.h"

/* Pixel format conversion routines */
#include "SDL_photon_pixelfmt.h"

/* Use GF's pixel format functions for OpenGL ES context creation */
#if defined(SDL_VIDEO_OPENGL_ES)
#include "../qnxgf/SDL_gf_pixelfmt.h"

   /* If GF driver is not compiled in, include some of usefull functions */
#if !defined(SDL_VIDEO_DRIVER_QNXGF)
#include "../qnxgf/SDL_gf_pixelfmt.c"
#endif /* SDL_VIDEO_DRIVER_QNXGF */
#endif /* SDL_VIDEO_OPENGL_ES */

/* Use GF's OpenGL ES 1.1 functions emulation */
#if defined(SDL_VIDEO_OPENGL_ES)
#include "../qnxgf/SDL_gf_opengles.h"

   /* If GF driver is not compiled in, include some of usefull functions */
#if !defined(SDL_VIDEO_DRIVER_QNXGF)
#include "../qnxgf/SDL_gf_opengles.c"
#endif /* SDL_VIDEO_DRIVER_QNXGF */
#endif /* SDL_VIDEO_OPENGL_ES */

/* Low level device graphics driver names, which they are reporting */
Photon_DeviceCaps photon_devicename[] = {
    /* ATI Rage 128 graphics driver (devg-ati_rage128)      */
    {"ati_rage128", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* Fujitsu Carmine graphics driver (devg-carmine.so)    */
    {"carmine", SDL_PHOTON_ACCELERATED | SDL_PHOTON_ACCELERATED_3D}
    ,
    /* C&T graphics driver (devg-chips.so)                  */
    {"chips", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* Fujitsu Coral graphics driver (devg-coral.so)        */
    {"coral", SDL_PHOTON_ACCELERATED | SDL_PHOTON_ACCELERATED_3D}
    ,
    /* Intel integrated graphics driver (devg-extreme2.so)  */
    {"extreme2", SDL_PHOTON_ACCELERATED | SDL_PHOTON_ACCELERATED_3D}
    ,
    /* Unaccelerated FB driver (devg-flat.so)               */
    {"flat", SDL_PHOTON_UNACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* NS Geode graphics driver (devg-geode.so)             */
    {"geode", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* Geode LX graphics driver (devg-geodelx.so)           */
    {"geodelx", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* Intel integrated graphics driver (devg-gma9xx.so)    */
    {"gma", SDL_PHOTON_ACCELERATED | SDL_PHOTON_ACCELERATED_3D}
    ,
    /* Intel integrated graphics driver (devg-i810.so)      */
    {"i810", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* Intel integrated graphics driver (devg-i830.so)      */
    {"i830", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* Geode LX graphics driver (devg-lx800.so)             */
    {"lx800", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* Matrox Gxx graphics driver (devg-matroxg.so)         */
    {"matroxg", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* Intel Poulsbo graphics driver (devg-poulsbo.so)      */
    {"poulsbo", SDL_PHOTON_ACCELERATED | SDL_PHOTON_ACCELERATED_3D}
    ,
    /* ATI Radeon driver (devg-radeon.so)                   */
    {"radeon", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* ATI Rage driver (devg-rage.so)                       */
    {"rage", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* S3 Savage graphics driver (devg-s3_savage.so)        */
    {"s3_savage", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* SiS630 integrated graphics driver (devg-sis630.so)   */
    {"sis630", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* PowerVR SGX 535 graphics driver (devg-poulsbo.so)    */
    {"sgx", SDL_PHOTON_ACCELERATED | SDL_PHOTON_ACCELERATED_3D}
    ,
    /* SM Voyager GX graphics driver (devg-smi5xx.so)       */
    {"smi5xx", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* Silicon Motion graphics driver (devg-smi7xx.so)      */
    {"smi7xx", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* SVGA unaccelerated gfx driver (devg-svga.so)         */
    {"svga", SDL_PHOTON_UNACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* nVidia TNT graphics driver (devg-tnt.so)             */
    {"tnt", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* VIA integrated graphics driver (devg-tvia.so)        */
    {"tvia", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* VIA UniChrome graphics driver (devg-unichrome.so)    */
    {"unichrome", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* VESA unaccelerated gfx driver (devg-vesa.so)         */
    {"vesa", SDL_PHOTON_UNACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* VmWare graphics driver (devg-volari.so)              */
    {"vmware", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* XGI XP10 graphics driver (devg-volari.so), OpenGL 1.5 */
    {"volari", SDL_PHOTON_ACCELERATED | SDL_PHOTON_UNACCELERATED_3D}
    ,
    /* End of list */
    {NULL, 0x00000000}
};

static SDL_bool photon_initialized = SDL_FALSE;

static int
photon_available(void)
{
    int status;

    /* Check if Photon was initialized before */
    if (photon_initialized == SDL_FALSE) {
        /* Initialize Photon widget library and open channel to Photon */
        status = PtInit(NULL);
        if (status == 0) {
            photon_initialized = SDL_TRUE;
            return 1;
        } else {
            photon_initialized = SDL_FALSE;
            return 0;
        }
    }

    return 1;
}

static void
photon_destroy(SDL_VideoDevice * device)
{
    SDL_VideoData *phdata = (SDL_VideoData *) device->driverdata;

#if defined(SDL_VIDEO_OPENGL_ES)
    if (phdata->gfinitialized != SDL_FALSE) {
        gf_dev_detach(phdata->gfdev);
    }
#endif /* SDL_VIDEO_OPENGL_ES */

    if (device->driverdata != NULL) {
        device->driverdata = NULL;
    }
}

static SDL_VideoDevice *
photon_create(int devindex)
{
    SDL_VideoDevice *device;
    SDL_VideoData *phdata;
    int status;

    /* Check if photon could be initialized */
    status = photon_available();
    if (status == 0) {
        /* Photon could not be used */
        return NULL;
    }

    /* Photon agregates all video devices to one with multiple heads */
    if (devindex != 0) {
        /* devindex could be zero only in Photon SDL driver */
        return NULL;
    }

    /* Initialize SDL_VideoDevice structure */
    device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
    if (device == NULL) {
        SDL_OutOfMemory();
        return NULL;
    }

    /* Initialize internal photon specific data */
    phdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
    if (phdata == NULL) {
        SDL_OutOfMemory();
        SDL_free(device);
        return NULL;
    }
    device->driverdata = phdata;

    /* Get all photon display devices */
    phdata->avail_rids =
        PdGetDevices(&phdata->rid[0], SDL_VIDEO_PHOTON_MAX_RIDS);
    if (phdata->avail_rids > SDL_VIDEO_PHOTON_MAX_RIDS) {
        phdata->avail_rids = SDL_VIDEO_PHOTON_MAX_RIDS;
    }
#if defined(SDL_VIDEO_OPENGL_ES)
    /* TODO: add real device detection versus multiple heads */
    status =
        gf_dev_attach(&phdata->gfdev, GF_DEVICE_INDEX(0),
                      &phdata->gfdev_info);
    if (status != GF_ERR_OK) {
        /* Do not fail right now, if GF can't be attached */
        phdata->gfinitialized = SDL_FALSE;
    } else {
        phdata->gfinitialized = SDL_TRUE;
    }
#endif /* SDL_VIDEO_OPENGL_ES */

    /* Set default target device */
    status = PdSetTargetDevice(NULL, phdata->rid[0]);
    if (status == -1) {
        SDL_SetError("Photon: Can't set default target device");
#if defined(SDL_VIDEO_OPENGL_ES)
        gf_dev_detach(phdata->gfdev);
#endif /* SDL_VIDEO_OPENGL_ES */
        SDL_free(phdata);
        SDL_free(device);
        return NULL;
    }
    phdata->current_device_id = 0;

    /* Setup amount of available displays and current display */
    device->num_displays = 0;
    device->current_display = 0;

    /* Set device free function */
    device->free = photon_destroy;

    /* Setup all functions which we can handle */
    device->VideoInit = photon_videoinit;
    device->VideoQuit = photon_videoquit;
    device->GetDisplayModes = photon_getdisplaymodes;
    device->SetDisplayMode = photon_setdisplaymode;
    device->SetDisplayPalette = photon_setdisplaypalette;
    device->GetDisplayPalette = photon_getdisplaypalette;
    device->SetDisplayGammaRamp = photon_setdisplaygammaramp;
    device->GetDisplayGammaRamp = photon_getdisplaygammaramp;
    device->CreateWindow = photon_createwindow;
    device->CreateWindowFrom = photon_createwindowfrom;
    device->SetWindowTitle = photon_setwindowtitle;
    device->SetWindowIcon = photon_setwindowicon;
    device->SetWindowPosition = photon_setwindowposition;
    device->SetWindowSize = photon_setwindowsize;
    device->ShowWindow = photon_showwindow;
    device->HideWindow = photon_hidewindow;
    device->RaiseWindow = photon_raisewindow;
    device->MaximizeWindow = photon_maximizewindow;
    device->MinimizeWindow = photon_minimizewindow;
    device->RestoreWindow = photon_restorewindow;
    device->SetWindowGrab = photon_setwindowgrab;
    device->DestroyWindow = photon_destroywindow;
    device->GetWindowWMInfo = photon_getwindowwminfo;
    device->GL_LoadLibrary = photon_gl_loadlibrary;
    device->GL_GetProcAddress = photon_gl_getprocaddres;
    device->GL_UnloadLibrary = photon_gl_unloadlibrary;
    device->GL_CreateContext = photon_gl_createcontext;
    device->GL_MakeCurrent = photon_gl_makecurrent;
    device->GL_SetSwapInterval = photon_gl_setswapinterval;
    device->GL_GetSwapInterval = photon_gl_getswapinterval;
    device->GL_SwapWindow = photon_gl_swapwindow;
    device->GL_DeleteContext = photon_gl_deletecontext;
    device->PumpEvents = photon_pumpevents;
    device->SuspendScreenSaver = photon_suspendscreensaver;

    return device;
}

VideoBootStrap photon_bootstrap = {
    "photon",
    "SDL QNX Photon video driver",
    photon_available,
    photon_create
};

/*****************************************************************************/
/* SDL Video and Display initialization/handling functions                   */
/*****************************************************************************/
int
photon_videoinit(_THIS)
{
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    PgHWCaps_t hwcaps;
    PgVideoModeInfo_t modeinfo;
    int32_t status;
    SDL_VideoDisplay display;
    SDL_DisplayMode current_mode;
    SDL_DisplayData *didata;
    uint32_t it;
    uint32_t jt;
    char *override;

    /* By default Photon do not uses swap on VSYNC */
    phdata->swapinterval = 0;

    for (it = 0; it < phdata->avail_rids; it++) {
        didata = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
        if (didata == NULL) {
            /* memory allocation error */
            SDL_OutOfMemory();
            return -1;
        }

        /* Allocate two cursors with SDL_VIDEO_PHOTON_MAX_CURSOR_SIZE size */
        /* and 128 bytes of spare place                                    */
        didata->cursor_size =
            ((SDL_VIDEO_PHOTON_MAX_CURSOR_SIZE * 4) >> 3) + 128;
        didata->cursor = (PhCursorDef_t *) SDL_calloc(1, didata->cursor_size);
        if (didata->cursor == NULL) {
            /* memory allocation error */
            SDL_OutOfMemory();
            SDL_free(didata);
            return -1;
        }

        /* Initialize GF in case of OpenGL ES support is compiled in */
#if defined(SDL_VIDEO_OPENGL_ES)
        /* TODO: add real device detection versus multiple heads */
        if (phdata->gfinitialized == SDL_TRUE) {
            status =
                gf_display_attach(&didata->display, phdata->gfdev, it,
                                  &didata->display_info);
            if (status != GF_ERR_OK) {
                /* Just shutdown GF, do not fail */
                gf_dev_detach(phdata->gfdev);
                phdata->gfinitialized = SDL_FALSE;
            }
        }
#endif /* SDL_VIDEO_OPENGL_ES */

        /* Check if current device is not the same as target */
        if (phdata->current_device_id != it) {
            /* Set target device as default for Pd and Pg functions */
            status = PdSetTargetDevice(NULL, phdata->rid[it]);
            if (status != 0) {
                SDL_SetError("Photon: Can't set default target device\n");
                SDL_free(didata->cursor);
                SDL_free(didata);
                return -1;
            }
            phdata->current_device_id = it;
        }

        /* Store device id */
        didata->device_id = it;

        /* Query photon about graphics hardware caps and current video mode */
        status = PgGetGraphicsHWCaps(&hwcaps);
        if (status != 0) {
            SDL_SetError("Photon: Can't get graphics capabilities");
            SDL_free(didata->cursor);
            SDL_free(didata);
            return -1;
        }

        /* Get current video mode details */
        status = PgGetVideoModeInfo(hwcaps.current_video_mode, &modeinfo);
        if (status != 0) {
            SDL_SetError("Photon: Can't get current video mode information");
            SDL_free(didata->cursor);
            SDL_free(didata);
            return -1;
        }

        /* Setup current desktop mode for SDL */
        SDL_zero(current_mode);
        current_mode.w = modeinfo.width;
        current_mode.h = modeinfo.height;
        current_mode.refresh_rate = hwcaps.current_rrate;
        current_mode.format = photon_image_to_sdl_pixelformat(modeinfo.type);
        current_mode.driverdata = NULL;

        /* Copy device name */
        SDL_strlcpy(didata->description, hwcaps.chip_name,
                    SDL_VIDEO_PHOTON_DEVICENAME_MAX - 1);

        /* Search device capabilities and possible workarounds */
        jt = 0;
        do {
            if (photon_devicename[jt].name == NULL) {
                break;
            }
            if (SDL_strncmp
                (photon_devicename[jt].name, didata->description,
                 SDL_strlen(photon_devicename[jt].name)) == 0) {
                didata->caps = photon_devicename[jt].caps;
            }
            jt++;
        } while (1);

        /* Initialize display structure */
        SDL_zero(display);
        display.desktop_mode = current_mode;
        display.current_mode = current_mode;
        display.driverdata = didata;
        didata->current_mode = current_mode;
        SDL_AddVideoDisplay(&display);

        /* Check for environment variables which could override some SDL settings */
        didata->custom_refresh = 0;
        override = SDL_getenv("SDL_VIDEO_PHOTON_REFRESH_RATE");
        if (override != NULL) {
            if (SDL_sscanf(override, "%u", &didata->custom_refresh) != 1) {
                didata->custom_refresh = 0;
            }
        }
    }

    /* Add photon input devices */
    status = photon_addinputdevices(_this);
    if (status != 0) {
        /* SDL error is set by photon_addinputdevices() function */
        return -1;
    }

    /* Add photon renderer to SDL */
    photon_addrenderdriver(_this);

    /* video has been initialized successfully */
    return 1;
}

void
photon_videoquit(_THIS)
{
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    SDL_DisplayData *didata;
    uint32_t it;

    /* SDL will restore our desktop mode on exit */
    for (it = 0; it < _this->num_displays; it++) {
        didata = _this->displays[it].driverdata;

        if (didata->cursor != NULL) {
            SDL_free(didata->cursor);
        }
#if defined(SDL_VIDEO_OPENGL_ES)
        if (phdata->gfinitialized == SDL_TRUE) {
            /* Detach GF display */
            gf_display_detach(didata->display);
        }
#endif /* SDL_VIDEO_OPENGL_ES */
    }
}

void
photon_getdisplaymodes(_THIS)
{
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    SDL_DisplayMode mode;
    PgVideoModes_t modes;
    PgVideoModeInfo_t modeinfo;
    int32_t status;
    uint32_t it;
    uint32_t jt;

    /* Check if current device is not the same as target */
    if (phdata->current_device_id != didata->device_id) {
        /* Set target device as default for Pd and Pg functions */
        status = PdSetTargetDevice(NULL, phdata->rid[didata->device_id]);
        if (status != 0) {
            SDL_SetError("Photon: Can't set default target device\n");
            return;
        }
        phdata->current_device_id = didata->device_id;
    }

    /* Get array of available video modes */
    status = PgGetVideoModeList(&modes);
    if (status != 0) {
        SDL_SetError("Photon: Can't get video mode list");
        return;
    }

    for (it = 0; it < modes.num_modes; it++) {
        status = PgGetVideoModeInfo(modes.modes[it], &modeinfo);
        if (status != 0) {
            /* Maybe something wrong with this particular mode, skip it */
            continue;
        }

        jt = 0;
        do {
            if (modeinfo.refresh_rates[jt] != 0) {
                mode.w = modeinfo.width;
                mode.h = modeinfo.height;
                mode.refresh_rate = modeinfo.refresh_rates[jt];
                mode.format = photon_image_to_sdl_pixelformat(modeinfo.type);
                mode.driverdata = NULL;
                SDL_AddDisplayMode(_this->current_display, &mode);
                jt++;
            } else {
                break;
            }
        } while (1);
    }
}

int
photon_setdisplaymode(_THIS, SDL_DisplayMode * mode)
{
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    PgVideoModes_t modes;
    PgVideoModeInfo_t modeinfo;
    PgDisplaySettings_t modesettings;
    uint32_t refresh_rate = 0;
    int32_t status;
    uint32_t it;

    /* Check if current device is not the same as target */
    if (phdata->current_device_id != didata->device_id) {
        /* Set target device as default for Pd and Pg functions */
        status = PdSetTargetDevice(NULL, phdata->rid[didata->device_id]);
        if (status != 0) {
            SDL_SetError("Photon: Can't set default target device\n");
            return;
        }
        phdata->current_device_id = didata->device_id;
    }

    /* Get array of available video modes */
    status = PgGetVideoModeList(&modes);
    if (status != 0) {
        SDL_SetError("Photon: Can't get video mode list");
        return;
    }

    /* Current display dimension and bpp are no more valid */
    didata->current_mode.format = SDL_PIXELFORMAT_UNKNOWN;
    didata->current_mode.w = 0;
    didata->current_mode.h = 0;

    /* Check if custom refresh rate requested */
    if (didata->custom_refresh != 0) {
        refresh_rate = didata->custom_refresh;
    } else {
        refresh_rate = mode->refresh_rate;
    }

    /* Check if SDL GF driver needs to find appropriate refresh rate itself */
    if (refresh_rate == 0) {
        SDL_DisplayMode tempmode;

        /* Clear display mode structure */
        SDL_memset(&tempmode, 0x00, sizeof(SDL_DisplayMode));
        tempmode.refresh_rate = 0x0000FFFF;

        /* Check if window width and height matches one of our modes */
        for (it = 0; it < SDL_CurrentDisplay.num_display_modes; it++) {
            if ((SDL_CurrentDisplay.display_modes[it].w == mode->w) &&
                (SDL_CurrentDisplay.display_modes[it].h == mode->h) &&
                (SDL_CurrentDisplay.display_modes[it].format == mode->format))
            {
                /* Find the lowest refresh rate available */
                if (tempmode.refresh_rate >
                    SDL_CurrentDisplay.display_modes[it].refresh_rate) {
                    tempmode = SDL_CurrentDisplay.display_modes[it];
                }
            }
        }
        if (tempmode.refresh_rate != 0x0000FFFF) {
            refresh_rate = tempmode.refresh_rate;
        } else {
            /* Let video driver decide what to do with this */
            refresh_rate = 0;
        }
    }

    /* Check if SDL GF driver needs to check custom refresh rate */
    if (didata->custom_refresh != 0) {
        SDL_DisplayMode tempmode;

        /* Clear display mode structure */
        SDL_memset(&tempmode, 0x00, sizeof(SDL_DisplayMode));
        tempmode.refresh_rate = 0x0000FFFF;

        /* Check if window width and height matches one of our modes */
        for (it = 0; it < SDL_CurrentDisplay.num_display_modes; it++) {
            if ((SDL_CurrentDisplay.display_modes[it].w == mode->w) &&
                (SDL_CurrentDisplay.display_modes[it].h == mode->h) &&
                (SDL_CurrentDisplay.display_modes[it].format == mode->format))
            {
                /* Find the lowest refresh rate available */
                if (tempmode.refresh_rate >
                    SDL_CurrentDisplay.display_modes[it].refresh_rate) {
                    tempmode = SDL_CurrentDisplay.display_modes[it];
                }

                /* Check if requested refresh rate found */
                if (refresh_rate ==
                    SDL_CurrentDisplay.display_modes[it].refresh_rate) {
                    tempmode = SDL_CurrentDisplay.display_modes[it];
                    break;
                }
            }
        }
        if (tempmode.refresh_rate != 0x0000FFFF) {
            refresh_rate = tempmode.refresh_rate;
        } else {
            /* Let video driver decide what to do with this */
            refresh_rate = 0;
        }
    }

    /* Find photon's video mode number */
    for (it = 0; it < modes.num_modes; it++) {
        uint32_t jt;
        uint32_t foundrefresh;

        /* Get current video mode details */
        status = PgGetVideoModeInfo(modes.modes[it], &modeinfo);
        if (status != 0) {
            /* Maybe something wrong with this particular mode, skip it */
            continue;
        }
        if ((modeinfo.width == mode->w) && (modeinfo.height == mode->h) &&
            (modeinfo.type == photon_sdl_to_image_pixelformat(mode->format)))
        {
            /* Mode is found, find requested refresh rate, this case is for */
            /* video drivers, which provide non-generic video modes.        */
            jt = 0;
            foundrefresh = 0;
            do {
                if (modeinfo.refresh_rates[jt] != 0) {
                    if (modeinfo.refresh_rates[jt] == refresh_rate) {
                        foundrefresh = 1;
                        break;
                    }
                    jt++;
                } else {
                    break;
                }
            } while (1);
            if (foundrefresh != 0) {
                break;
            }
        }
    }

    /* Check if video mode has not been found */
    if (it == modes.num_modes) {
        SDL_SetError("Photon: Can't find appropriate video mode");
        return -1;
    }

    /* Fill mode settings */
    modesettings.flags = 0x00000000;
    modesettings.mode = modes.modes[it];
    modesettings.refresh = refresh_rate;

    /* Finally set new video mode */
    status = PgSetVideoMode(&modesettings);
    if (status != 0) {
        SDL_SetError("Photon: Can't set new video mode");
        return -1;
    }

    /* Store new video mode parameters */
    didata->current_mode = *mode;
    didata->current_mode.refresh_rate = refresh_rate;

    return 0;
}

int
photon_setdisplaypalette(_THIS, SDL_Palette * palette)
{
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;

    /* Setting display palette operation has been failed */
    return -1;
}

int
photon_getdisplaypalette(_THIS, SDL_Palette * palette)
{
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;

    /* Getting display palette operation has been failed */
    return -1;
}

int
photon_setdisplaygammaramp(_THIS, Uint16 * ramp)
{
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;

    /* Setting display gamma ramp operation has been failed */
    return -1;
}

int
photon_getdisplaygammaramp(_THIS, Uint16 * ramp)
{
    /* Getting display gamma ramp operation has been failed */
    return -1;
}

int
photon_createwindow(_THIS, SDL_Window * window)
{
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    SDL_WindowData *wdata;
    PhDim_t winsize;
    PhPoint_t winpos;
    PtArg_t winargs[32];
    uint32_t winargc = 0;
    int32_t status;
    PhRegion_t wregion;

    /* Allocate window internal data */
    wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
    if (wdata == NULL) {
        SDL_OutOfMemory();
        return -1;
    }

    /* Setup driver data for this window */
    window->driverdata = wdata;

    /* Set initial window title */
    if (window->title != NULL) {
        PtSetArg(&winargs[winargc++], Pt_ARG_WINDOW_TITLE, window->title, 0);
    } else {
        PtSetArg(&winargs[winargc++], Pt_ARG_WINDOW_TITLE, "", 0);
    }

    /* TODO: handle SDL_WINDOW_INPUT_GRABBED */

    /* Disable default window filling on redraw */
    PtSetArg(&winargs[winargc++], Pt_ARG_BASIC_FLAGS, Pt_TRUE,
             Pt_BASIC_PREVENT_FILL);

    /* Reset default managed flags to disabled state */
    PtSetArg(&winargs[winargc++], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE,
             Ph_WM_APP_DEF_MANAGED);
    /* Set which events we will not handle, let WM to handle them */
    PtSetArg(&winargs[winargc++], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_TRUE,
             Ph_WM_BACKDROP | Ph_WM_TOFRONT | Ph_WM_COLLAPSE | Ph_WM_FFRONT |
             Ph_WM_FOCUS | Ph_WM_HELP | Ph_WM_HIDE | Ph_WM_MAX |
             Ph_WM_MENU | Ph_WM_MOVE | Ph_WM_RESTORE | Ph_WM_TASKBAR |
             Ph_WM_TOBACK | Ph_WM_RESIZE);

    /* Reset default notify events to disable */
    PtSetArg(&winargs[winargc++], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_FALSE,
             Ph_WM_RESIZE | Ph_WM_CLOSE | Ph_WM_HELP);
    /* Set which events we will handle */
    PtSetArg(&winargs[winargc++], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE,
             Ph_WM_CLOSE | Ph_WM_COLLAPSE | Ph_WM_FOCUS | Ph_WM_MAX |
             Ph_WM_MOVE | Ph_WM_RESIZE | Ph_WM_RESTORE | Ph_WM_HIDE);

    /* Borderless window can't be resizeable */
    if ((window->flags & SDL_WINDOW_BORDERLESS) == SDL_WINDOW_BORDERLESS) {
        window->flags &= ~(SDL_WINDOW_RESIZABLE);
    }

    /* Reset all default decorations */
    PtSetArg(&winargs[winargc++], Pt_ARG_WINDOW_RENDER_FLAGS, Pt_FALSE,
             Ph_WM_APP_DEF_RENDER);

    /* Fullscreen window has its own decorations */
    if ((window->flags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN) {
        window->flags |= SDL_WINDOW_BORDERLESS;
        window->flags &= ~(SDL_WINDOW_RESIZABLE);
        PtSetArg(&winargs[winargc++], Pt_ARG_WINDOW_RENDER_FLAGS, Pt_TRUE,
                 Ph_WM_RENDER_CLOSE | Ph_WM_RENDER_TITLE);
    } else {
        uint32_t decorations =
            Ph_WM_RENDER_CLOSE | Ph_WM_RENDER_MENU | Ph_WM_RENDER_MIN |
            Ph_WM_RENDER_TITLE | Ph_WM_RENDER_MOVE;

        if ((window->flags & SDL_WINDOW_RESIZABLE) == SDL_WINDOW_RESIZABLE) {
            decorations |=
                Ph_WM_RENDER_BORDER | Ph_WM_RENDER_RESIZE | Ph_WM_RENDER_MAX;
            PtSetArg(&winargs[winargc++], Pt_ARG_RESIZE_FLAGS, Pt_TRUE,
                     Pt_RESIZE_XY_AS_REQUIRED);
        }
        if ((window->flags & SDL_WINDOW_BORDERLESS) != SDL_WINDOW_BORDERLESS) {
            decorations |= Ph_WM_RENDER_BORDER;
        }
        PtSetArg(&winargs[winargc++], Pt_ARG_WINDOW_RENDER_FLAGS, Pt_TRUE,
                 decorations);
    }

    /* Set initial window state */
    PtSetArg(&winargs[winargc++], Pt_ARG_WINDOW_STATE, Pt_FALSE,
             Ph_WM_STATE_ISFOCUS);
    PtSetArg(&winargs[winargc++], Pt_ARG_WINDOW_STATE, Pt_TRUE,
             Ph_WM_STATE_ISALTKEY);

    /* Set window dimension */
    winsize.w = window->w;
    winsize.h = window->h;
    PtSetArg(&winargs[winargc++], Pt_ARG_DIM, &winsize, 0);

    /* Check if upper level requests WM to position window */
    if ((window->x == SDL_WINDOWPOS_UNDEFINED)
        && (window->y == SDL_WINDOWPOS_UNDEFINED)) {
        /* Do not set widget position, let WM to set it */
    } else {
        if (window->x == SDL_WINDOWPOS_UNDEFINED) {
            window->x = 0;
        }
        if (window->y == SDL_WINDOWPOS_UNDEFINED) {
            window->y = 0;
        }
        if (window->x == SDL_WINDOWPOS_CENTERED) {
            window->x = (didata->current_mode.w - window->w) / 2;
        }
        if (window->y == SDL_WINDOWPOS_CENTERED) {
            window->y = (didata->current_mode.h - window->h) / 2;
        }

        /* Now set window position */
        winpos.x = window->x;
        winpos.y = window->y;
        PtSetArg(&winargs[winargc++], Pt_ARG_POS, &winpos, 0);
    }

    /* Check if window must support OpenGL ES rendering */
    if ((window->flags & SDL_WINDOW_OPENGL) == SDL_WINDOW_OPENGL) {
#if defined(SDL_VIDEO_OPENGL_ES)
        EGLBoolean initstatus;

        /* Check if GF was initialized correctly */
        if (phdata->gfinitialized == SDL_FALSE) {
            SDL_SetError
                ("Photon: GF initialization failed, no OpenGL ES support");
            return -1;
        }

        /* Mark this window as OpenGL ES compatible */
        wdata->uses_gles = SDL_TRUE;

        /* Create connection to OpenGL ES */
        if (phdata->egldisplay == EGL_NO_DISPLAY) {
            phdata->egldisplay = eglGetDisplay(phdata->gfdev);
            if (phdata->egldisplay == EGL_NO_DISPLAY) {
                SDL_SetError("Photon: Can't get connection to OpenGL ES");
                return -1;
            }

            /* Initialize OpenGL ES library, ignore EGL version */
            initstatus = eglInitialize(phdata->egldisplay, NULL, NULL);
            if (initstatus != EGL_TRUE) {
                SDL_SetError("Photon: Can't init OpenGL ES library");
                return -1;
            }
        }

        /* Increment GL ES reference count usage */
        phdata->egl_refcount++;
#else
        SDL_SetError("Photon: OpenGL ES support is not compiled in");
        return -1;
#endif /* SDL_VIDEO_OPENGL_ES */
    }

    /* Finally create the window */
    wdata->window = PtCreateWidget(PtWindow, Pt_NO_PARENT, winargc, winargs);
    if (wdata->window == NULL) {
        SDL_SetError("Photon: Can't create window widget");
        SDL_free(wdata);
        return -1;
    }

    /* Show widget */
    status = PtRealizeWidget(wdata->window);
    if (status != 0) {
        SDL_SetError("Photon: Can't realize window widget");
        PtDestroyWidget(wdata->window);
        SDL_free(wdata);
        return;
    }

    /* Just created SDL window always gets focus */
    window->flags |= SDL_WINDOW_INPUT_FOCUS;

    /* Create window-specific cursor after creation */
    if (didata->cursor_visible == SDL_TRUE) {
        /* Setup cursor type. shape and default color */
        PtSetResource(wdata->window, Pt_ARG_CURSOR_COLOR,
                      Ph_CURSOR_DEFAULT_COLOR, 0);
        PtSetResource(wdata->window, Pt_ARG_CURSOR_TYPE, Ph_CURSOR_BITMAP, 0);
        PtSetResource(wdata->window, Pt_ARG_BITMAP_CURSOR, didata->cursor,
                      didata->cursor->hdr.len + sizeof(PhRegionDataHdr_t));
    } else {
        PtSetResource(wdata->window, Pt_ARG_CURSOR_TYPE, Ph_CURSOR_NONE, 0);
    }

    /* Set window region sensible to mouse motion events */
    status =
        PhRegionQuery(PtWidgetRid(wdata->window), &wregion, NULL, NULL, 0);
    if (status != 0) {
        SDL_SetError
            ("Photon: Can't set region sensivity to mouse motion events");
        PtDestroyWidget(wdata->window);
        SDL_free(wdata);
        return -1;
    }
    wregion.events_sense |=
        Ph_EV_PTR_MOTION_BUTTON | Ph_EV_PTR_MOTION_NOBUTTON;
    status = PhRegionChange(Ph_REGION_EV_SENSE, 0, &wregion, NULL, NULL);
    if (status < 0) {
        SDL_SetError("Photon: Can't change region sensivity");
        PtDestroyWidget(wdata->window);
        SDL_free(wdata);
        return -1;
    }

    /* Flush all widget operations again */
    PtFlush();

    /* By default last created window got a input focus */
    SDL_SetKeyboardFocus(0, window->id);

    /* Window has been successfully created */
    return 0;
}

int
photon_createwindowfrom(_THIS, SDL_Window * window, const void *data)
{
    /* TODO: it is possible */

    /* Failed to create window from another window */
    return -1;
}

void
photon_setwindowtitle(_THIS, SDL_Window * window)
{
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    int32_t status;

    /* Set window title */
    if (window->title != NULL) {
        status =
            PtSetResource(wdata->window, Pt_ARG_WINDOW_TITLE, window->title,
                          0);
    } else {
        status = PtSetResource(wdata->window, Pt_ARG_WINDOW_TITLE, "", 0);
    }

    if (status != 0) {
        SDL_SetError("Photon: Can't set window title");
    }

    /* Flush all widget operations */
    PtFlush();
}

void
photon_setwindowicon(_THIS, SDL_Window * window, SDL_Surface * icon)
{
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    int32_t status;

    /* TODO: Use iconify ? */

    /* Flush all widget operations */
    PtFlush();
}

void
photon_setwindowposition(_THIS, SDL_Window * window)
{
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    PhPoint_t winpos;
    int32_t status;

    /* Check if upper level requests WM to position window */
    if ((window->x == SDL_WINDOWPOS_UNDEFINED)
        && (window->y == SDL_WINDOWPOS_UNDEFINED)) {
        /* Do not set widget position, let WM to set it */
    } else {
        if (window->x == SDL_WINDOWPOS_UNDEFINED) {
            window->x = 0;
        }
        if (window->y == SDL_WINDOWPOS_UNDEFINED) {
            window->y = 0;
        }
        if (window->x == SDL_WINDOWPOS_CENTERED) {
            window->x = (didata->current_mode.w - window->w) / 2;
        }
        if (window->y == SDL_WINDOWPOS_CENTERED) {
            window->y = (didata->current_mode.h - window->h) / 2;
        }

        /* Now set window position */
        winpos.x = window->x;
        winpos.y = window->y;
        status = PtSetResource(wdata->window, Pt_ARG_POS, &winpos, 0);
        if (status != 0) {
            SDL_SetError("Photon: Can't set window position");
        }
    }

    /* Flush all widget operations */
    PtFlush();
}

void
photon_setwindowsize(_THIS, SDL_Window * window)
{
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    PhDim_t winsize;
    int32_t status;

    winsize.w = window->w;
    winsize.h = window->h;

    status = PtSetResource(wdata->window, Pt_ARG_DIM, &winsize, 0);
    if (status != 0) {
        SDL_SetError("Photon: Can't set window size");
    }

    /* Flush all widget operations */
    PtFlush();
}

void
photon_showwindow(_THIS, SDL_Window * window)
{
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    int32_t status;

    /* Bring focus to window and put it in front of others */
    PtWindowToFront(wdata->window);

    /* Flush all widget operations */
    PtFlush();
}

void
photon_hidewindow(_THIS, SDL_Window * window)
{
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    PhWindowEvent_t winevent;
    int32_t status;

    SDL_memset(&winevent, 0x00, sizeof(PhWindowEvent_t));
    winevent.event_f = Ph_WM_HIDE;
    winevent.rid = PtWidgetRid(wdata->window);
    winevent.event_state = Ph_WM_EVSTATE_HIDE;

    status = PtForwardWindowEvent(&winevent);
    if (status != 0) {
        SDL_SetError("Photon: Can't hide window");
    }

    /* Flush all widget operations */
    PtFlush();
}

void
photon_raisewindow(_THIS, SDL_Window * window)
{
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    PhWindowEvent_t winevent;
    int32_t status;

    SDL_memset(&winevent, 0x00, sizeof(PhWindowEvent_t));
    winevent.event_f = Ph_WM_HIDE;
    winevent.rid = PtWidgetRid(wdata->window);
    winevent.event_state = Ph_WM_EVSTATE_UNHIDE;

    status = PtForwardWindowEvent(&winevent);
    if (status != 0) {
        SDL_SetError("Photon: Can't hide window");
    }

    /* Flush all widget operations */
    PtFlush();
}

void
photon_maximizewindow(_THIS, SDL_Window * window)
{
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    PhWindowEvent_t winevent;
    int32_t status;

    /* Flush all widget operations */
    PtFlush();
}

void
photon_minimizewindow(_THIS, SDL_Window * window)
{
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    PhWindowEvent_t winevent;
    int32_t status;

    SDL_memset(&winevent, 0x00, sizeof(PhWindowEvent_t));
    winevent.event_f = Ph_WM_HIDE;
    winevent.rid = PtWidgetRid(wdata->window);
    winevent.event_state = Ph_WM_EVSTATE_HIDE;

    status = PtForwardWindowEvent(&winevent);
    if (status != 0) {
        SDL_SetError("Photon: Can't hide window");
    }

    /* Flush all widget operations */
    PtFlush();
}

void
photon_restorewindow(_THIS, SDL_Window * window)
{
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    PhWindowEvent_t winevent;
    int32_t status;

    /* Flush all widget operations */
    PtFlush();
}

void
photon_setwindowgrab(_THIS, SDL_Window * window)
{
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    PhWindowEvent_t winevent;
    int32_t status;

    /* Flush all widget operations */
    PtFlush();
}

void
photon_destroywindow(_THIS, SDL_Window * window)
{
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    int32_t status;

    if (wdata != NULL) {
        status = PtDestroyWidget(wdata->window);
        if (status != 0) {
            SDL_SetError("Photon: Can't destroy window widget");
        }
        wdata->window = NULL;

#if defined(SDL_VIDEO_OPENGL_ES)
        if (phdata->gfinitialized == SDL_TRUE) {
            /* Destroy OpenGL ES surface if it was created */
            if (wdata->gles_surface != EGL_NO_SURFACE) {
                eglDestroySurface(phdata->egldisplay, wdata->gles_surface);
            }

            /* Free OpenGL ES target surface */
            if (wdata->gfsurface != NULL) {
                gf_surface_free(wdata->gfsurface);
            }

            phdata->egl_refcount--;
            if (phdata->egl_refcount == 0) {
                /* Terminate connection to OpenGL ES */
                if (phdata->egldisplay != EGL_NO_DISPLAY) {
                    eglTerminate(phdata->egldisplay);
                    phdata->egldisplay = EGL_NO_DISPLAY;
                }
            }
        }
#endif /* SDL_VIDEO_OPENGL_ES */
    }

    /* Flush all widget operations */
    PtFlush();
}

/*****************************************************************************/
/* SDL Window Manager function                                               */
/*****************************************************************************/
SDL_bool
photon_getwindowwminfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
{
    if (info->version.major <= SDL_MAJOR_VERSION) {
        return SDL_TRUE;
    } else {
        SDL_SetError("application not compiled with SDL %d.%d\n",
                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
        return SDL_FALSE;
    }

    /* Failed to get window manager information */
    return SDL_FALSE;
}

/*****************************************************************************/
/* SDL OpenGL/OpenGL ES functions                                            */
/*****************************************************************************/
int
photon_gl_loadlibrary(_THIS, const char *path)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;

    if (phdata->gfinitialized != SDL_TRUE) {
        SDL_SetError
            ("Photon: GF initialization failed, no OpenGL ES support");
        return NULL;
    }

    /* Check if OpenGL ES library is specified for GF driver */
    if (path == NULL) {
        path = SDL_getenv("SDL_OPENGL_LIBRARY");
        if (path == NULL) {
            path = SDL_getenv("SDL_OPENGLES_LIBRARY");
        }
    }

    /* Check if default library loading requested */
    if (path == NULL) {
        /* Already linked with GF library which provides egl* subset of  */
        /* functions, use Common profile of OpenGL ES library by default */
        path = "/usr/lib/libGLES_CM.so.1";
    }

    /* Load dynamic library */
    _this->gl_config.dll_handle = SDL_LoadObject(path);
    if (!_this->gl_config.dll_handle) {
        /* Failed to load new GL ES library */
        SDL_SetError("Photon: Failed to locate OpenGL ES library");
        return -1;
    }

    /* Store OpenGL ES library path and name */
    SDL_strlcpy(_this->gl_config.driver_path, path,
                SDL_arraysize(_this->gl_config.driver_path));

    /* New OpenGL ES library is loaded */
    return 0;
#else
    SDL_SetError("Photon: OpenGL ES support is not compiled in");
    return -1;
#endif /* SDL_VIDEO_OPENGL_ES */
}

void *
photon_gl_getprocaddres(_THIS, const char *proc)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    void *function_address;

    if (phdata->gfinitialized != SDL_TRUE) {
        SDL_SetError
            ("Photon: GF initialization failed, no OpenGL ES support");
        return NULL;
    }

    /* Try to get function address through the egl interface */
    function_address = eglGetProcAddress(proc);
    if (function_address != NULL) {
        return function_address;
    }

    /* Then try to get function in the OpenGL ES library */
    if (_this->gl_config.dll_handle) {
        function_address =
            SDL_LoadFunction(_this->gl_config.dll_handle, proc);
        if (function_address != NULL) {
            return function_address;
        }
    }

    /* Add emulated OpenGL ES 1.1 functions */
    if (SDL_strcmp(proc, "glTexParameteri") == 0) {
        return glTexParameteri;
    }
    if (SDL_strcmp(proc, "glTexParameteriv") == 0) {
        return glTexParameteriv;
    }
    if (SDL_strcmp(proc, "glColor4ub") == 0) {
        return glColor4ub;
    }

    /* Failed to get GL ES function address pointer */
    SDL_SetError("Photon: Cannot locate OpenGL ES function name");
    return NULL;
#else
    SDL_SetError("Photon: OpenGL ES support is not compiled in");
    return NULL;
#endif /* SDL_VIDEO_OPENGL_ES */
}

void
photon_gl_unloadlibrary(_THIS)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;

    if (phdata->gfinitialized == SDL_TRUE) {
        /* Unload OpenGL ES library */
        if (_this->gl_config.dll_handle) {
            SDL_UnloadObject(_this->gl_config.dll_handle);
            _this->gl_config.dll_handle = NULL;
        }
    } else {
        SDL_SetError
            ("Photon: GF initialization failed, no OpenGL ES support");
    }
#else
    SDL_SetError("Photon: OpenGL ES support is not compiled in");
    return;
#endif /* SDL_VIDEO_OPENGL_ES */
}

SDL_GLContext
photon_gl_createcontext(_THIS, SDL_Window * window)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    EGLBoolean status;
    int32_t gfstatus;
    EGLint configs;
    uint32_t attr_pos;
    EGLint attr_value;
    EGLint cit;

    /* Check if GF was initialized */
    if (phdata->gfinitialized != SDL_TRUE) {
        SDL_SetError
            ("Photon: GF initialization failed, no OpenGL ES support");
        return NULL;
    }

    /* Prepare attributes list to pass them to OpenGL ES */
    attr_pos = 0;
    wdata->gles_attributes[attr_pos++] = EGL_NATIVE_VISUAL_ID;
    wdata->gles_attributes[attr_pos++] =
        qnxgf_sdl_to_gf_pixelformat(didata->current_mode.format);
    wdata->gles_attributes[attr_pos++] = EGL_RED_SIZE;
    wdata->gles_attributes[attr_pos++] = _this->gl_config.red_size;
    wdata->gles_attributes[attr_pos++] = EGL_GREEN_SIZE;
    wdata->gles_attributes[attr_pos++] = _this->gl_config.green_size;
    wdata->gles_attributes[attr_pos++] = EGL_BLUE_SIZE;
    wdata->gles_attributes[attr_pos++] = _this->gl_config.blue_size;
    wdata->gles_attributes[attr_pos++] = EGL_ALPHA_SIZE;

    /* Setup alpha size in bits */
    if (_this->gl_config.alpha_size) {
        wdata->gles_attributes[attr_pos++] = _this->gl_config.alpha_size;
    } else {
        wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
    }

    /* Setup color buffer size */
    if (_this->gl_config.buffer_size) {
        wdata->gles_attributes[attr_pos++] = EGL_BUFFER_SIZE;
        wdata->gles_attributes[attr_pos++] = _this->gl_config.buffer_size;
    } else {
        wdata->gles_attributes[attr_pos++] = EGL_BUFFER_SIZE;
        wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
    }

    /* Setup depth buffer bits */
    wdata->gles_attributes[attr_pos++] = EGL_DEPTH_SIZE;
    wdata->gles_attributes[attr_pos++] = _this->gl_config.depth_size;

    /* Setup stencil bits */
    if (_this->gl_config.stencil_size) {
        wdata->gles_attributes[attr_pos++] = EGL_STENCIL_SIZE;
        wdata->gles_attributes[attr_pos++] = _this->gl_config.buffer_size;
    } else {
        wdata->gles_attributes[attr_pos++] = EGL_STENCIL_SIZE;
        wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
    }

    /* Set number of samples in multisampling */
    if (_this->gl_config.multisamplesamples) {
        wdata->gles_attributes[attr_pos++] = EGL_SAMPLES;
        wdata->gles_attributes[attr_pos++] =
            _this->gl_config.multisamplesamples;
    }

    /* Multisample buffers, OpenGL ES 1.0 spec defines 0 or 1 buffer */
    if (_this->gl_config.multisamplebuffers) {
        wdata->gles_attributes[attr_pos++] = EGL_SAMPLE_BUFFERS;
        wdata->gles_attributes[attr_pos++] =
            _this->gl_config.multisamplebuffers;
    }

    /* Finish attributes list */
    wdata->gles_attributes[attr_pos] = EGL_NONE;

    /* Request first suitable framebuffer configuration */
    status = eglChooseConfig(phdata->egldisplay, wdata->gles_attributes,
                             wdata->gles_configs, SDL_VIDEO_GF_OPENGLES_CONFS,
                             &configs);
    if (status != EGL_TRUE) {
        SDL_SetError
            ("Photon: Can't find closest configuration for OpenGL ES");
        return NULL;
    }

    /* Check if nothing has been found, try "don't care" settings */
    if (configs == 0) {
        int32_t it;
        int32_t jt;
        GLint depthbits[4] = { 32, 24, 16, EGL_DONT_CARE };

        for (it = 0; it < 4; it++) {
            for (jt = 16; jt >= 0; jt--) {
                /* Don't care about color buffer bits, use what exist */
                /* Replace previous set data with EGL_DONT_CARE       */
                attr_pos = 0;
                wdata->gles_attributes[attr_pos++] = EGL_NATIVE_VISUAL_ID;
                wdata->gles_attributes[attr_pos++] =
                    qnxgf_sdl_to_gf_pixelformat(didata->current_mode.format);
                wdata->gles_attributes[attr_pos++] = EGL_RED_SIZE;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos++] = EGL_GREEN_SIZE;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos++] = EGL_BLUE_SIZE;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos++] = EGL_ALPHA_SIZE;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos++] = EGL_BUFFER_SIZE;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;

                /* Try to find requested or smallest depth */
                if (_this->gl_config.depth_size) {
                    wdata->gles_attributes[attr_pos++] = EGL_DEPTH_SIZE;
                    wdata->gles_attributes[attr_pos++] = depthbits[it];
                } else {
                    wdata->gles_attributes[attr_pos++] = EGL_DEPTH_SIZE;
                    wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                }

                if (_this->gl_config.stencil_size) {
                    wdata->gles_attributes[attr_pos++] = EGL_STENCIL_SIZE;
                    wdata->gles_attributes[attr_pos++] = jt;
                } else {
                    wdata->gles_attributes[attr_pos++] = EGL_STENCIL_SIZE;
                    wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                }

                wdata->gles_attributes[attr_pos++] = EGL_SAMPLES;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos++] = EGL_SAMPLE_BUFFERS;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos] = EGL_NONE;

                /* Request first suitable framebuffer configuration */
                status =
                    eglChooseConfig(phdata->egldisplay,
                                    wdata->gles_attributes,
                                    wdata->gles_configs,
                                    SDL_VIDEO_GF_OPENGLES_CONFS, &configs);
                if (status != EGL_TRUE) {
                    SDL_SetError
                        ("Photon: Can't find closest configuration for OpenGL ES");
                    return NULL;
                }
                if (configs != 0) {
                    break;
                }
            }
            if (configs != 0) {
                break;
            }
        }

        /* No available configs */
        if (configs == 0) {
            SDL_SetError
                ("Photon: Can't find any configuration for OpenGL ES");
            return NULL;
        }
    }

    /* Initialize config index */
    wdata->gles_config = 0;

    /* Now check each configuration to find out the best */
    for (cit = 0; cit < configs; cit++) {
        uint32_t stencil_found;
        uint32_t depth_found;

        stencil_found = 0;
        depth_found = 0;

        if (_this->gl_config.stencil_size) {
            status =
                eglGetConfigAttrib(phdata->egldisplay,
                                   wdata->gles_configs[cit], EGL_STENCIL_SIZE,
                                   &attr_value);
            if (status == EGL_TRUE) {
                if (attr_value != 0) {
                    stencil_found = 1;
                }
            }
        } else {
            stencil_found = 1;
        }

        if (_this->gl_config.depth_size) {
            status =
                eglGetConfigAttrib(phdata->egldisplay,
                                   wdata->gles_configs[cit], EGL_DEPTH_SIZE,
                                   &attr_value);
            if (status == EGL_TRUE) {
                if (attr_value != 0) {
                    depth_found = 1;
                }
            }
        } else {
            depth_found = 1;
        }

        /* Exit from loop if found appropriate configuration */
        if ((depth_found != 0) && (stencil_found != 0)) {
            break;
        }
    }

    /* If best could not be found, use first */
    if (cit == configs) {
        cit = 0;
    }
    wdata->gles_config = cit;

    /* Create OpenGL ES context */
    wdata->gles_context =
        eglCreateContext(phdata->egldisplay,
                         wdata->gles_configs[wdata->gles_config],
                         EGL_NO_CONTEXT, NULL);
    if (wdata->gles_context == EGL_NO_CONTEXT) {
        SDL_SetError("Photon: OpenGL ES context creation has been failed");
        return NULL;
    }

    /* Check if surface is exist */
    if (wdata->gfsurface != NULL) {
        gf_surface_free(wdata->gfsurface);
        wdata->gfsurface = NULL;
    }

    /* Create GF surface */
    gfstatus =
        gf_surface_create(&wdata->gfsurface, phdata->gfdev, window->w,
                          window->h,
                          qnxgf_sdl_to_gf_pixelformat(didata->current_mode.
                                                      format), NULL,
                          GF_SURFACE_CREATE_2D_ACCESSIBLE |
                          GF_SURFACE_CREATE_3D_ACCESSIBLE |
                          GF_SURFACE_CREATE_SHAREABLE);
    if (gfstatus != GF_ERR_OK) {
        eglDestroyContext(phdata->egldisplay, wdata->gles_context);
        wdata->gles_context = EGL_NO_CONTEXT;
        SDL_SetError("Photon: Can't create GF 3D surface (%08X)", gfstatus);
        return NULL;
    }

    /* Create pixmap 3D target surface */
    wdata->gles_surface =
        eglCreatePixmapSurface(phdata->egldisplay,
                               wdata->gles_configs[wdata->gles_config],
                               wdata->gfsurface, NULL);
    if (wdata->gles_surface == EGL_NO_SURFACE) {
        gf_surface_free(wdata->gfsurface);
        eglDestroyContext(phdata->egldisplay, wdata->gles_context);
        wdata->gles_context = EGL_NO_CONTEXT;
        SDL_SetError("Photon: Can't create EGL pixmap surface");
        return NULL;
    }

    /* Make just created context current */
    status =
        eglMakeCurrent(phdata->egldisplay, wdata->gles_surface,
                       wdata->gles_surface, wdata->gles_context);
    if (status != EGL_TRUE) {
        /* Destroy OpenGL ES surface */
        eglDestroySurface(phdata->egldisplay, wdata->gles_surface);
        gf_surface_free(wdata->gfsurface);
        eglDestroyContext(phdata->egldisplay, wdata->gles_context);
        wdata->gles_context = EGL_NO_CONTEXT;
        SDL_SetError("Photon: Can't set OpenGL ES context on creation");
        return NULL;
    }

    /* Setup into SDL internals state of OpenGL ES:  */
    /* it is accelerated or not                      */
    if ((didata->caps & SDL_PHOTON_ACCELERATED_3D) ==
        SDL_PHOTON_ACCELERATED_3D) {
        _this->gl_config.accelerated = 1;
    } else {
        _this->gl_config.accelerated = 0;
    }

    /* Always clear stereo enable, since OpenGL ES do not supports stereo */
    _this->gl_config.stereo = 0;

    /* Get back samples and samplebuffers configurations. Rest framebuffer */
    /* parameters could be obtained through the OpenGL ES API              */
    status =
        eglGetConfigAttrib(phdata->egldisplay,
                           wdata->gles_configs[wdata->gles_config],
                           EGL_SAMPLES, &attr_value);
    if (status == EGL_TRUE) {
        _this->gl_config.multisamplesamples = attr_value;
    }
    status =
        eglGetConfigAttrib(phdata->egldisplay,
                           wdata->gles_configs[wdata->gles_config],
                           EGL_SAMPLE_BUFFERS, &attr_value);
    if (status == EGL_TRUE) {
        _this->gl_config.multisamplebuffers = attr_value;
    }

    /* Get back stencil and depth buffer sizes */
    status =
        eglGetConfigAttrib(phdata->egldisplay,
                           wdata->gles_configs[wdata->gles_config],
                           EGL_DEPTH_SIZE, &attr_value);
    if (status == EGL_TRUE) {
        _this->gl_config.depth_size = attr_value;
    }
    status =
        eglGetConfigAttrib(phdata->egldisplay,
                           wdata->gles_configs[wdata->gles_config],
                           EGL_STENCIL_SIZE, &attr_value);
    if (status == EGL_TRUE) {
        _this->gl_config.stencil_size = attr_value;
    }

    /* Under Photon OpenGL ES output can't be double buffered */
    _this->gl_config.double_buffer = 0;

    /* Check if current device is not the same as target */
    if (phdata->current_device_id != didata->device_id) {
        /* Set target device as default for Pd and Pg functions */
        status = PdSetTargetDevice(NULL, phdata->rid[didata->device_id]);
        if (status != 0) {
            /* Destroy OpenGL ES surface */
            eglDestroySurface(phdata->egldisplay, wdata->gles_surface);
            gf_surface_free(wdata->gfsurface);
            eglDestroyContext(phdata->egldisplay, wdata->gles_context);
            wdata->gles_context = EGL_NO_CONTEXT;
            SDL_SetError("Photon: Can't set default target device\n");
            return NULL;
        }
        phdata->current_device_id = didata->device_id;
    }

    wdata->phsurface = PdCreateOffscreenContextGF(wdata->gfsurface);
    if (wdata->phsurface == NULL) {
        /* Destroy OpenGL ES surface */
        eglDestroySurface(phdata->egldisplay, wdata->gles_surface);
        gf_surface_free(wdata->gfsurface);
        eglDestroyContext(phdata->egldisplay, wdata->gles_context);
        wdata->gles_context = EGL_NO_CONTEXT;
        SDL_SetError("Photon: Can't bind GF surface to Photon\n");
        return NULL;
    }

    /* GL ES context was successfully created */
    return wdata->gles_context;
#else
    SDL_SetError("Photon: OpenGL ES support is not compiled in");
    return NULL;
#endif /* SDL_VIDEO_OPENGL_ES */
}

int
photon_gl_makecurrent(_THIS, SDL_Window * window, SDL_GLContext context)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    SDL_WindowData *wdata;
    EGLBoolean status;

    if (phdata->gfinitialized != SDL_TRUE) {
        SDL_SetError
            ("Photon: GF initialization failed, no OpenGL ES support");
        return -1;
    }

    if ((window == NULL) && (context == NULL)) {
        status =
            eglMakeCurrent(phdata->egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
                           EGL_NO_CONTEXT);
        if (status != EGL_TRUE) {
            /* Failed to set current GL ES context */
            SDL_SetError("Photon: Can't set OpenGL ES context");
            return -1;
        }
    } else {
        wdata = (SDL_WindowData *) window->driverdata;
        if (wdata->gles_surface == EGL_NO_SURFACE) {
            SDL_SetError
                ("Photon: OpenGL ES surface is not initialized for this window");
            return -1;
        }
        if (wdata->gles_context == EGL_NO_CONTEXT) {
            SDL_SetError
                ("Photon: OpenGL ES context is not initialized for this window");
            return -1;
        }
        if (wdata->gles_context != context) {
            SDL_SetError
                ("Photon: OpenGL ES context is not belong to this window");
            return -1;
        }
        status =
            eglMakeCurrent(phdata->egldisplay, wdata->gles_surface,
                           wdata->gles_surface, wdata->gles_context);
        if (status != EGL_TRUE) {
            /* Failed to set current GL ES context */
            SDL_SetError("Photon: Can't set OpenGL ES context");
            return -1;
        }
    }

    return 0;
#else
    SDL_SetError("Photon: OpenGL ES support is not compiled in");
    return -1;
#endif /* SDL_VIDEO_OPENGL_ES */
}

int
photon_gl_setswapinterval(_THIS, int interval)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    EGLBoolean status;

    if (phdata->gfinitialized != SDL_TRUE) {
        SDL_SetError
            ("Photon: GF initialization failed, no OpenGL ES support");
        return -1;
    }

    /* Check if OpenGL ES connection has been initialized */
    if (phdata->egldisplay != EGL_NO_DISPLAY) {
        /* Set swap OpenGL ES interval */
        status = eglSwapInterval(phdata->egldisplay, interval);
        if (status == EGL_TRUE) {
            /* Return success to upper level */
            phdata->swapinterval = interval;
            return 0;
        }
    }

    /* Failed to set swap interval */
    SDL_SetError("Photon: Cannot set swap interval");
    return -1;
#else
    SDL_SetError("Photon: OpenGL ES support is not compiled in");
    return -1;
#endif /* SDL_VIDEO_OPENGL_ES */
}

int
photon_gl_getswapinterval(_THIS)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;

    if (phdata->gfinitialized != SDL_TRUE) {
        SDL_SetError
            ("Photon: GF initialization failed, no OpenGL ES support");
        return -1;
    }

    /* Return default swap interval value */
    return phdata->swapinterval;
#else
    SDL_SetError("Photon: OpenGL ES support is not compiled in");
    return -1;
#endif /* SDL_VIDEO_OPENGL_ES */
}

void
photon_gl_swapwindow(_THIS, SDL_Window * window)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    PhRect_t dst_rect;
    PhRect_t src_rect;

    if (phdata->gfinitialized != SDL_TRUE) {
        SDL_SetError
            ("Photon: GF initialization failed, no OpenGL ES support");
        return;
    }

    /* Many applications do not uses glFinish(), so we call it for them */
    glFinish();

    /* Wait until OpenGL ES rendering is completed */
    eglWaitGL();

    /* Wait for VSYNC manually, if it was enabled */
    if (phdata->swapinterval != 0) {
        /* Wait for VSYNC, we use GF function, since Photon requires */
        /* to enter to the Direct mode to call PgWaitVSync()         */
        gf_display_wait_vsync(didata->display);
    }

    /* Set blit area */
    dst_rect = *PtGetCanvas(wdata->window);
    src_rect.ul.x = 0;
    src_rect.ul.y = 0;
    src_rect.lr.x = window->w - 1;
    src_rect.lr.y = window->h - 1;

    /* Blit OpenGL ES pixmap surface directly to window region */
    PgFFlush(Ph_START_DRAW);
    PgSetRegionCx(PhDCGetCurrent(), PtWidgetRid(wdata->window));
    PgClearTranslationCx(PgGetGCCx(PhDCGetCurrent()));
    PgContextBlit(wdata->phsurface, &src_rect, NULL, &dst_rect);
    PgFFlush(Ph_DONE_DRAW);
    PgWaitHWIdle();

    eglSwapBuffers(phdata->egldisplay, wdata->gles_surface);
#else
    SDL_SetError("Photon: OpenGL ES support is not compiled in");
    return;
#endif /* SDL_VIDEO_OPENGL_ES */
}

void
photon_gl_deletecontext(_THIS, SDL_GLContext context)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
    EGLBoolean status;

    if (phdata->gfinitialized != SDL_TRUE) {
        SDL_SetError
            ("Photon: GF initialization failed, no OpenGL ES support");
        return;
    }

    /* Check if OpenGL ES connection has been initialized */
    if (phdata->egldisplay != EGL_NO_DISPLAY) {
        if (context != EGL_NO_CONTEXT) {
            status = eglDestroyContext(phdata->egldisplay, context);
            if (status != EGL_TRUE) {
                /* Error during OpenGL ES context destroying */
                SDL_SetError("Photon: OpenGL ES context destroy error");
                return;
            }
        }
    }

    return;
#else
    SDL_SetError("Photon: OpenGL ES support is not compiled in");
    return;
#endif /* SDL_VIDEO_OPENGL_ES */
}

/*****************************************************************************/
/* SDL Event handling function                                               */
/*****************************************************************************/
void
photon_pumpevents(_THIS)
{
    uint8_t eventbuffer[SDL_VIDEO_PHOTON_EVENT_SIZE];
    PhEvent_t *event = (PhEvent_t *) eventbuffer;
    int32_t status;
    uint32_t finish = 0;
    uint32_t it;
    SDL_Window *window;
    SDL_WindowData *wdata;

    do {
        status = PhEventPeek(event, SDL_VIDEO_PHOTON_EVENT_SIZE);
        switch (status) {
        case Ph_RESIZE_MSG:
            {
                SDL_SetError("Photon: Event size too much for buffer");
                return;
            }
            break;
        case Ph_EVENT_MSG:
            {
                /* Find a window, to which this handle destinated */
                status = 0;
                for (it = 0; it < SDL_CurrentDisplay.num_windows; it++) {
                    wdata =
                        (SDL_WindowData *) SDL_CurrentDisplay.windows[it].
                        driverdata;

                    /* Find the proper window */
                    if (wdata->window != NULL) {
                        if (PtWidgetRid(wdata->window) ==
                            event->collector.rid) {
                            window =
                                (SDL_Window *) & SDL_CurrentDisplay.
                                windows[it];
                            status = 1;
                            break;
                        }
                    } else {
                        continue;
                    }
                }
                if (status == 0) {
                    window = NULL;
                    wdata = NULL;
                }

                /* Event is ready */
                switch (event->type) {
                case Ph_EV_BOUNDARY:
                    {
                        switch (event->subtype) {
                        case Ph_EV_PTR_ENTER:
                            {
                                /* Mouse cursor over handled window */
                                if (window != NULL) {
                                    SDL_SendWindowEvent(window->id,
                                                        SDL_WINDOWEVENT_ENTER,
                                                        0, 0);
                                    SDL_SetMouseFocus(0, window->id);
                                }
                            }
                            break;
                        case Ph_EV_PTR_LEAVE:
                            {
                                /* Mouse cursor out of handled window */
                                if (window != NULL) {
                                    SDL_SendWindowEvent(window->id,
                                                        SDL_WINDOWEVENT_LEAVE,
                                                        0, 0);
                                }
                            }
                            break;
                        }
                    }
                    break;
                case Ph_EV_PTR_MOTION_BUTTON:
                case Ph_EV_PTR_MOTION_NOBUTTON:
                    {
                        PhPointerEvent_t *pevent = NULL;
                        PhRect_t *prects = NULL;

                        /* Get event data */
                        pevent = PhGetData(event);
                        /* Get associated event rectangles */
                        prects = PhGetRects(event);
                        if ((pevent != NULL) && (prects != NULL)) {
                            SDL_SendMouseMotion(0, 0, prects->ul.x,
                                                prects->ul.y, 0);
                        }
                    }
                    break;
                case Ph_EV_BUT_PRESS:
                    {
                        /* Button press event */
                        PhPointerEvent_t *pevent = NULL;
                        uint32_t sdlbutton = 0x00000000;

                        /* Get event data */
                        pevent = PhGetData(event);
                        if (pevent != NULL) {
                            for (it = 0; it < sizeof(pevent->buttons) * 8;
                                 it++) {
                                if ((pevent->buttons & (0x0001 << it)) ==
                                    (0x0001 << it)) {
                                    switch (it) {
                                    case 0:
                                        {
                                            sdlbutton = SDL_BUTTON_RIGHT;
                                        }
                                        break;
                                    case 1:
                                        {
                                            sdlbutton = SDL_BUTTON_MIDDLE;
                                        }
                                        break;
                                    case 2:
                                        {
                                            sdlbutton = SDL_BUTTON_LEFT;
                                        }
                                        break;
                                    default:
                                        {
                                            sdlbutton = it + 1;
                                        }
                                        break;
                                    }
                                    SDL_SendMouseButton(0, SDL_PRESSED,
                                                        sdlbutton);
                                }
                            }
                        }
                    }
                    break;
                case Ph_EV_BUT_RELEASE:
                    {
                        /* Button press event */
                        PhPointerEvent_t *pevent = NULL;
                        uint32_t sdlbutton = 0x00000000;

                        /* Get event data */
                        pevent = PhGetData(event);
                        if (pevent != NULL) {
                            for (it = 0; it < sizeof(pevent->buttons) * 8;
                                 it++) {
                                if ((pevent->buttons & (0x0001 << it)) ==
                                    (0x0001 << it)) {
                                    switch (it) {
                                    case 0:
                                        {
                                            sdlbutton = SDL_BUTTON_RIGHT;
                                        }
                                        break;
                                    case 1:
                                        {
                                            sdlbutton = SDL_BUTTON_MIDDLE;
                                        }
                                        break;
                                    case 2:
                                        {
                                            sdlbutton = SDL_BUTTON_LEFT;
                                        }
                                        break;
                                    default:
                                        {
                                            sdlbutton = it + 1;
                                        }
                                        break;
                                    }
                                }
                            }
                        }

                        switch (event->subtype) {
                        case Ph_EV_RELEASE_REAL:
                            {
                                /* Real release button event */
                                SDL_SendMouseButton(0, SDL_RELEASED,
                                                    sdlbutton);
                            }
                            break;
                        case Ph_EV_RELEASE_PHANTOM:
                            {
                                /* We will get phantom button release */
                                /* event in case if it was unpressed  */
                                /* outside of window                  */
                                if (window != NULL) {
                                    if ((window->
                                         flags & SDL_WINDOW_MOUSE_FOCUS) !=
                                        SDL_WINDOW_MOUSE_FOCUS) {
                                        /* Send phantom button release */
                                        SDL_SendMouseButton(0, SDL_RELEASED,
                                                            sdlbutton);
                                    }
                                }
                            }
                            break;
                        }
                    }
                    break;
                case Ph_EV_EXPOSE:
                    {
                        switch (event->subtype) {
                        case Ph_NORMAL_EXPOSE:
                            {
                                PhRect_t *rects = NULL;

                                /* Get array of rectangles to be updated */
                                rects = PhGetRects(event);
                                if (rects == NULL) {
                                    break;
                                }

                                /* Check if expose come to one of the our windows */
                                if ((wdata != NULL) && (window != NULL)) {
                                    /* Check if window uses OpenGL ES */
                                    if (wdata->uses_gles == SDL_TRUE) {
                                        PhRect_t dst_rect;
                                        PhRect_t src_rect;

                                        /* Cycle through each rectangle */
                                        for (it = 0; it < event->num_rects;
                                             it++) {
                                            /* Blit OpenGL ES pixmap surface directly to window region */
                                            PgFFlush(Ph_START_DRAW);
                                            PgSetRegionCx(PhDCGetCurrent(),
                                                          PtWidgetRid(wdata->
                                                                      window));
                                            PgClearTranslationCx(PgGetGCCx
                                                                 (PhDCGetCurrent
                                                                  ()));
                                            PgContextBlit(wdata->phsurface,
                                                          &rects[it], NULL,
                                                          &rects[it]);
                                            PgFFlush(Ph_DONE_DRAW);
                                            PgWaitHWIdle();
                                        }
                                    } else {
                                        /* Normal window */
                                        /* TODO: update the damaged rectangles */
                                    }
                                }

                                /* Flush all blittings */
                                PgFlush();
                            }
                            break;
                        case Ph_CAPTURE_EXPOSE:
                            {
                                /* Check if expose come to one of the our windows */
                                if ((wdata != NULL) && (window != NULL)) {
                                    /* Check if window uses OpenGL ES */
                                    if (wdata->uses_gles == SDL_TRUE) {
                                        PhRect_t dst_rect;
                                        PhRect_t src_rect;

                                        /* Set blit area */
                                        dst_rect =
                                            *PtGetCanvas(wdata->window);
                                        src_rect.ul.x = 0;
                                        src_rect.ul.y = 0;
                                        src_rect.lr.x = window->w - 1;
                                        src_rect.lr.y = window->h - 1;

                                        /* We need to redraw entire window */
                                        PgFFlush(Ph_START_DRAW);
                                        PgSetRegionCx(PhDCGetCurrent(),
                                                      PtWidgetRid(wdata->
                                                                  window));
                                        PgClearTranslationCx(PgGetGCCx
                                                             (PhDCGetCurrent
                                                              ()));
                                        PgContextBlit(wdata->phsurface,
                                                      &src_rect, NULL,
                                                      &dst_rect);
                                        PgFFlush(Ph_DONE_DRAW);
                                        PgWaitHWIdle();
                                    } else {
                                        /* Normal window */
                                        /* TODO: update the damaged rectangles */

                                        /* We need to redraw entire window */
                                    }
                                }
                            }
                            break;
                        case Ph_GRAPHIC_EXPOSE:
                            {
                                /* TODO: What this event means ? */
                            }
                            break;
                        }
                    }
                    break;
                case Ph_EV_INFO:
                    {
                    }
                    break;
                case Ph_EV_KEY:
                    {
                        PhKeyEvent_t *keyevent = NULL;
                        SDL_scancode scancode = SDL_SCANCODE_UNKNOWN;
                        SDL_bool pressed = SDL_FALSE;

                        keyevent = PhGetData(event);
                        if (keyevent == NULL) {
                            break;
                        }

                        /* Check if key is repeated */
                        if ((keyevent->key_flags & Pk_KF_Key_Repeat) ==
                            Pk_KF_Key_Repeat) {
                            /* Ignore such events */
                            break;
                        }

                        /* Check if key has its own scancode */
                        if ((keyevent->key_flags & Pk_KF_Scan_Valid) ==
                            Pk_KF_Scan_Valid) {
                            if ((keyevent->key_flags & Pk_KF_Key_Down) ==
                                Pk_KF_Key_Down) {
                                pressed = SDL_TRUE;
                            } else {
                                pressed = SDL_FALSE;
                            }
                            scancode =
                                photon_to_sdl_keymap(keyevent->key_scan);

                            /* Add details for the pressed key */
                            if ((keyevent->key_flags & Pk_KF_Cap_Valid) ==
                                Pk_KF_Cap_Valid) {
                                switch (keyevent->key_cap) {
                                case Pk_Hyper_R:       /* Right windows flag key */
                                    scancode = SDL_SCANCODE_RGUI;
                                    break;
                                case Pk_Control_R:     /* Right Ctrl key */
                                    scancode = SDL_SCANCODE_RCTRL;
                                    break;
                                case Pk_Alt_R: /* Right Alt key */
                                    scancode = SDL_SCANCODE_RALT;
                                    break;
                                case Pk_Up:    /* Up key but with invalid scan */
                                    if (scancode != SDL_SCANCODE_UP) {
                                        /* This is a mouse wheel event */
                                        SDL_SendMouseWheel(0, 0, 1);
                                        return;
                                    }
                                    break;
                                case Pk_KP_8:  /* Up arrow or 8 on keypad */
                                    scancode = SDL_SCANCODE_KP_8;
                                    break;
                                case Pk_Down:  /* Down key but with invalid scan */
                                    if (scancode != SDL_SCANCODE_DOWN) {
                                        /* This is a mouse wheel event */
                                        SDL_SendMouseWheel(0, 0, -1);
                                        return;
                                    }
                                    break;
                                case Pk_KP_2:  /* Down arrow or 2 on keypad */
                                    scancode = SDL_SCANCODE_KP_2;
                                    break;
                                case Pk_Left:  /* Left arrow key */
                                    scancode = SDL_SCANCODE_LEFT;
                                    break;
                                case Pk_KP_4:  /* Left arrow or 4 on keypad */
                                    scancode = SDL_SCANCODE_KP_4;
                                    break;
                                case Pk_Right: /* Right arrow key */
                                    scancode = SDL_SCANCODE_RIGHT;
                                    break;
                                case Pk_KP_6:  /* Right arrow or 6 on keypad */
                                    scancode = SDL_SCANCODE_KP_6;
                                    break;
                                case Pk_Insert:        /* Insert key */
                                    scancode = SDL_SCANCODE_INSERT;
                                    break;
                                case Pk_KP_0:  /* Insert or 0 on keypad */
                                    scancode = SDL_SCANCODE_KP_0;
                                    break;
                                case Pk_Home:  /* Home key */
                                    scancode = SDL_SCANCODE_HOME;
                                    break;
                                case Pk_KP_7:  /* Home or 7 on keypad */
                                    scancode = SDL_SCANCODE_KP_7;
                                    break;
                                case Pk_Pg_Up: /* PageUp key */
                                    scancode = SDL_SCANCODE_PAGEUP;
                                    break;
                                case Pk_KP_9:  /* PgUp or 9 on keypad */
                                    scancode = SDL_SCANCODE_KP_9;
                                    break;
                                case Pk_Delete:        /* Delete key */
                                    scancode = SDL_SCANCODE_DELETE;
                                    break;
                                case Pk_KP_Decimal:    /* Del or . on keypad */
                                    scancode = SDL_SCANCODE_KP_PERIOD;
                                    break;
                                case Pk_End:   /* End key */
                                    scancode = SDL_SCANCODE_END;
                                    break;
                                case Pk_KP_1:  /* End or 1 on keypad */
                                    scancode = SDL_SCANCODE_KP_1;
                                    break;
                                case Pk_Pg_Down:       /* PageDown key */
                                    scancode = SDL_SCANCODE_PAGEDOWN;
                                    break;
                                case Pk_KP_3:  /* PgDn or 3 on keypad */
                                    scancode = SDL_SCANCODE_KP_3;
                                    break;
                                case Pk_KP_5:  /* 5 on keypad */
                                    scancode = SDL_SCANCODE_KP_5;
                                    break;
                                case Pk_KP_Enter:
                                    scancode = SDL_SCANCODE_KP_ENTER;
                                    break;
                                case Pk_KP_Add:
                                    scancode = SDL_SCANCODE_KP_PLUS;
                                    break;
                                case Pk_KP_Subtract:
                                    scancode = SDL_SCANCODE_KP_MINUS;
                                    break;
                                case Pk_KP_Multiply:
                                    scancode = SDL_SCANCODE_KP_MULTIPLY;
                                    break;
                                case Pk_KP_Divide:
                                    scancode = SDL_SCANCODE_KP_DIVIDE;
                                    break;
                                case Pk_Pause:
                                    scancode = SDL_SCANCODE_PAUSE;
                                    break;
                                }
                            }

                            /* Finally check if scancode has been decoded */
                            if (scancode == SDL_SCANCODE_UNKNOWN) {
                                /* Something was pressed, which is not supported */
                                break;
                            }

                            /* Report pressed/released key to SDL */
                            if (pressed == SDL_TRUE) {
                                SDL_SendKeyboardKey(0, SDL_PRESSED, scancode);
                            } else {
                                SDL_SendKeyboardKey(0, SDL_RELEASED,
                                                    scancode);
                            }

                            /* Photon doesn't send a release event for PrnScr key */
                            if ((scancode == SDL_SCANCODE_PRINTSCREEN)
                                && (pressed)) {
                                SDL_SendKeyboardKey(0, SDL_RELEASED,
                                                    scancode);
                            }
                        }
                    }
                    break;
                case Ph_EV_SERVICE:
                    {
                    }
                    break;
                case Ph_EV_SYSTEM:
                    {
                    }
                    break;
                case Ph_EV_WM:
                    {
                        PhWindowEvent_t *wmevent = NULL;

                        /* Get associated event data */
                        wmevent = PhGetData(event);
                        if (wmevent == NULL) {
                            break;
                        }

                        switch (wmevent->event_f) {
                        case Ph_WM_CLOSE:
                            {
                                if (window != NULL) {
                                    SDL_SendWindowEvent(window->id,
                                                        SDL_WINDOWEVENT_CLOSE,
                                                        0, 0);
                                }
                            }
                            break;
                        case Ph_WM_FOCUS:
                            {
                                if (wmevent->event_state ==
                                    Ph_WM_EVSTATE_FOCUS) {
                                    if (window != NULL) {
                                        PhRegion_t wregion;

                                        SDL_SendWindowEvent(window->id,
                                                            SDL_WINDOWEVENT_FOCUS_GAINED,
                                                            0, 0);
                                        SDL_SetKeyboardFocus(0, window->id);

                                        /* Set window region sensible to mouse motion events */
                                        PhRegionQuery(PtWidgetRid
                                                      (wdata->window),
                                                      &wregion, NULL, NULL,
                                                      0);
                                        wregion.events_sense |=
                                            Ph_EV_PTR_MOTION_BUTTON |
                                            Ph_EV_PTR_MOTION_NOBUTTON;
                                        PhRegionChange(Ph_REGION_EV_SENSE, 0,
                                                       &wregion, NULL, NULL);

                                        /* If window got a focus, the it is visible */
                                        SDL_SendWindowEvent(window->id,
                                                            SDL_WINDOWEVENT_SHOWN,
                                                            0, 0);
                                    }
                                }
                                if (wmevent->event_state ==
                                    Ph_WM_EVSTATE_FOCUSLOST) {
                                    if (window != NULL) {
                                        PhRegion_t wregion;

                                        SDL_SendWindowEvent(window->id,
                                                            SDL_WINDOWEVENT_FOCUS_LOST,
                                                            0, 0);

                                        /* Set window region ignore mouse motion events */
                                        PhRegionQuery(PtWidgetRid
                                                      (wdata->window),
                                                      &wregion, NULL, NULL,
                                                      0);
                                        wregion.events_sense &=
                                            ~(Ph_EV_PTR_MOTION_BUTTON |
                                              Ph_EV_PTR_MOTION_NOBUTTON);
                                        PhRegionChange(Ph_REGION_EV_SENSE, 0,
                                                       &wregion, NULL, NULL);
                                    }
                                }
                            }
                            break;
                        case Ph_WM_MOVE:
                            {
                                if (window != NULL) {
                                    SDL_SendWindowEvent(window->id,
                                                        SDL_WINDOWEVENT_MOVED,
                                                        wmevent->pos.x,
                                                        wmevent->pos.y);
                                }
                            }
                            break;
                        case Ph_WM_RESIZE:
                            {
                                if (window != NULL) {
                                    /* Set new window position after resize */
                                    SDL_SendWindowEvent(window->id,
                                                        SDL_WINDOWEVENT_MOVED,
                                                        wmevent->pos.x,
                                                        wmevent->pos.y);
                                    /* Set new window size after resize */
                                    SDL_SendWindowEvent(window->id,
                                                        SDL_WINDOWEVENT_RESIZED,
                                                        wmevent->size.w,
                                                        wmevent->size.h);
                                }
                            }
                            break;
                        case Ph_WM_HIDE:
                            {
                                if (window != NULL) {
                                    /* Send new window state: minimized */
                                    SDL_SendWindowEvent(window->id,
                                                        SDL_WINDOWEVENT_MINIMIZED,
                                                        0, 0);
                                    /* In case window is minimized, then it is hidden */
                                    SDL_SendWindowEvent(window->id,
                                                        SDL_WINDOWEVENT_HIDDEN,
                                                        0, 0);
                                }
                            }
                            break;
                        case Ph_WM_MAX:
                            {
                                if (window != NULL) {
                                    SDL_SendWindowEvent(window->id,
                                                        SDL_WINDOWEVENT_MAXIMIZED,
                                                        0, 0);
                                }
                            }
                            break;
                        case Ph_WM_RESTORE:
                            {
                                if (window != NULL) {
                                    SDL_SendWindowEvent(window->id,
                                                        SDL_WINDOWEVENT_RESTORED,
                                                        0, 0);
                                }
                            }
                            break;
                        }
                    }
                    break;
                }
                PtEventHandler(event);
            }
            break;
        case 0:
            {
                /* All events are read */
                finish = 1;
                break;
            }
        case -1:
            {
                /* Error occured in event reading */
                SDL_SetError("Photon: Can't read event");
                return;
            }
            break;
        }
        if (finish != 0) {
            break;
        }
    } while (1);
}

/*****************************************************************************/
/* SDL screen saver related functions                                        */
/*****************************************************************************/
void
photon_suspendscreensaver(_THIS)
{
    /* There is no screensaver in pure console, it may exist when running */
    /* GF under Photon, but I do not know, how to disable screensaver     */
}

/* vi: set ts=4 sw=4 expandtab: */