Home | History | Annotate | Download | only in qtopia
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2006 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 #include "SDL_QWin.h"
     25 #include <qapplication.h>
     26 #include <qdirectpainter_qws.h>
     27 
     28 screenRotationT screenRotation = SDL_QT_NO_ROTATION;
     29 
     30 SDL_QWin::SDL_QWin(const QSize& size)
     31   : QWidget(0, "SDL_main"), my_painter(0), my_image(0),
     32     my_inhibit_resize(false), my_mouse_pos(-1,-1), my_flags(0),
     33     my_has_fullscreen(false), my_locked(0)
     34 {
     35   setBackgroundMode(NoBackground);
     36 }
     37 
     38 SDL_QWin::~SDL_QWin() {
     39   // Nothing to do yet.
     40   if(my_image) {
     41     delete my_image;
     42   }
     43 }
     44 
     45 void SDL_QWin::setImage(QImage *image) {
     46   if ( my_image ) {
     47     delete my_image;
     48   }
     49   my_image = image;
     50   //  setFixedSize(image->size());
     51 }
     52 
     53 void SDL_QWin::resizeEvent(QResizeEvent *e) {
     54   if(size() != qApp->desktop()->size()) {
     55     // Widget is not the correct size, so do the fullscreen magic
     56     my_has_fullscreen = false;
     57     enableFullscreen();
     58   }
     59   if(my_inhibit_resize) {
     60     my_inhibit_resize = false;
     61   } else {
     62     SDL_PrivateResize(e->size().width(), e->size().height());
     63   }
     64 }
     65 
     66 void SDL_QWin::focusInEvent(QFocusEvent *) {
     67   // Always do it here, no matter the size.
     68   enableFullscreen();
     69   SDL_PrivateAppActive(true, SDL_APPINPUTFOCUS);
     70 }
     71 
     72 void SDL_QWin::focusOutEvent(QFocusEvent *) {
     73   my_has_fullscreen = false;
     74   SDL_PrivateAppActive(false, SDL_APPINPUTFOCUS);
     75 }
     76 
     77 void SDL_QWin::closeEvent(QCloseEvent *e) {
     78   SDL_PrivateQuit();
     79   e->ignore();
     80 }
     81 
     82 void SDL_QWin::setMousePos(const QPoint &pos) {
     83   if(my_image->width() == height()) {
     84     if (screenRotation == SDL_QT_ROTATION_90)
     85       my_mouse_pos = QPoint(height()-pos.y(), pos.x());
     86     else if (screenRotation == SDL_QT_ROTATION_270)
     87       my_mouse_pos = QPoint(pos.y(), width()-pos.x());
     88   } else {
     89     my_mouse_pos = pos;
     90   }
     91 }
     92 
     93 void SDL_QWin::mouseMoveEvent(QMouseEvent *e) {
     94   Qt::ButtonState button = e->button();
     95   int sdlstate = 0;
     96   if( (button & Qt::LeftButton)) {
     97     sdlstate |= SDL_BUTTON_LMASK;
     98   }
     99   if( (button & Qt::RightButton)) {
    100     sdlstate |= SDL_BUTTON_RMASK;
    101   }
    102   if( (button & Qt::MidButton)) {
    103     sdlstate |= SDL_BUTTON_MMASK;
    104   }
    105   setMousePos(e->pos());
    106   SDL_PrivateMouseMotion(sdlstate, 0, my_mouse_pos.x(), my_mouse_pos.y());
    107 }
    108 
    109 void SDL_QWin::mousePressEvent(QMouseEvent *e) {
    110   mouseMoveEvent(e);
    111   Qt::ButtonState button = e->button();
    112   SDL_PrivateMouseButton(SDL_PRESSED,
    113 			 (button & Qt::LeftButton) ? 1 :
    114 			 ((button & Qt::RightButton) ? 2 : 3),
    115 			 my_mouse_pos.x(), my_mouse_pos.y());
    116 }
    117 
    118 void SDL_QWin::mouseReleaseEvent(QMouseEvent *e) {
    119   setMousePos(e->pos());
    120   Qt::ButtonState button = e->button();
    121   SDL_PrivateMouseButton(SDL_RELEASED,
    122 			 (button & Qt::LeftButton) ? 1 :
    123 			 ((button & Qt::RightButton) ? 2 : 3),
    124 			 my_mouse_pos.x(), my_mouse_pos.y());
    125   my_mouse_pos = QPoint(-1, -1);
    126 }
    127 
    128 static inline void
    129 gs_fastRotateBlit_3 ( unsigned short *fb,
    130 		      unsigned short *bits,
    131 		      const QRect& rect )
    132 {
    133   // FIXME: this only works correctly for 240x320 displays
    134   int startx, starty;
    135   int width, height;
    136 
    137   startx = rect.left() >> 1;
    138   starty = rect.top() >> 1;
    139   width  = ((rect.right() - rect.left()) >> 1) + 2;
    140   height = ((rect.bottom() - rect.top()) >> 1) + 2;
    141 
    142   if((startx+width) > 120) {
    143     width = 120 - startx; // avoid horizontal overflow
    144   }
    145   if((starty+height) > 160) {
    146     height = 160 - starty; // avoid vertical overflow
    147   }
    148 
    149   ulong *sp1, *sp2, *dp1, *dp2;
    150   ulong stop, sbot, dtop, dbot;
    151 
    152   sp1 = (ulong*)bits + startx + starty*240;
    153   sp2 = sp1 + 120;
    154   dp1 = (ulong *)fb + (159 - starty) + startx*320;
    155   dp2 = dp1 + 160;
    156   int rowadd = (-320*width) - 1;
    157   int rowadd2 = 240 - width;
    158   // transfer in cells of 2x2 pixels in words
    159   for (int y=0; y<height; y++) {
    160     for (int x=0; x<width; x++) {
    161       // read source pixels
    162       stop = *sp1;
    163       sbot = *sp2;
    164       // rotate pixels
    165       dtop = (sbot & 0xffff) + ((stop & 0xffff)<<16);
    166       dbot = ((sbot & 0xffff0000)>>16) + (stop & 0xffff0000);
    167       // write to framebuffer
    168       *dp1 = dtop;
    169       *dp2 = dbot;
    170       // update source ptrs
    171       sp1++; sp2++;
    172       // update dest ptrs - 2 pix at a time
    173       dp1 += 320;
    174       dp2 += 320;
    175     }
    176     // adjust src ptrs - skip a row as we work in pairs
    177     sp1 += rowadd2;
    178     sp2 += rowadd2;
    179     // adjust dest ptrs for rotation
    180     dp1 += rowadd;
    181     dp2 += rowadd;
    182   }
    183 }
    184 
    185 static inline void
    186 gs_fastRotateBlit_1 ( unsigned short *fb,
    187 		      unsigned short *bits,
    188 		      const QRect& rect ) {
    189   // FIXME: this only works correctly for 240x320 displays
    190   int startx, starty;
    191   int width, height;
    192 
    193   startx = rect.left() >> 1;
    194   starty = rect.top() >> 1;
    195   width  = ((rect.right() - rect.left()) >> 1) + 2;
    196   height = ((rect.bottom() - rect.top()) >> 1) + 2;
    197 
    198   if((startx+width) > 120) {
    199     width = 120 - startx; // avoid horizontal overflow
    200   }
    201   if((starty+height) > 160) {
    202     height = 160 - starty; // avoid vertical overflow
    203   }
    204 
    205   ulong *sp1, *sp2, *dp1, *dp2;
    206   ulong stop, sbot, dtop, dbot;
    207   fb += 320*239; // Move "fb" to top left corner
    208   sp1 = (ulong*)bits + startx + starty*240;
    209   sp2 = sp1 + 120;
    210   dp1 = (ulong*)fb - startx * 320 - starty;
    211   dp2 = dp1 - 160;
    212   int rowadd = (320*width) + 1;
    213   int rowadd2 = 240 - width;
    214   // transfer in cells of 2x2 pixels in words
    215   for (int y=0; y<height; y++) {
    216     for (int x=0; x<width; x++) {
    217       // read
    218       stop = *sp1;
    219       sbot = *sp2;
    220       // rotate
    221       dtop = (stop & 0xffff) + ((sbot & 0xffff)<<16);
    222       dbot = ((stop & 0xffff0000)>>16) + (sbot & 0xffff0000);
    223       // write
    224       *dp1 = dtop;
    225       *dp2 = dbot;
    226       // update source ptrs
    227       sp1++; sp2++;
    228       // update dest ptrs - 2 pix at a time
    229       dp1 -= 320;
    230       dp2 -= 320;
    231     }
    232     // adjust src ptrs - skip a row as we work in pairs
    233     sp1 += rowadd2;
    234     sp2 += rowadd2;
    235     // adjust dest ptrs for rotation
    236     dp1 += rowadd;
    237     dp2 += rowadd;
    238   }
    239 }
    240 
    241 // desktop, SL-A300 etc
    242 bool SDL_QWin::repaintRotation0(const QRect& rect) {
    243   if(my_image->width() == width()) {
    244     uchar *fb = (uchar*)my_painter->frameBuffer();
    245     uchar *buf = (uchar*)my_image->bits();
    246     if(rect == my_image->rect()) {
    247       SDL_memcpy(fb, buf, width()*height()*2);
    248     } else {
    249       int h = rect.height();
    250       int wd = rect.width()<<1;
    251       int fblineadd = my_painter->lineStep();
    252       int buflineadd = my_image->bytesPerLine();
    253       fb  += (rect.left()<<1) + rect.top() * my_painter->lineStep();
    254       buf += (rect.left()<<1) + rect.top() * my_image->bytesPerLine();
    255       while(h--) {
    256 	SDL_memcpy(fb, buf, wd);
    257 	fb += fblineadd;
    258 	buf += buflineadd;
    259       }
    260     }
    261   } else {
    262     return false; // FIXME: Landscape
    263   }
    264 #ifdef __i386__
    265   my_painter->fillRect( rect, QBrush( Qt::NoBrush ) );
    266 #endif
    267   return true;
    268 }
    269 
    270 
    271 // Sharp Zaurus SL-5500 etc
    272 bool SDL_QWin::repaintRotation3(const QRect& rect) {
    273   if(my_image->width() == width()) {
    274     ushort *fb = (ushort*)my_painter->frameBuffer();
    275     ushort *buf = (ushort*)my_image->bits();
    276     gs_fastRotateBlit_3(fb, buf, rect);
    277   } else {
    278     // landscape mode
    279     if (screenRotation == SDL_QT_ROTATION_90) {
    280       uchar *fb = (uchar*)my_painter->frameBuffer();
    281       uchar *buf = (uchar*)my_image->bits();
    282       if(rect == my_image->rect()) {
    283 	SDL_memcpy(fb, buf, width()*height()*2);
    284       } else {
    285 	int h = rect.height();
    286 	int wd = rect.width()<<1;
    287 	int fblineadd = my_painter->lineStep();
    288 	int buflineadd = my_image->bytesPerLine();
    289 	fb  += (rect.left()<<1) + rect.top() * my_painter->lineStep();
    290 	buf += (rect.left()<<1) + rect.top() * my_image->bytesPerLine();
    291 	while(h--) {
    292 	  SDL_memcpy(fb, buf, wd);
    293 	  fb += fblineadd;
    294 	  buf += buflineadd;
    295 	}
    296       }
    297     } else if (screenRotation == SDL_QT_ROTATION_270) {
    298       int h = rect.height();
    299       int wd = rect.width();
    300       int fblineadd = my_painter->lineStep() - (rect.width() << 1);
    301       int buflineadd = my_image->bytesPerLine() - (rect.width() << 1);
    302       int w;
    303 
    304       uchar *fb = (uchar*)my_painter->frameBuffer();
    305       uchar *buf = (uchar*)my_image->bits();
    306 
    307       fb += ((my_painter->width() - (rect.top() + rect.height())) *
    308 	     my_painter->lineStep()) + ((my_painter->height() - ((rect.left() +
    309 								  rect.width()))) << 1);
    310 
    311       buf += my_image->bytesPerLine() * (rect.top() + rect.height()) -
    312 	(((my_image->width() - (rect.left() + rect.width())) << 1) + 2);
    313 
    314       while(h--) {
    315 	w = wd;
    316 	while(w--) *((unsigned short*)fb)++ = *((unsigned short*)buf)--;
    317 	fb += fblineadd;
    318 	buf -= buflineadd;
    319       }
    320     }
    321   }
    322   return true;
    323 }
    324 
    325 // ipaq 3800...
    326 bool SDL_QWin::repaintRotation1(const QRect& rect) {
    327   if(my_image->width() == width()) {
    328     ushort *fb = (ushort*)my_painter->frameBuffer();
    329     ushort *buf = (ushort*)my_image->bits();
    330     gs_fastRotateBlit_1(fb, buf, rect);
    331   } else {
    332     return false; // FIXME: landscape mode
    333   }
    334   return true;
    335 }
    336 
    337 void SDL_QWin::repaintRect(const QRect& rect) {
    338   if(!my_painter || !rect.width() || !rect.height()) {
    339     return;
    340   }
    341 
    342   if(QPixmap::defaultDepth() == 16) {
    343     switch(my_painter->transformOrientation()) {
    344     case 3:
    345       if(repaintRotation3(rect)) { return;  }
    346       break;
    347     case 1:
    348       if(repaintRotation1(rect)) { return;  }
    349       break;
    350     case 0:
    351       if(repaintRotation0(rect)) { return;  }
    352       break;
    353     }
    354   }
    355   my_painter->drawImage(rect.topLeft(), *my_image, rect);
    356 }
    357 
    358 // This paints the current buffer to the screen, when desired.
    359 void SDL_QWin::paintEvent(QPaintEvent *ev) {
    360   if(my_image) {
    361     lockScreen(true);
    362     repaintRect(ev->rect());
    363     unlockScreen();
    364   }
    365 }
    366 
    367 /* Function to translate a keyboard transition and queue the key event
    368  * This should probably be a table although this method isn't exactly
    369  * slow.
    370  */
    371 void SDL_QWin::QueueKey(QKeyEvent *e, int pressed)
    372 {
    373   SDL_keysym keysym;
    374   int scancode = e->key();
    375   /* Set the keysym information */
    376   if(scancode >= 'A' && scancode <= 'Z') {
    377     // Qt sends uppercase, SDL wants lowercase
    378     keysym.sym = static_cast<SDLKey>(scancode + 32);
    379   } else if(scancode  >= 0x1000) {
    380     // Special keys
    381     switch(scancode) {
    382     case Qt::Key_Escape: scancode = SDLK_ESCAPE; break;
    383     case Qt::Key_Tab: scancode = SDLK_TAB; break;
    384     case Qt::Key_Backspace: scancode = SDLK_BACKSPACE; break;
    385     case Qt::Key_Return: scancode = SDLK_RETURN; break;
    386     case Qt::Key_Enter: scancode = SDLK_KP_ENTER; break;
    387     case Qt::Key_Insert: scancode = SDLK_INSERT; break;
    388     case Qt::Key_Delete: scancode = SDLK_DELETE; break;
    389     case Qt::Key_Pause: scancode = SDLK_PAUSE; break;
    390     case Qt::Key_Print: scancode = SDLK_PRINT; break;
    391     case Qt::Key_SysReq: scancode = SDLK_SYSREQ; break;
    392     case Qt::Key_Home: scancode = SDLK_HOME; break;
    393     case Qt::Key_End: scancode = SDLK_END; break;
    394     // We want the control keys to rotate with the screen
    395     case Qt::Key_Left:
    396         if (screenRotation == SDL_QT_ROTATION_90) scancode = SDLK_UP;
    397         else if (screenRotation == SDL_QT_ROTATION_270) scancode = SDLK_DOWN;
    398         else scancode = SDLK_LEFT;
    399         break;
    400     case Qt::Key_Up:
    401         if (screenRotation == SDL_QT_ROTATION_90) scancode = SDLK_RIGHT;
    402         else if (screenRotation == SDL_QT_ROTATION_270) scancode = SDLK_LEFT;
    403         else scancode = SDLK_UP;
    404         break;
    405     case Qt::Key_Right:
    406         if (screenRotation == SDL_QT_ROTATION_90) scancode = SDLK_DOWN;
    407         else if (screenRotation == SDL_QT_ROTATION_270) scancode = SDLK_UP;
    408         else scancode = SDLK_RIGHT;
    409         break;
    410     case Qt::Key_Down:
    411         if (screenRotation == SDL_QT_ROTATION_90) scancode = SDLK_LEFT;
    412         else if (screenRotation == SDL_QT_ROTATION_270) scancode = SDLK_RIGHT;
    413         else scancode = SDLK_DOWN;
    414         break;
    415     case Qt::Key_Prior: scancode = SDLK_PAGEUP; break;
    416     case Qt::Key_Next: scancode = SDLK_PAGEDOWN; break;
    417     case Qt::Key_Shift: scancode = SDLK_LSHIFT; break;
    418     case Qt::Key_Control: scancode = SDLK_LCTRL; break;
    419     case Qt::Key_Meta: scancode = SDLK_LMETA; break;
    420     case Qt::Key_Alt: scancode = SDLK_LALT; break;
    421     case Qt::Key_CapsLock: scancode = SDLK_CAPSLOCK; break;
    422     case Qt::Key_NumLock: scancode = SDLK_NUMLOCK; break;
    423     case Qt::Key_ScrollLock: scancode = SDLK_SCROLLOCK; break;
    424     case Qt::Key_F1: scancode = SDLK_F1; break;
    425     case Qt::Key_F2: scancode = SDLK_F2; break;
    426     case Qt::Key_F3: scancode = SDLK_F3; break;
    427     case Qt::Key_F4: scancode = SDLK_F4; break;
    428     case Qt::Key_F5: scancode = SDLK_F5; break;
    429     case Qt::Key_F6: scancode = SDLK_F6; break;
    430     case Qt::Key_F7: scancode = SDLK_F7; break;
    431     case Qt::Key_F8: scancode = SDLK_F8; break;
    432     case Qt::Key_F9: scancode = SDLK_F9; break;
    433     case Qt::Key_F10: scancode = SDLK_F10; break;
    434     case Qt::Key_F11: scancode = SDLK_F11; break;
    435     case Qt::Key_F12: scancode = SDLK_F12; break;
    436     case Qt::Key_F13: scancode = SDLK_F13; break;
    437     case Qt::Key_F14: scancode = SDLK_F14; break;
    438     case Qt::Key_F15: scancode = SDLK_F15; break;
    439     case Qt::Key_Super_L: scancode = SDLK_LSUPER; break;
    440     case Qt::Key_Super_R: scancode = SDLK_RSUPER; break;
    441     case Qt::Key_Menu: scancode = SDLK_MENU; break;
    442     case Qt::Key_Help: scancode = SDLK_HELP; break;
    443 
    444     case Qt::Key_F33:
    445       // FIXME: This is a hack to enable the OK key on
    446       // Zaurii devices. SDLK_RETURN is a suitable key to use
    447       // since it often is used as such.
    448       //     david (at) hedbor.org
    449       scancode = SDLK_RETURN;
    450       break;
    451     default:
    452       scancode = SDLK_UNKNOWN;
    453       break;
    454     }
    455     keysym.sym = static_cast<SDLKey>(scancode);
    456   } else {
    457     keysym.sym = static_cast<SDLKey>(scancode);
    458   }
    459   keysym.scancode = scancode;
    460   keysym.mod = KMOD_NONE;
    461   ButtonState st = e->state();
    462   if( (st & ShiftButton) )   { keysym.mod = static_cast<SDLMod>(keysym.mod | KMOD_LSHIFT);  }
    463   if( (st & ControlButton) ) { keysym.mod = static_cast<SDLMod>(keysym.mod | KMOD_LCTRL);  }
    464   if( (st & AltButton) )     { keysym.mod = static_cast<SDLMod>(keysym.mod | KMOD_LALT);  }
    465   if ( SDL_TranslateUNICODE ) {
    466     QChar qchar = e->text()[0];
    467     keysym.unicode = qchar.unicode();
    468   } else {
    469     keysym.unicode = 0;
    470   }
    471 
    472   /* NUMLOCK and CAPSLOCK are implemented as double-presses in reality */
    473   //	if ( (keysym.sym == SDLK_NUMLOCK) || (keysym.sym == SDLK_CAPSLOCK) ) {
    474   //		pressed = 1;
    475   //	}
    476 
    477   /* Queue the key event */
    478   if ( pressed ) {
    479     SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
    480   } else {
    481     SDL_PrivateKeyboard(SDL_RELEASED, &keysym);
    482   }
    483 }
    484 
    485 void SDL_QWin::setFullscreen(bool fs_on) {
    486   my_has_fullscreen = false;
    487   enableFullscreen();
    488 }
    489 
    490 void SDL_QWin::enableFullscreen() {
    491   // Make sure size is correct
    492   if(!my_has_fullscreen) {
    493     setFixedSize(qApp->desktop()->size());
    494     // This call is needed because showFullScreen won't work
    495     // correctly if the widget already considers itself to be fullscreen.
    496     showNormal();
    497     // This is needed because showNormal() forcefully changes the window
    498     // style to WSTyle_TopLevel.
    499     setWFlags(WStyle_Customize | WStyle_NoBorder);
    500     // Enable fullscreen.
    501     showFullScreen();
    502     my_has_fullscreen = true;
    503   }
    504 }
    505 
    506 bool SDL_QWin::lockScreen(bool force) {
    507   if(!my_painter) {
    508     if(force || (isVisible() && isActiveWindow())) {
    509       my_painter = new QDirectPainter(this);
    510     } else {
    511       return false;
    512     }
    513   }
    514   my_locked++; // Increate lock refcount
    515   return true;
    516 }
    517 
    518 void SDL_QWin::unlockScreen() {
    519   if(my_locked > 0) {
    520     my_locked--; // decrease lock refcount;
    521   }
    522   if(!my_locked && my_painter) {
    523     my_painter->end();
    524     delete my_painter;
    525     my_painter = 0;
    526   }
    527 }
    528