view src/video/qtopia/SDL_QWin.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 376665398b25
children 11775724e3fe
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"

#include "SDL_QWin.h"
#include <qapplication.h>
#include <qdirectpainter_qws.h>

screenRotationT screenRotation = SDL_QT_NO_ROTATION;

SDL_QWin::SDL_QWin (const QSize & size):
QWidget (0, "SDL_main"),
my_painter (0),
my_image (0),
my_inhibit_resize (false),
my_mouse_pos (-1, -1),
my_flags (0),
my_has_fullscreen (false),
my_locked (0)
{
    setBackgroundMode (NoBackground);
}

SDL_QWin::~SDL_QWin ()
{
    // Nothing to do yet.
    if (my_image) {
        delete my_image;
    }
}

void
SDL_QWin::setImage (QImage * image)
{
    if (my_image) {
        delete my_image;
    }
    my_image = image;
    //  setFixedSize(image->size());
}

void
SDL_QWin::resizeEvent (QResizeEvent * e)
{
    if (size () != qApp->desktop ()->size ()) {
        // Widget is not the correct size, so do the fullscreen magic
        my_has_fullscreen = false;
        enableFullscreen ();
    }
    if (my_inhibit_resize) {
        my_inhibit_resize = false;
    } else {
        SDL_PrivateResize (e->size ().width (), e->size ().height ());
    }
}

void
SDL_QWin::focusInEvent (QFocusEvent *)
{
    // Always do it here, no matter the size.
    enableFullscreen ();
    SDL_PrivateAppActive (true, SDL_APPINPUTFOCUS);
}

void
SDL_QWin::focusOutEvent (QFocusEvent *)
{
    my_has_fullscreen = false;
    SDL_PrivateAppActive (false, SDL_APPINPUTFOCUS);
}

void
SDL_QWin::closeEvent (QCloseEvent * e)
{
    SDL_PrivateQuit ();
    e->ignore ();
}

void
SDL_QWin::setMousePos (const QPoint & pos)
{
    if (my_image->width () == height ()) {
        if (screenRotation == SDL_QT_ROTATION_90)
            my_mouse_pos = QPoint (height () - pos.y (), pos.x ());
        else if (screenRotation == SDL_QT_ROTATION_270)
            my_mouse_pos = QPoint (pos.y (), width () - pos.x ());
    } else {
        my_mouse_pos = pos;
    }
}

void
SDL_QWin::mouseMoveEvent (QMouseEvent * e)
{
    Qt::ButtonState button = e->button ();
    int sdlstate = 0;
    if ((button & Qt::LeftButton)) {
        sdlstate |= SDL_BUTTON_LMASK;
    }
    if ((button & Qt::RightButton)) {
        sdlstate |= SDL_BUTTON_RMASK;
    }
    if ((button & Qt::MidButton)) {
        sdlstate |= SDL_BUTTON_MMASK;
    }
    setMousePos (e->pos ());
    SDL_PrivateMouseMotion (sdlstate, 0, my_mouse_pos.x (),
                            my_mouse_pos.y ());
}

void
SDL_QWin::mousePressEvent (QMouseEvent * e)
{
    mouseMoveEvent (e);
    Qt::ButtonState button = e->button ();
    SDL_PrivateMouseButton (SDL_PRESSED,
                            (button & Qt::LeftButton) ? 1 :
                            ((button & Qt::RightButton) ? 2 : 3),
                            my_mouse_pos.x (), my_mouse_pos.y ());
}

void
SDL_QWin::mouseReleaseEvent (QMouseEvent * e)
{
    setMousePos (e->pos ());
    Qt::ButtonState button = e->button ();
    SDL_PrivateMouseButton (SDL_RELEASED,
                            (button & Qt::LeftButton) ? 1 :
                            ((button & Qt::RightButton) ? 2 : 3),
                            my_mouse_pos.x (), my_mouse_pos.y ());
    my_mouse_pos = QPoint (-1, -1);
}

static inline void
gs_fastRotateBlit_3 (unsigned short *fb,
                     unsigned short *bits, const QRect & rect)
{
    // FIXME: this only works correctly for 240x320 displays
    int startx, starty;
    int width, height;

    startx = rect.left () >> 1;
    starty = rect.top () >> 1;
    width = ((rect.right () - rect.left ()) >> 1) + 2;
    height = ((rect.bottom () - rect.top ()) >> 1) + 2;

    if ((startx + width) > 120) {
        width = 120 - startx;   // avoid horizontal overflow
    }
    if ((starty + height) > 160) {
        height = 160 - starty;  // avoid vertical overflow
    }

    ulong *sp1, *sp2, *dp1, *dp2;
    ulong stop, sbot, dtop, dbot;

    sp1 = (ulong *) bits + startx + starty * 240;
    sp2 = sp1 + 120;
    dp1 = (ulong *) fb + (159 - starty) + startx * 320;
    dp2 = dp1 + 160;
    int rowadd = (-320 * width) - 1;
    int rowadd2 = 240 - width;
    // transfer in cells of 2x2 pixels in words
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            // read source pixels
            stop = *sp1;
            sbot = *sp2;
            // rotate pixels
            dtop = (sbot & 0xffff) + ((stop & 0xffff) << 16);
            dbot = ((sbot & 0xffff0000) >> 16) + (stop & 0xffff0000);
            // write to framebuffer
            *dp1 = dtop;
            *dp2 = dbot;
            // update source ptrs
            sp1++;
            sp2++;
            // update dest ptrs - 2 pix at a time
            dp1 += 320;
            dp2 += 320;
        }
        // adjust src ptrs - skip a row as we work in pairs
        sp1 += rowadd2;
        sp2 += rowadd2;
        // adjust dest ptrs for rotation
        dp1 += rowadd;
        dp2 += rowadd;
    }
}

static inline void
gs_fastRotateBlit_1 (unsigned short *fb,
                     unsigned short *bits, const QRect & rect)
{
    // FIXME: this only works correctly for 240x320 displays
    int startx, starty;
    int width, height;

    startx = rect.left () >> 1;
    starty = rect.top () >> 1;
    width = ((rect.right () - rect.left ()) >> 1) + 2;
    height = ((rect.bottom () - rect.top ()) >> 1) + 2;

    if ((startx + width) > 120) {
        width = 120 - startx;   // avoid horizontal overflow
    }
    if ((starty + height) > 160) {
        height = 160 - starty;  // avoid vertical overflow
    }

    ulong *sp1, *sp2, *dp1, *dp2;
    ulong stop, sbot, dtop, dbot;
    fb += 320 * 239;            // Move "fb" to top left corner
    sp1 = (ulong *) bits + startx + starty * 240;
    sp2 = sp1 + 120;
    dp1 = (ulong *) fb - startx * 320 - starty;
    dp2 = dp1 - 160;
    int rowadd = (320 * width) + 1;
    int rowadd2 = 240 - width;
    // transfer in cells of 2x2 pixels in words
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            // read
            stop = *sp1;
            sbot = *sp2;
            // rotate
            dtop = (stop & 0xffff) + ((sbot & 0xffff) << 16);
            dbot = ((stop & 0xffff0000) >> 16) + (sbot & 0xffff0000);
            // write
            *dp1 = dtop;
            *dp2 = dbot;
            // update source ptrs
            sp1++;
            sp2++;
            // update dest ptrs - 2 pix at a time
            dp1 -= 320;
            dp2 -= 320;
        }
        // adjust src ptrs - skip a row as we work in pairs
        sp1 += rowadd2;
        sp2 += rowadd2;
        // adjust dest ptrs for rotation
        dp1 += rowadd;
        dp2 += rowadd;
    }
}

// desktop, SL-A300 etc
bool SDL_QWin::repaintRotation0 (const QRect & rect)
{
    if (my_image->width () == width ()) {
        uchar *
            fb = (uchar *) my_painter->frameBuffer ();
        uchar *
            buf = (uchar *) my_image->bits ();
        if (rect == my_image->rect ()) {
            SDL_memcpy (fb, buf, width () * height () * 2);
        } else {
            int
                h = rect.height ();
            int
                wd = rect.width () << 1;
            int
                fblineadd = my_painter->lineStep ();
            int
                buflineadd = my_image->bytesPerLine ();
            fb += (rect.left () << 1) + rect.top () * my_painter->lineStep ();
            buf +=
                (rect.left () << 1) + rect.top () * my_image->bytesPerLine ();
            while (h--) {
                SDL_memcpy (fb, buf, wd);
                fb += fblineadd;
                buf += buflineadd;
            }
        }
    } else {
        return false;           // FIXME: Landscape
    }
#ifdef __i386__
    my_painter->fillRect (rect, QBrush (Qt::NoBrush));
#endif
    return true;
}


// Sharp Zaurus SL-5500 etc 
bool SDL_QWin::repaintRotation3 (const QRect & rect)
{
    if (my_image->width () == width ()) {
        ushort *
            fb = (ushort *) my_painter->frameBuffer ();
        ushort *
            buf = (ushort *) my_image->bits ();
        gs_fastRotateBlit_3 (fb, buf, rect);
    } else {
        // landscape mode
        if (screenRotation == SDL_QT_ROTATION_90) {
            uchar *
                fb = (uchar *) my_painter->frameBuffer ();
            uchar *
                buf = (uchar *) my_image->bits ();
            if (rect == my_image->rect ()) {
                SDL_memcpy (fb, buf, width () * height () * 2);
            } else {
                int
                    h = rect.height ();
                int
                    wd = rect.width () << 1;
                int
                    fblineadd = my_painter->lineStep ();
                int
                    buflineadd = my_image->bytesPerLine ();
                fb +=
                    (rect.left () << 1) +
                    rect.top () * my_painter->lineStep ();
                buf +=
                    (rect.left () << 1) +
                    rect.top () * my_image->bytesPerLine ();
                while (h--) {
                    SDL_memcpy (fb, buf, wd);
                    fb += fblineadd;
                    buf += buflineadd;
                }
            }
        } else if (screenRotation == SDL_QT_ROTATION_270) {
            int
                h = rect.height ();
            int
                wd = rect.width ();
            int
                fblineadd = my_painter->lineStep () - (rect.width () << 1);
            int
                buflineadd = my_image->bytesPerLine () - (rect.width () << 1);
            int
                w;

            uchar *
                fb = (uchar *) my_painter->frameBuffer ();
            uchar *
                buf = (uchar *) my_image->bits ();

            fb +=
                ((my_painter->width () -
                  (rect.top () +
                   rect.height ())) * my_painter->lineStep ()) +
                ((my_painter->height () -
                  ((rect.left () + rect.width ()))) << 1);

            buf +=
                my_image->bytesPerLine () * (rect.top () +
                                             rect.height ()) -
                (((my_image->width () -
                   (rect.left () + rect.width ())) << 1) + 2);

            while (h--) {
                w = wd;
                while (w--)
                    *((unsigned short *) fb)++ = *((unsigned short *) buf)--;
                fb += fblineadd;
                buf -= buflineadd;
            }
        }
    }
    return true;
}

// ipaq 3800...
bool SDL_QWin::repaintRotation1 (const QRect & rect)
{
    if (my_image->width () == width ()) {
        ushort *
            fb = (ushort *) my_painter->frameBuffer ();
        ushort *
            buf = (ushort *) my_image->bits ();
        gs_fastRotateBlit_1 (fb, buf, rect);
    } else {
        return false;           // FIXME: landscape mode
    }
    return true;
}

void
SDL_QWin::repaintRect (const QRect & rect)
{
    if (!my_painter || !rect.width () || !rect.height ()) {
        return;
    }

    if (QPixmap::defaultDepth () == 16) {
        switch (my_painter->transformOrientation ()) {
        case 3:
            if (repaintRotation3 (rect)) {
                return;
            }
            break;
        case 1:
            if (repaintRotation1 (rect)) {
                return;
            }
            break;
        case 0:
            if (repaintRotation0 (rect)) {
                return;
            }
            break;
        }
    }
    my_painter->drawImage (rect.topLeft (), *my_image, rect);
}

// This paints the current buffer to the screen, when desired. 
void
SDL_QWin::paintEvent (QPaintEvent * ev)
{
    if (my_image) {
        lockScreen (true);
        repaintRect (ev->rect ());
        unlockScreen ();
    }
}

/* Function to translate a keyboard transition and queue the key event
 * This should probably be a table although this method isn't exactly
 * slow.
 */
void
SDL_QWin::QueueKey (QKeyEvent * e, int pressed)
{
    SDL_keysym keysym;
    int scancode = e->key ();
    /* Set the keysym information */
    if (scancode >= 'A' && scancode <= 'Z') {
        // Qt sends uppercase, SDL wants lowercase
        keysym.sym = static_cast < SDLKey > (scancode + 32);
    } else if (scancode >= 0x1000) {
        // Special keys
        switch (scancode) {
        case Qt::Key_Escape:
            scancode = SDLK_ESCAPE;
            break;
        case Qt::Key_Tab:
            scancode = SDLK_TAB;
            break;
        case Qt::Key_Backspace:
            scancode = SDLK_BACKSPACE;
            break;
        case Qt::Key_Return:
            scancode = SDLK_RETURN;
            break;
        case Qt::Key_Enter:
            scancode = SDLK_KP_ENTER;
            break;
        case Qt::Key_Insert:
            scancode = SDLK_INSERT;
            break;
        case Qt::Key_Delete:
            scancode = SDLK_DELETE;
            break;
        case Qt::Key_Pause:
            scancode = SDLK_PAUSE;
            break;
        case Qt::Key_Print:
            scancode = SDLK_PRINT;
            break;
        case Qt::Key_SysReq:
            scancode = SDLK_SYSREQ;
            break;
        case Qt::Key_Home:
            scancode = SDLK_HOME;
            break;
        case Qt::Key_End:
            scancode = SDLK_END;
            break;
            // We want the control keys to rotate with the screen
        case Qt::Key_Left:
            if (screenRotation == SDL_QT_ROTATION_90)
                scancode = SDLK_UP;
            else if (screenRotation == SDL_QT_ROTATION_270)
                scancode = SDLK_DOWN;
            else
                scancode = SDLK_LEFT;
            break;
        case Qt::Key_Up:
            if (screenRotation == SDL_QT_ROTATION_90)
                scancode = SDLK_RIGHT;
            else if (screenRotation == SDL_QT_ROTATION_270)
                scancode = SDLK_LEFT;
            else
                scancode = SDLK_UP;
            break;
        case Qt::Key_Right:
            if (screenRotation == SDL_QT_ROTATION_90)
                scancode = SDLK_DOWN;
            else if (screenRotation == SDL_QT_ROTATION_270)
                scancode = SDLK_UP;
            else
                scancode = SDLK_RIGHT;
            break;
        case Qt::Key_Down:
            if (screenRotation == SDL_QT_ROTATION_90)
                scancode = SDLK_LEFT;
            else if (screenRotation == SDL_QT_ROTATION_270)
                scancode = SDLK_RIGHT;
            else
                scancode = SDLK_DOWN;
            break;
        case Qt::Key_Prior:
            scancode = SDLK_PAGEUP;
            break;
        case Qt::Key_Next:
            scancode = SDLK_PAGEDOWN;
            break;
        case Qt::Key_Shift:
            scancode = SDLK_LSHIFT;
            break;
        case Qt::Key_Control:
            scancode = SDLK_LCTRL;
            break;
        case Qt::Key_Meta:
            scancode = SDLK_LMETA;
            break;
        case Qt::Key_Alt:
            scancode = SDLK_LALT;
            break;
        case Qt::Key_CapsLock:
            scancode = SDLK_CAPSLOCK;
            break;
        case Qt::Key_NumLock:
            scancode = SDLK_NUMLOCK;
            break;
        case Qt::Key_ScrollLock:
            scancode = SDLK_SCROLLOCK;
            break;
        case Qt::Key_F1:
            scancode = SDLK_F1;
            break;
        case Qt::Key_F2:
            scancode = SDLK_F2;
            break;
        case Qt::Key_F3:
            scancode = SDLK_F3;
            break;
        case Qt::Key_F4:
            scancode = SDLK_F4;
            break;
        case Qt::Key_F5:
            scancode = SDLK_F5;
            break;
        case Qt::Key_F6:
            scancode = SDLK_F6;
            break;
        case Qt::Key_F7:
            scancode = SDLK_F7;
            break;
        case Qt::Key_F8:
            scancode = SDLK_F8;
            break;
        case Qt::Key_F9:
            scancode = SDLK_F9;
            break;
        case Qt::Key_F10:
            scancode = SDLK_F10;
            break;
        case Qt::Key_F11:
            scancode = SDLK_F11;
            break;
        case Qt::Key_F12:
            scancode = SDLK_F12;
            break;
        case Qt::Key_F13:
            scancode = SDLK_F13;
            break;
        case Qt::Key_F14:
            scancode = SDLK_F14;
            break;
        case Qt::Key_F15:
            scancode = SDLK_F15;
            break;
        case Qt::Key_Super_L:
            scancode = SDLK_LSUPER;
            break;
        case Qt::Key_Super_R:
            scancode = SDLK_RSUPER;
            break;
        case Qt::Key_Menu:
            scancode = SDLK_MENU;
            break;
        case Qt::Key_Help:
            scancode = SDLK_HELP;
            break;

        case Qt::Key_F33:
            // FIXME: This is a hack to enable the OK key on
            // Zaurii devices. SDLK_RETURN is a suitable key to use
            // since it often is used as such.
            //     david@hedbor.org
            scancode = SDLK_RETURN;
            break;
        default:
            scancode = SDLK_UNKNOWN;
            break;
        }
        keysym.sym = static_cast < SDLKey > (scancode);
    } else {
        keysym.sym = static_cast < SDLKey > (scancode);
    }
    keysym.scancode = scancode;
    keysym.mod = KMOD_NONE;
    ButtonState st = e->state ();
    if ((st & ShiftButton)) {
        keysym.mod = static_cast < SDLMod > (keysym.mod | KMOD_LSHIFT);
    }
    if ((st & ControlButton)) {
        keysym.mod = static_cast < SDLMod > (keysym.mod | KMOD_LCTRL);
    }
    if ((st & AltButton)) {
        keysym.mod = static_cast < SDLMod > (keysym.mod | KMOD_LALT);
    }
    if (SDL_TranslateUNICODE) {
        QChar qchar = e->text ()[0];
        keysym.unicode = qchar.unicode ();
    } else {
        keysym.unicode = 0;
    }

    /* NUMLOCK and CAPSLOCK are implemented as double-presses in reality */
    //    if ( (keysym.sym == SDLK_NUMLOCK) || (keysym.sym == SDLK_CAPSLOCK) ) {
    //            pressed = 1;
    //    }

    /* Queue the key event */
    if (pressed) {
        SDL_PrivateKeyboard (SDL_PRESSED, &keysym);
    } else {
        SDL_PrivateKeyboard (SDL_RELEASED, &keysym);
    }
}

void
SDL_QWin::setFullscreen (bool fs_on)
{
    my_has_fullscreen = false;
    enableFullscreen ();
}

void
SDL_QWin::enableFullscreen ()
{
    // Make sure size is correct
    if (!my_has_fullscreen) {
        setFixedSize (qApp->desktop ()->size ());
        // This call is needed because showFullScreen won't work
        // correctly if the widget already considers itself to be fullscreen.
        showNormal ();
        // This is needed because showNormal() forcefully changes the window
        // style to WSTyle_TopLevel.
        setWFlags (WStyle_Customize | WStyle_NoBorder);
        // Enable fullscreen.
        showFullScreen ();
        my_has_fullscreen = true;
    }
}

bool SDL_QWin::lockScreen (bool force)
{
    if (!my_painter) {
        if (force || (isVisible () && isActiveWindow ())) {
            my_painter = new QDirectPainter (this);
        } else {
            return false;
        }
    }
    my_locked++;                // Increate lock refcount
    return true;
}

void
SDL_QWin::unlockScreen ()
{
    if (my_locked > 0) {
        my_locked--;            // decrease lock refcount;
    }
    if (!my_locked && my_painter) {
        my_painter->end ();
        delete my_painter;
        my_painter = 0;
    }
}

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