Files
xserver_xsdl/hw/kdrive/sdl/sdl.c
2018-12-21 23:26:25 +02:00

436 lines
11 KiB
C

/*
* Copyright © 2004 PillowElephantBadgerBankPond
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of PillowElephantBadgerBankPond not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. PillowElephantBadgerBankPond makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* PillowElephantBadgerBankPond DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL PillowElephantBadgerBankPond BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* It's really not my fault - see it was the elephants!!
* - jaymz
*
*/
#ifdef HAVE_CONFIG_H
#include "kdrive-config.h"
#endif
#include "kdrive.h"
#include <SDL/SDL.h>
#include <SDL/SDL_screenkeyboard.h>
#include <X11/keysym.h>
#include <android/log.h>
// DEBUG
//#define printf(...)
#define printf(...) __android_log_print(ANDROID_LOG_INFO, "XSDL", __VA_ARGS__)
static void xsdlFini(void);
static Bool sdlScreenInit(KdScreenInfo *screen);
static Bool sdlFinishInitScreen(ScreenPtr pScreen);
static Bool sdlCreateRes(ScreenPtr pScreen);
static void sdlKeyboardFini(KdKeyboardInfo *ki);
static Status sdlKeyboardInit(KdKeyboardInfo *ki);
static Status sdlKeyboardEnable (KdKeyboardInfo *ki);
static void sdlKeyboardDisable (KdKeyboardInfo *ki);
static void sdlKeyboardLeds (KdKeyboardInfo *ki, int leds);
static void sdlKeyboardBell (KdKeyboardInfo *ki, int volume, int frequency, int duration);
static Bool sdlMouseInit(KdPointerInfo *pi);
static void sdlMouseFini(KdPointerInfo *pi);
static Status sdlMouseEnable (KdPointerInfo *pi);
static void sdlMouseDisable (KdPointerInfo *pi);
void *sdlShadowWindow (ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode, CARD32 *size, void *closure);
void sdlShadowUpdate (ScreenPtr pScreen, shadowBufPtr pBuf);
void sdlPollInput(void);
KdKeyboardInfo *sdlKeyboard = NULL;
KdPointerInfo *sdlPointer = NULL;
KdKeyboardDriver sdlKeyboardDriver = {
.name = "keyboard",
.Init = sdlKeyboardInit,
.Fini = sdlKeyboardFini,
.Enable = sdlKeyboardEnable,
.Disable = sdlKeyboardDisable,
.Leds = sdlKeyboardLeds,
.Bell = sdlKeyboardBell,
};
KdPointerDriver sdlMouseDriver = {
.name = "mouse",
.Init = sdlMouseInit,
.Fini = sdlMouseFini,
.Enable = sdlMouseEnable,
.Disable = sdlMouseDisable,
};
KdCardFuncs sdlFuncs = {
.scrinit = sdlScreenInit, /* scrinit */
.finishInitScreen = sdlFinishInitScreen, /* finishInitScreen */
.createRes = sdlCreateRes, /* createRes */
};
int mouseState = 0;
enum { NUMRECTS = 32, FULLSCREEN_REFRESH_TIME = 1000 };
//Uint32 nextFullScreenRefresh = 0;
struct SdlDriver
{
SDL_Surface *screen;
};
static Bool sdlScreenInit(KdScreenInfo *screen)
{
struct SdlDriver *sdlDriver=calloc(1, sizeof(struct SdlDriver));
printf("sdlScreenInit()\n");
if (!screen->width || !screen->height)
{
screen->width = 640;
screen->height = 480;
}
if (!screen->fb.depth)
screen->fb.depth = 4;
printf("Attempting for %dx%d/%dbpp mode\n", screen->width, screen->height, screen->fb.depth);
sdlDriver->screen=SDL_SetVideoMode(screen->width, screen->height, screen->fb.depth, 0);
if(sdlDriver->screen==NULL)
return FALSE;
printf("Set %dx%d/%dbpp mode\n", sdlDriver->screen->w, sdlDriver->screen->h, sdlDriver->screen->format->BitsPerPixel);
screen->width=sdlDriver->screen->w;
screen->height=sdlDriver->screen->h;
screen->fb.depth=sdlDriver->screen->format->BitsPerPixel;
screen->fb.visuals=(1<<TrueColor);
screen->fb.redMask=sdlDriver->screen->format->Rmask;
screen->fb.greenMask=sdlDriver->screen->format->Gmask;
screen->fb.blueMask=sdlDriver->screen->format->Bmask;
screen->fb.bitsPerPixel=sdlDriver->screen->format->BitsPerPixel;
screen->rate=30; // 60 is too intense for CPU
screen->driver=sdlDriver;
screen->fb.byteStride=sdlDriver->screen->pitch;
screen->fb.pixelStride=sdlDriver->screen->w;
screen->fb.frameBuffer=(CARD8 *)sdlDriver->screen->pixels;
SDL_WM_SetCaption("Freedesktop.org X server (SDL)", NULL);
return TRUE;
}
void sdlShadowUpdate (ScreenPtr pScreen, shadowBufPtr pBuf)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
struct SdlDriver *sdlDriver=screen->driver;
pixman_box16_t * rects;
int amount, i;
int updateRectsPixelCount = 0;
/*
// Not needed on Android
if(SDL_MUSTLOCK(sdlDriver->screen))
{
if(SDL_LockSurface(sdlDriver->screen)<0)
{
printf("Couldn't lock SDL surface - d'oh!\n");
return;
}
}
if(SDL_MUSTLOCK(sdlDriver->screen))
SDL_UnlockSurface(sdlDriver->screen);
*/
rects = pixman_region_rectangles(&pBuf->pDamage->damage, &amount);
for ( i = 0; i < amount; i++ )
{
updateRectsPixelCount += (pBuf->pDamage->damage.extents.x2 - pBuf->pDamage->damage.extents.x1) *
(pBuf->pDamage->damage.extents.y2 - pBuf->pDamage->damage.extents.y1);
}
// Each subrect is copied into temp buffer before uploading to OpenGL texture,
// so if total area of pixels copied is more than 1/3 of the whole screen area,
// there will be performance hit instead of optimization.
//printf("sdlShadowUpdate: time %d", SDL_GetTicks());
if ( amount > NUMRECTS || updateRectsPixelCount * 3 > sdlDriver->screen->w * sdlDriver->screen->h )
{
//printf("SDL_Flip");
SDL_Flip(sdlDriver->screen);
//nextFullScreenRefresh = 0;
}
else
{
SDL_Rect updateRects[NUMRECTS];
//if ( ! nextFullScreenRefresh )
// nextFullScreenRefresh = SDL_GetTicks() + FULLSCREEN_REFRESH_TIME;
for ( i = 0; i < amount; i++ )
{
updateRects[i].x = rects[i].x1;
updateRects[i].y = rects[i].y1;
updateRects[i].w = rects[i].x2 - rects[i].x1;
updateRects[i].h = rects[i].y2 - rects[i].y1;
//printf("sdlShadowUpdate: rect %d: %04d:%04d:%04d:%04d", i, rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
}
//printf("SDL_UpdateRects %d %d", SDL_GetTicks(), amount);
SDL_UpdateRects(sdlDriver->screen, amount, updateRects);
}
SDL_Flip(sdlDriver->screen);
}
void *sdlShadowWindow (ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode, CARD32 *size, void *closure)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
struct SdlDriver *sdlDriver = screen->driver;
*size = sdlDriver->screen->pitch;
//printf("Shadow window()\n");
return (void *)((CARD8 *)sdlDriver->screen->pixels + row * (*size) + offset);
}
static Bool sdlCreateRes(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
KdShadowFbAlloc(screen, 0);
KdShadowSet(pScreen, RR_Rotate_0, sdlShadowUpdate, sdlShadowWindow);
return TRUE;
}
static Bool sdlFinishInitScreen(ScreenPtr pScreen)
{
if (!shadowSetup (pScreen))
return FALSE;
/*
#ifdef RANDR
if (!sdlRandRInit (pScreen))
return FALSE;
#endif
*/
return TRUE;
}
static void sdlKeyboardFini(KdKeyboardInfo *ki)
{
printf("sdlKeyboardFini() %p\n", ki);
sdlKeyboard = NULL;
}
static Status sdlKeyboardInit(KdKeyboardInfo *ki)
{
ki->minScanCode = 8;
ki->maxScanCode = 255;
sdlKeyboard = ki;
printf("sdlKeyboardInit() %p\n", ki);
return Success;
}
static Status sdlKeyboardEnable (KdKeyboardInfo *ki)
{
return Success;
}
static void sdlKeyboardDisable (KdKeyboardInfo *ki)
{
}
static void sdlKeyboardLeds (KdKeyboardInfo *ki, int leds)
{
}
static void sdlKeyboardBell (KdKeyboardInfo *ki, int volume, int frequency, int duration)
{
}
static Status sdlMouseInit (KdPointerInfo *pi)
{
sdlPointer = pi;
printf("sdlMouseInit() %p\n", pi);
return Success;
}
static void sdlMouseFini(KdPointerInfo *pi)
{
printf("sdlMouseFini() %p\n", pi);
sdlPointer = NULL;
}
static Status sdlMouseEnable (KdPointerInfo *pi)
{
return Success;
}
static void sdlMouseDisable (KdPointerInfo *pi)
{
return;
}
void InitCard(char *name)
{
KdCardInfoAdd (&sdlFuncs, 0);
printf("InitCard: %s\n", name);
}
void InitOutput(ScreenInfo *pScreenInfo, int argc, char **argv)
{
KdInitOutput(pScreenInfo, argc, argv);
printf("InitOutput()\n");
}
void InitInput(int argc, char **argv)
{
KdPointerInfo *pi;
KdKeyboardInfo *ki;
KdAddKeyboardDriver(&sdlKeyboardDriver);
KdAddPointerDriver(&sdlMouseDriver);
ki = KdParseKeyboard("keyboard");
KdAddKeyboard(ki);
pi = KdParsePointer("mouse");
KdAddPointer(pi);
KdInitInput();
}
#ifdef DDXBEFORERESET
void ddxBeforeReset(void)
{
}
#endif
void ddxUseMsg(void)
{
KdUseMsg();
}
int ddxProcessArgument(int argc, char **argv, int i)
{
return KdProcessArgument(argc, argv, i);
}
void sdlPollInput(void)
{
static int buttonState=0;
static int pressure = 0;
SDL_Event event;
//printf("sdlPollInput() %d\n", SDL_GetTicks());
while ( SDL_PollEvent(&event) ) {
switch (event.type) {
case SDL_MOUSEMOTION:
//printf("SDL_MOUSEMOTION pressure %d\n", pressure);
KdEnqueuePointerEvent(sdlPointer, mouseState, event.motion.x, event.motion.y, pressure);
break;
case SDL_MOUSEBUTTONDOWN:
switch(event.button.button)
{
case 1:
buttonState=KD_BUTTON_1;
break;
case 2:
buttonState=KD_BUTTON_2;
break;
case 3:
buttonState=KD_BUTTON_3;
break;
}
mouseState|=buttonState;
KdEnqueuePointerEvent(sdlPointer, mouseState|KD_MOUSE_DELTA, 0, 0, 0);
break;
case SDL_MOUSEBUTTONUP:
switch(event.button.button)
{
case 1:
buttonState=KD_BUTTON_1;
pressure = 0;
break;
case 2:
buttonState=KD_BUTTON_2;
break;
case 3:
buttonState=KD_BUTTON_3;
break;
}
mouseState &= ~buttonState;
KdEnqueuePointerEvent(sdlPointer, mouseState|KD_MOUSE_DELTA, 0, 0, 0);
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
if (event.key.keysym.sym == SDLK_UNDO)
{
if(event.type == SDL_KEYUP)
SDL_ANDROID_ToggleScreenKeyboardWithoutTextInput();
}
else
KdEnqueueKeyboardEvent (sdlKeyboard, event.key.keysym.scancode, event.type==SDL_KEYUP);
break;
case SDL_JOYAXISMOTION:
if(event.jaxis.which == 0 && event.jaxis.axis == 4)
pressure = event.jaxis.value;
break;
//case SDL_QUIT:
/* this should never happen */
//SDL_Quit(); // SDL_Quit() on Android is buggy
}
}
/*
if ( nextFullScreenRefresh && nextFullScreenRefresh < SDL_GetTicks() )
{
//printf("SDL_Flip from sdlPollInput");
SDL_Flip(SDL_GetVideoSurface());
nextFullScreenRefresh = 0;
}
*/
}
static int xsdlInit(void)
{
printf("Calling SDL_Init()\n");
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
SDL_JoystickOpen(0); // Receive pressure events
return 0;
}
static void xsdlFini(void)
{
//SDL_Quit(); // SDL_Quit() on Android is buggy
}
void
CloseInput (void)
{
KdCloseInput ();
}
KdOsFuncs sdlOsFuncs={
.Init = xsdlInit,
.Fini = xsdlFini,
.pollEvents = sdlPollInput,
};
void OsVendorInit (void)
{
KdOsInit (&sdlOsFuncs);
}