Home | History | Annotate | Download | only in qtopia
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 Sam Lantinga
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Lesser General Public
      7     License as published by the Free Software Foundation; either
      8     version 2.1 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Lesser General Public License for more details.
     14 
     15     You should have received a copy of the GNU Lesser General Public
     16     License along with this library; if not, write to the Free Software
     17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     18 
     19     Sam Lantinga
     20     slouken (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 /* Qtopia based framebuffer implementation */
     25 
     26 #include <unistd.h>
     27 
     28 #include <qapplication.h>
     29 #include <qpe/qpeapplication.h>
     30 
     31 #include "SDL_timer.h"
     32 
     33 #include "SDL_QWin.h"
     34 
     35 extern "C" {
     36 
     37 #include "../SDL_sysvideo.h"
     38 #include "../../events/SDL_events_c.h"
     39 #include "SDL_sysevents_c.h"
     40 #include "SDL_sysmouse_c.h"
     41 #include "SDL_syswm_c.h"
     42 #include "SDL_lowvideo.h"
     43 
     44   //#define QTOPIA_DEBUG
     45 #define QT_HIDDEN_SIZE	32	/* starting hidden window size */
     46 
     47   /* Name of the environment variable used to invert the screen rotation or not:
     48      Possible values:
     49      !=0 : Screen is 270 rotated
     50      0: Screen is 90 rotated*/
     51 #define SDL_QT_ROTATION_ENV_NAME "SDL_QT_INVERT_ROTATION"
     52 
     53   /* Initialization/Query functions */
     54   static int QT_VideoInit(_THIS, SDL_PixelFormat *vformat);
     55   static SDL_Rect **QT_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
     56   static SDL_Surface *QT_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
     57   static void QT_UpdateMouse(_THIS);
     58   static int QT_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
     59   static void QT_VideoQuit(_THIS);
     60 
     61   /* Hardware surface functions */
     62   static int QT_AllocHWSurface(_THIS, SDL_Surface *surface);
     63   static int QT_LockHWSurface(_THIS, SDL_Surface *surface);
     64   static void QT_UnlockHWSurface(_THIS, SDL_Surface *surface);
     65   static void QT_FreeHWSurface(_THIS, SDL_Surface *surface);
     66 
     67   static int QT_ToggleFullScreen(_THIS, int fullscreen);
     68 
     69   static int QT_IconifyWindow(_THIS);
     70   static SDL_GrabMode QT_GrabInput(_THIS, SDL_GrabMode mode);
     71 
     72   /* FB driver bootstrap functions */
     73 
     74   static int QT_Available(void)
     75   {
     76     return(1);
     77   }
     78 
     79   static void QT_DeleteDevice(SDL_VideoDevice *device)
     80   {
     81     SDL_free(device->hidden);
     82     SDL_free(device);
     83   }
     84 
     85   static SDL_VideoDevice *QT_CreateDevice(int devindex)
     86   {
     87     SDL_VideoDevice *device;
     88 
     89     /* Initialize all variables that we clean on shutdown */
     90     device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
     91     if ( device ) {
     92       SDL_memset(device, 0, (sizeof *device));
     93       device->hidden = (struct SDL_PrivateVideoData *)
     94 	SDL_malloc((sizeof *device->hidden));
     95     }
     96     if ( (device == NULL) || (device->hidden == NULL) ) {
     97       SDL_OutOfMemory();
     98       if ( device ) {
     99 	SDL_free(device);
    100       }
    101       return(0);
    102     }
    103     SDL_memset(device->hidden, 0, (sizeof *device->hidden));
    104 
    105     /* Set the function pointers */
    106     device->VideoInit = QT_VideoInit;
    107     device->ListModes = QT_ListModes;
    108     device->SetVideoMode = QT_SetVideoMode;
    109     device->UpdateMouse = QT_UpdateMouse;
    110     device->SetColors = QT_SetColors;
    111     device->UpdateRects = NULL;
    112     device->VideoQuit = QT_VideoQuit;
    113     device->AllocHWSurface = QT_AllocHWSurface;
    114     device->CheckHWBlit = NULL;
    115     device->FillHWRect = NULL;
    116     device->SetHWColorKey = NULL;
    117     device->SetHWAlpha = NULL;
    118     device->LockHWSurface = QT_LockHWSurface;
    119     device->UnlockHWSurface = QT_UnlockHWSurface;
    120     device->FlipHWSurface = NULL;
    121     device->FreeHWSurface = QT_FreeHWSurface;
    122     device->SetIcon = NULL;
    123     device->SetCaption = QT_SetWMCaption;
    124     device->IconifyWindow = QT_IconifyWindow;
    125     device->GrabInput = QT_GrabInput;
    126     device->GetWMInfo = NULL;
    127     device->FreeWMCursor = QT_FreeWMCursor;
    128     device->CreateWMCursor = QT_CreateWMCursor;
    129     device->ShowWMCursor = QT_ShowWMCursor;
    130     device->WarpWMCursor = QT_WarpWMCursor;
    131     device->InitOSKeymap = QT_InitOSKeymap;
    132     device->PumpEvents = QT_PumpEvents;
    133 
    134     device->free = QT_DeleteDevice;
    135     device->ToggleFullScreen = QT_ToggleFullScreen;
    136 
    137     /* Set the driver flags */
    138     device->handles_any_size = 0;
    139 
    140     return device;
    141   }
    142 
    143   VideoBootStrap Qtopia_bootstrap = {
    144     "qtopia", "Qtopia / QPE graphics",
    145     QT_Available, QT_CreateDevice
    146   };
    147 
    148   /* Function to sort the display_list */
    149   static int CompareModes(const void *A, const void *B)
    150   {
    151 #if 0
    152     const display_mode *a = (display_mode *)A;
    153     const display_mode *b = (display_mode *)B;
    154 
    155     if ( a->space == b->space ) {
    156       return((b->virtual_width*b->virtual_height)-
    157 	     (a->virtual_width*a->virtual_height));
    158     } else {
    159       return(ColorSpaceToBitsPerPixel(b->space)-
    160 	     ColorSpaceToBitsPerPixel(a->space));
    161     }
    162 #endif
    163     return 0;
    164   }
    165 
    166   /* Yes, this isn't the fastest it could be, but it works nicely */
    167   static int QT_AddMode(_THIS, int index, unsigned int w, unsigned int h)
    168   {
    169     SDL_Rect *mode;
    170     int i;
    171     int next_mode;
    172 
    173     /* Check to see if we already have this mode */
    174     if ( SDL_nummodes[index] > 0 ) {
    175       for ( i=SDL_nummodes[index]-1; i >= 0; --i ) {
    176 	mode = SDL_modelist[index][i];
    177 	if ( (mode->w == w) && (mode->h == h) ) {
    178 	  return(0);
    179 	}
    180       }
    181     }
    182 
    183     /* Set up the new video mode rectangle */
    184     mode = (SDL_Rect *)SDL_malloc(sizeof *mode);
    185     if ( mode == NULL ) {
    186       SDL_OutOfMemory();
    187       return(-1);
    188     }
    189     mode->x = 0;
    190     mode->y = 0;
    191     mode->w = w;
    192     mode->h = h;
    193 #ifdef QTOPIA_DEBUG
    194     fprintf(stderr, "Adding mode %dx%d at %d bytes per pixel\n", w, h, index+1);
    195 #endif
    196 
    197     /* Allocate the new list of modes, and fill in the new mode */
    198     next_mode = SDL_nummodes[index];
    199     SDL_modelist[index] = (SDL_Rect **)
    200       SDL_realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
    201     if ( SDL_modelist[index] == NULL ) {
    202       SDL_OutOfMemory();
    203       SDL_nummodes[index] = 0;
    204       SDL_free(mode);
    205       return(-1);
    206     }
    207     SDL_modelist[index][next_mode] = mode;
    208     SDL_modelist[index][next_mode+1] = NULL;
    209     SDL_nummodes[index]++;
    210 
    211     return(0);
    212   }
    213 
    214   int QT_VideoInit(_THIS, SDL_PixelFormat *vformat)
    215   {
    216     /* Initialize the QPE Application  */
    217      /* Determine the screen depth */
    218     vformat->BitsPerPixel = QPixmap::defaultDepth();
    219 
    220     // For now we hardcode the current depth because anything else
    221     // might as well be emulated by SDL rather than by Qtopia.
    222 
    223     QSize desktop_size = qApp->desktop()->size();
    224     QT_AddMode(_this, ((vformat->BitsPerPixel+7)/8)-1,
    225 	       desktop_size.width(), desktop_size.height());
    226     QT_AddMode(_this, ((vformat->BitsPerPixel+7)/8)-1,
    227 	       desktop_size.height(), desktop_size.width());
    228 
    229     /* Determine the current screen size */
    230     _this->info.current_w = desktop_size.width();
    231     _this->info.current_h = desktop_size.height();
    232 
    233     /* Create the window / widget */
    234     SDL_Win = new SDL_QWin(QSize(QT_HIDDEN_SIZE, QT_HIDDEN_SIZE));
    235     ((QPEApplication*)qApp)->showMainWidget(SDL_Win);
    236     /* Fill in some window manager capabilities */
    237     _this->info.wm_available = 0;
    238 
    239     /* We're done! */
    240     return(0);
    241   }
    242 
    243   /* We support any dimension at our bit-depth */
    244   SDL_Rect **QT_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
    245   {
    246     SDL_Rect **modes;
    247 
    248     modes = ((SDL_Rect **)0);
    249     if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
    250       modes = SDL_modelist[((format->BitsPerPixel+7)/8)-1];
    251     } else {
    252       if ( format->BitsPerPixel ==
    253 	   _this->screen->format->BitsPerPixel ) {
    254 	modes = ((SDL_Rect **)-1);
    255       }
    256     }
    257     return(modes);
    258   }
    259 
    260   /* Various screen update functions available */
    261   static void QT_NormalUpdate(_THIS, int numrects, SDL_Rect *rects);
    262 
    263 
    264   static int QT_SetFullScreen(_THIS, SDL_Surface *screen, int fullscreen)
    265   {
    266     return -1;
    267   }
    268 
    269   static int QT_ToggleFullScreen(_THIS, int fullscreen)
    270   {
    271     return -1;
    272   }
    273 
    274   /* FIXME: check return values and cleanup here */
    275   SDL_Surface *QT_SetVideoMode(_THIS, SDL_Surface *current,
    276 			       int width, int height, int bpp, Uint32 flags)
    277   {
    278 
    279     QImage *qimage;
    280     QSize desktop_size = qApp->desktop()->size();
    281 
    282 
    283     current->flags = 0; //SDL_FULLSCREEN; // We always run fullscreen.
    284 
    285     if(width <= desktop_size.width()
    286 	      && height <= desktop_size.height()) {
    287       current->w = desktop_size.width();
    288       current->h = desktop_size.height();
    289     } else if(width <= desktop_size.height() && height <= desktop_size.width()) {
    290       // Landscape mode
    291       char * envString = SDL_getenv(SDL_QT_ROTATION_ENV_NAME);
    292       int envValue = envString ? atoi(envString) : 0;
    293       screenRotation = envValue ? SDL_QT_ROTATION_270 : SDL_QT_ROTATION_90;
    294       current->h = desktop_size.width();
    295       current->w = desktop_size.height();
    296     } else {
    297       SDL_SetError("Unsupported resolution, %dx%d\n", width, height);
    298     }
    299     if ( flags & SDL_OPENGL ) {
    300       SDL_SetError("OpenGL not supported");
    301       return(NULL);
    302     }
    303     /* Create the QImage framebuffer */
    304     qimage = new QImage(current->w, current->h, bpp);
    305     if (qimage->isNull()) {
    306       SDL_SetError("Couldn't create screen bitmap");
    307       delete qimage;
    308       return(NULL);
    309     }
    310     current->pitch = qimage->bytesPerLine();
    311     current->pixels = (void *)qimage->bits();
    312     SDL_Win->setImage(qimage);
    313     _this->UpdateRects = QT_NormalUpdate;
    314     SDL_Win->setFullscreen(true);
    315     /* We're done */
    316     return(current);
    317   }
    318 
    319   /* Update the current mouse state and position */
    320   void QT_UpdateMouse(_THIS)
    321   {
    322     QPoint point(-1, -1);
    323     if ( SDL_Win->isActiveWindow() ) {
    324       point = SDL_Win->mousePos();
    325     }
    326 
    327     if ( (point.x() >= 0) && (point.x() < SDL_VideoSurface->w) &&
    328 	 (point.y() >= 0) && (point.y() < SDL_VideoSurface->h) ) {
    329       SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
    330       SDL_PrivateMouseMotion(0, 0,
    331 			     (Sint16)point.x(), (Sint16)point.y());
    332     } else {
    333       SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
    334     }
    335   }
    336 
    337   /* We don't actually allow hardware surfaces other than the main one */
    338   static int QT_AllocHWSurface(_THIS, SDL_Surface *surface)
    339   {
    340     return(-1);
    341   }
    342   static void QT_FreeHWSurface(_THIS, SDL_Surface *surface)
    343   {
    344     return;
    345   }
    346   static int QT_LockHWSurface(_THIS, SDL_Surface *surface)
    347   {
    348     return(0);
    349   }
    350   static void QT_UnlockHWSurface(_THIS, SDL_Surface *surface)
    351   {
    352     return;
    353   }
    354 
    355   static void QT_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
    356   {
    357     if(SDL_Win->lockScreen()) {
    358       for(int i=0; i<numrects; ++i ) {
    359 	QRect rect(rects[i].x, rects[i].y,
    360 		   rects[i].w, rects[i].h);
    361 	SDL_Win->repaintRect(rect);
    362       }
    363       SDL_Win->unlockScreen();
    364     }
    365   }
    366   /* Is the system palette settable? */
    367   int QT_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
    368   {
    369     return -1;
    370   }
    371 
    372   void QT_VideoQuit(_THIS)
    373   {
    374     // This is dumb, but if I free this, the app doesn't exit correctly.
    375     // Of course, this will leak memory if init video is done more than once.
    376     // Sucks but such is life.
    377 
    378     //    -- David Hedbor
    379     //    delete SDL_Win;
    380     //    SDL_Win = 0;
    381     _this->screen->pixels = NULL;
    382     QT_GrabInput(_this, SDL_GRAB_OFF);
    383   }
    384 
    385   static int QT_IconifyWindow(_THIS) {
    386     SDL_Win->hide();
    387 
    388     return true;
    389   }
    390 
    391   static SDL_GrabMode QT_GrabInput(_THIS, SDL_GrabMode mode) {
    392     if(mode == SDL_GRAB_OFF) {
    393       QPEApplication::grabKeyboard();
    394       qApp->processEvents();
    395       QPEApplication::ungrabKeyboard();
    396     } else {
    397       QPEApplication::grabKeyboard();
    398     }
    399     qApp->processEvents();
    400     return mode;
    401   }
    402 
    403 }; /* Extern C */
    404