view src/video/qtopia/SDL_sysvideo.cc @ 1662:782fd950bd46 SDL-1.3

Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API. WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid. The code is now run through a consistent indent format: indent -i4 -nut -nsc -br -ce The headers are being converted to automatically generate doxygen documentation.
author Sam Lantinga <slouken@libsdl.org>
date Sun, 28 May 2006 13:04:16 +0000
parents e49147870aac
children 4da1ee79c9af
line wrap: on
line source

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

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

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

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

    Sam Lantinga
    slouken@libsdl.org
*/
#include "SDL_config.h"

/* Qtopia based framebuffer implementation */

#include <unistd.h>

#include <qapplication.h>
#include <qpe/qpeapplication.h>

#include "SDL_timer.h"

#include "SDL_QWin.h"

extern "C"
{

#include "../SDL_sysvideo.h"
#include "../../events/SDL_events_c.h"
#include "SDL_sysevents_c.h"
#include "SDL_sysmouse_c.h"
#include "SDL_syswm_c.h"
#include "SDL_lowvideo.h"

    //#define QTOPIA_DEBUG
#define QT_HIDDEN_SIZE	32      /* starting hidden window size */

    /* Name of the environment variable used to invert the screen rotation or not:
       Possible values:
       !=0 : Screen is 270° rotated
       0: Screen is 90° rotated */
#define SDL_QT_ROTATION_ENV_NAME "SDL_QT_INVERT_ROTATION"

    /* Initialization/Query functions */
    static int QT_VideoInit (_THIS, SDL_PixelFormat * vformat);
    static SDL_Rect **QT_ListModes (_THIS, SDL_PixelFormat * format,
                                    Uint32 flags);
    static SDL_Surface *QT_SetVideoMode (_THIS, SDL_Surface * current,
                                         int width, int height, int bpp,
                                         Uint32 flags);
    static void QT_UpdateMouse (_THIS);
    static int QT_SetColors (_THIS, int firstcolor, int ncolors,
                             SDL_Color * colors);
    static void QT_VideoQuit (_THIS);

    /* Hardware surface functions */
    static int QT_AllocHWSurface (_THIS, SDL_Surface * surface);
    static int QT_LockHWSurface (_THIS, SDL_Surface * surface);
    static void QT_UnlockHWSurface (_THIS, SDL_Surface * surface);
    static void QT_FreeHWSurface (_THIS, SDL_Surface * surface);

    static int QT_ToggleFullScreen (_THIS, int fullscreen);

    static int QT_IconifyWindow (_THIS);
    static SDL_GrabMode QT_GrabInput (_THIS, SDL_GrabMode mode);

    /* FB driver bootstrap functions */

    static int QT_Available (void)
    {
        return (1);
    }

    static void QT_DeleteDevice (SDL_VideoDevice * device)
    {
        SDL_free (device->hidden);
        SDL_free (device);
    }

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

        /* Initialize all variables that we clean on shutdown */
        device = (SDL_VideoDevice *) SDL_malloc (sizeof (SDL_VideoDevice));
        if (device) {
            SDL_memset (device, 0, (sizeof *device));
            device->hidden = (struct SDL_PrivateVideoData *)
                SDL_malloc ((sizeof *device->hidden));
        }
        if ((device == NULL) || (device->hidden == NULL)) {
            SDL_OutOfMemory ();
            if (device) {
                SDL_free (device);
            }
            return (0);
        }
        SDL_memset (device->hidden, 0, (sizeof *device->hidden));

        /* Set the function pointers */
        device->VideoInit = QT_VideoInit;
        device->ListModes = QT_ListModes;
        device->SetVideoMode = QT_SetVideoMode;
        device->UpdateMouse = QT_UpdateMouse;
        device->SetColors = QT_SetColors;
        device->UpdateRects = NULL;
        device->VideoQuit = QT_VideoQuit;
        device->AllocHWSurface = QT_AllocHWSurface;
        device->CheckHWBlit = NULL;
        device->FillHWRect = NULL;
        device->SetHWColorKey = NULL;
        device->SetHWAlpha = NULL;
        device->LockHWSurface = QT_LockHWSurface;
        device->UnlockHWSurface = QT_UnlockHWSurface;
        device->FlipHWSurface = NULL;
        device->FreeHWSurface = QT_FreeHWSurface;
        device->SetIcon = NULL;
        device->SetCaption = QT_SetWMCaption;
        device->IconifyWindow = QT_IconifyWindow;
        device->GrabInput = QT_GrabInput;
        device->GetWMInfo = NULL;
        device->FreeWMCursor = QT_FreeWMCursor;
        device->CreateWMCursor = QT_CreateWMCursor;
        device->ShowWMCursor = QT_ShowWMCursor;
        device->WarpWMCursor = QT_WarpWMCursor;
        device->InitOSKeymap = QT_InitOSKeymap;
        device->PumpEvents = QT_PumpEvents;

        device->free = QT_DeleteDevice;
        device->ToggleFullScreen = QT_ToggleFullScreen;

        /* Set the driver flags */
        device->handles_any_size = 0;

        return device;
    }

    VideoBootStrap Qtopia_bootstrap = {
        "qtopia", "Qtopia / QPE graphics",
        QT_Available, QT_CreateDevice
    };

    /* Function to sort the display_list */
    static int CompareModes (const void *A, const void *B)
    {
#if 0
        const display_mode *a = (display_mode *) A;
        const display_mode *b = (display_mode *) B;

        if (a->space == b->space) {
            return ((b->virtual_width * b->virtual_height) -
                    (a->virtual_width * a->virtual_height));
        } else {
            return (ColorSpaceToBitsPerPixel (b->space) -
                    ColorSpaceToBitsPerPixel (a->space));
        }
#endif
        return 0;
    }

    /* Yes, this isn't the fastest it could be, but it works nicely */
    static int QT_AddMode (_THIS, int index, unsigned int w, unsigned int h)
    {
        SDL_Rect *mode;
        int i;
        int next_mode;

        /* Check to see if we already have this mode */
        if (SDL_nummodes[index] > 0) {
            for (i = SDL_nummodes[index] - 1; i >= 0; --i) {
                mode = SDL_modelist[index][i];
                if ((mode->w == w) && (mode->h == h)) {
                    return (0);
                }
            }
        }

        /* Set up the new video mode rectangle */
        mode = (SDL_Rect *) SDL_malloc (sizeof *mode);
        if (mode == NULL) {
            SDL_OutOfMemory ();
            return (-1);
        }
        mode->x = 0;
        mode->y = 0;
        mode->w = w;
        mode->h = h;
#ifdef QTOPIA_DEBUG
        fprintf (stderr, "Adding mode %dx%d at %d bytes per pixel\n", w, h,
                 index + 1);
#endif

        /* Allocate the new list of modes, and fill in the new mode */
        next_mode = SDL_nummodes[index];
        SDL_modelist[index] = (SDL_Rect **)
            SDL_realloc (SDL_modelist[index],
                         (1 + next_mode + 1) * sizeof (SDL_Rect *));
        if (SDL_modelist[index] == NULL) {
            SDL_OutOfMemory ();
            SDL_nummodes[index] = 0;
            SDL_free (mode);
            return (-1);
        }
        SDL_modelist[index][next_mode] = mode;
        SDL_modelist[index][next_mode + 1] = NULL;
        SDL_nummodes[index]++;

        return (0);
    }

    int QT_VideoInit (_THIS, SDL_PixelFormat * vformat)
    {
        /* Initialize the QPE Application  */
        /* Determine the screen depth */
        vformat->BitsPerPixel = QPixmap::defaultDepth ();

        // For now we hardcode the current depth because anything else
        // might as well be emulated by SDL rather than by Qtopia.

        QSize desktop_size = qApp->desktop ()->size ();
        QT_AddMode (_this, ((vformat->BitsPerPixel + 7) / 8) - 1,
                    desktop_size.width (), desktop_size.height ());
        QT_AddMode (_this, ((vformat->BitsPerPixel + 7) / 8) - 1,
                    desktop_size.height (), desktop_size.width ());

        /* Determine the current screen size */
        this->info.current_w = desktop_size.width ();
        this->info.current_h = desktop_size.height ();

        /* Create the window / widget */
        SDL_Win = new SDL_QWin (QSize (QT_HIDDEN_SIZE, QT_HIDDEN_SIZE));
        ((QPEApplication *) qApp)->showMainWidget (SDL_Win);
        /* Fill in some window manager capabilities */
        _this->info.wm_available = 0;

        /* We're done! */
        return (0);
    }

    /* We support any dimension at our bit-depth */
    SDL_Rect **QT_ListModes (_THIS, SDL_PixelFormat * format, Uint32 flags)
    {
        SDL_Rect **modes;

        modes = ((SDL_Rect **) 0);
        if ((flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
            modes = SDL_modelist[((format->BitsPerPixel + 7) / 8) - 1];
        } else {
            if (format->BitsPerPixel == _this->screen->format->BitsPerPixel) {
                modes = ((SDL_Rect **) - 1);
            }
        }
        return (modes);
    }

    /* Various screen update functions available */
    static void QT_NormalUpdate (_THIS, int numrects, SDL_Rect * rects);


    static int QT_SetFullScreen (_THIS, SDL_Surface * screen, int fullscreen)
    {
        return -1;
    }

    static int QT_ToggleFullScreen (_THIS, int fullscreen)
    {
        return -1;
    }

    /* FIXME: check return values and cleanup here */
    SDL_Surface *QT_SetVideoMode (_THIS, SDL_Surface * current,
                                  int width, int height, int bpp,
                                  Uint32 flags)
    {

        QImage *qimage;
        QSize desktop_size = qApp->desktop ()->size ();


        current->flags = 0;     //SDL_FULLSCREEN; // We always run fullscreen.

        if (width <= desktop_size.width ()
            && height <= desktop_size.height ()) {
            current->w = desktop_size.width ();
            current->h = desktop_size.height ();
        } else if (width <= desktop_size.height ()
                   && height <= desktop_size.width ()) {
            // Landscape mode
            char *envString = SDL_getenv (SDL_QT_ROTATION_ENV_NAME);
            int envValue = envString ? atoi (envString) : 0;
            screenRotation =
                envValue ? SDL_QT_ROTATION_270 : SDL_QT_ROTATION_90;
            current->h = desktop_size.width ();
            current->w = desktop_size.height ();
        } else {
            SDL_SetError ("Unsupported resolution, %dx%d\n", width, height);
        }
        if (flags & SDL_INTERNALOPENGL) {
            SDL_SetError ("OpenGL not supported");
            return (NULL);
        }
        /* Create the QImage framebuffer */
        qimage = new QImage (current->w, current->h, bpp);
        if (qimage->isNull ()) {
            SDL_SetError ("Couldn't create screen bitmap");
            delete qimage;
            return (NULL);
        }
        current->pitch = qimage->bytesPerLine ();
        current->pixels = (void *) qimage->bits ();
        SDL_Win->setImage (qimage);
        _this->UpdateRects = QT_NormalUpdate;
        SDL_Win->setFullscreen (true);
        /* We're done */
        return (current);
    }

    /* Update the current mouse state and position */
    void QT_UpdateMouse (_THIS)
    {
        QPoint point (-1, -1);
        if (SDL_Win->isActiveWindow ()) {
            point = SDL_Win->mousePos ();
        }

        if ((point.x () >= 0) && (point.x () < SDL_VideoSurface->w) &&
            (point.y () >= 0) && (point.y () < SDL_VideoSurface->h)) {
            SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS);
            SDL_PrivateMouseMotion (0, 0,
                                    (Sint16) point.x (), (Sint16) point.y ());
        } else {
            SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS);
        }
    }

    /* We don't actually allow hardware surfaces other than the main one */
    static int QT_AllocHWSurface (_THIS, SDL_Surface * surface)
    {
        return (-1);
    }
    static void QT_FreeHWSurface (_THIS, SDL_Surface * surface)
    {
        return;
    }
    static int QT_LockHWSurface (_THIS, SDL_Surface * surface)
    {
        return (0);
    }
    static void QT_UnlockHWSurface (_THIS, SDL_Surface * surface)
    {
        return;
    }

    static void QT_NormalUpdate (_THIS, int numrects, SDL_Rect * rects)
    {
        if (SDL_Win->lockScreen ()) {
            for (int i = 0; i < numrects; ++i) {
                QRect rect (rects[i].x, rects[i].y, rects[i].w, rects[i].h);
                SDL_Win->repaintRect (rect);
            }
            SDL_Win->unlockScreen ();
        }
    }
    /* Is the system palette settable? */
    int QT_SetColors (_THIS, int firstcolor, int ncolors, SDL_Color * colors)
    {
        return -1;
    }

    void QT_VideoQuit (_THIS)
    {
        // This is dumb, but if I free this, the app doesn't exit correctly.
        // Of course, this will leak memory if init video is done more than once.
        // Sucks but such is life.

        //    -- David Hedbor
        //    delete SDL_Win; 
        //    SDL_Win = 0;
        _this->screen->pixels = NULL;
        QT_GrabInput (_this, SDL_GRAB_OFF);
    }

    static int QT_IconifyWindow (_THIS)
    {
        SDL_Win->hide ();

        return true;
    }

    static SDL_GrabMode QT_GrabInput (_THIS, SDL_GrabMode mode)
    {
        if (mode == SDL_GRAB_OFF) {
            QPEApplication::grabKeyboard ();
            qApp->processEvents ();
            QPEApplication::ungrabKeyboard ();
        } else {
            QPEApplication::grabKeyboard ();
        }
        qApp->processEvents ();
        return mode;
    }

};                              /* Extern C */

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