/*
    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: */
