SDL-1.2.14
[sdl_omap.git] / src / video / qtopia / SDL_sysvideo.cc
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 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@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 */