/* [<][>][^][v][top][bottom][index][help] */
//
// Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
// 2011 Free Software Foundation, Inc
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifdef HAVE_CONFIG_H
#include "gnashconfig.h"
#endif
#include <cstdio>
#include "log.h"
#include "sdlsup.h"
#include "Range2d.h" // for Intersection of inv bounds
#include "Renderer.h" // for setInvalidatedRegions
#include "RunResources.h"
using namespace std;
namespace gnash
{
SDLGui::SDLGui(unsigned long xid, float scale, bool loop, RunResources& r)
: Gui(xid, scale, loop, r),
_timeout(0),
_core_trap(true)
{
}
SDLGui::~SDLGui()
{
}
bool
SDLGui::run()
{
int x_old = -1;
int y_old = -1;
int button_state_old = -1;
Uint32 movie_time = 0;// SDL_GetTicks(); // what time it should be in the movie
SDL_Event event;
while (true)
{
if (_timeout && SDL_GetTicks() >= _timeout)
{
break;
}
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_MOUSEMOTION:
// SDL can generate MOUSEMOTION events even without mouse movement
if (event.motion.x == x_old && event.motion.y == y_old) { break; }
x_old = event.motion.x;
y_old = event.motion.y;
notifyMouseMove(x_old, y_old);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
if (event.button.state == SDL_PRESSED) {
// multiple events will be fired while the mouse is held down
// we are interested only in a change in the mouse state:
if (event.button.button == button_state_old) { break; }
notifyMouseClick(true);
button_state_old = event.button.button;
} else {
notifyMouseClick(false);
button_state_old = -1;
}
break;
}
case SDL_KEYDOWN:
{
if (event.key.keysym.sym == SDLK_ESCAPE)
{
return true;
}
key_event(&event.key, true);
break;
}
case SDL_KEYUP:
{
key_event(&event.key, false);
break;
}
case SDL_VIDEORESIZE:
resize_event();
break;
case SDL_VIDEOEXPOSE:
expose_event();
break;
case SDL_QUIT:
return true;
break;
}
}
// Wait until real time catches up with movie time.
int delay = movie_time - SDL_GetTicks();
if (delay > 0)
{
SDL_Delay(delay);
}
advanceMovie();
movie_time += _interval; // Time next frame should be displayed
}
return false;
}
void
SDLGui::setTimeout(unsigned int timeout)
{
_timeout = timeout;
}
bool
SDLGui::init(int argc, char **argv[])
{
disableCoreTrap();
if (_xid) {
char SDL_windowhack[32];
snprintf (SDL_windowhack, sizeof(SDL_windowhack), "SDL_WINDOWID=%ld", _xid);
putenv (SDL_windowhack);
}
// Initialize the SDL subsystems we're using. Linux
// and Darwin use Pthreads for SDL threads, Win32
// doesn't. Otherwise the SDL event loop just polls.
if (SDL_Init(SDL_INIT_VIDEO)) {
fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
atexit(SDL_Quit);
SDL_EnableKeyRepeat(250, 33);
_glue.init(argc, argv);
_renderer.reset(_glue.createRenderHandler(32));
if ( ! _renderer ) return false;
return true;
}
bool
SDLGui::createWindow(const char *title, int width, int height,
int /*xPosition*/, int /*yPosition*/)
{
_width = width;
_height = height;
boost::uint32_t sdl_flags = 0;
if (!_core_trap) {
sdl_flags |= SDL_INIT_NOPARACHUTE;
}
if (_xid) {
sdl_flags |= SDL_NOFRAME;
}
_glue.prepDrawingArea(_width, _height, sdl_flags);
_runResources.setRenderer(_renderer);
SDL_WM_SetCaption( title, title);
return false;
}
void
SDLGui::disableCoreTrap()
{
_core_trap = false;
}
/* public, overridden */
void
SDLGui::setInvalidatedRegions(const InvalidatedRanges& ranges)
{
_glue.setInvalidatedRegions(ranges);
}
void
SDLGui::renderBuffer()
{
_glue.render();
}
void
SDLGui::setInterval(unsigned int interval)
{
_interval = interval;
}
bool
SDLGui::createMenu()
{
return false;
}
bool
SDLGui::setupEvents()
{
return false;
}
key::code
SDLGui::sdl_to_gnash_key(SDL_KeyboardEvent * key)
{
gnash::key::code c(gnash::key::INVALID);
// TODO: take care of CAPS_LOCK and NUM_LOCK and SHIFT
// int mod = key->keysym.mod;
int code = key->keysym.sym;
if(code>= 32 && code <= 127) {
c = (gnash::key::code)(code);
}else if(code >= SDLK_KP0 && code <= SDLK_KP9) {
c = (gnash::key::code)(code - SDLK_KP0 + gnash::key::KP_0);
}else if(code >= SDLK_F1 && code <= SDLK_F15) {
c = (gnash::key::code)(code - SDLK_F1 + gnash::key::F1);
}else
{
switch(code) {
case SDLK_UP: c = gnash::key::UP; break;
case SDLK_DOWN: c = gnash::key::DOWN; break;
case SDLK_RIGHT: c = gnash::key::RIGHT; break;
case SDLK_LEFT: c = gnash::key::LEFT; break;
case SDLK_INSERT: c = gnash::key::INSERT; break;
case SDLK_HOME: c = gnash::key::HOME; break;
case SDLK_END: c = gnash::key::END; break;
case SDLK_PAGEUP: c = gnash::key::PGUP; break;
case SDLK_PAGEDOWN: c = gnash::key::PGDN; break;
case SDLK_RSHIFT:
case SDLK_LSHIFT: c = gnash::key::SHIFT; break;
case SDLK_RCTRL:
case SDLK_LCTRL: c = gnash::key::CONTROL; break;
case SDLK_RALT:
case SDLK_LALT: c = gnash::key::ALT; break;
default: c = gnash::key::INVALID; break;
}
}
return c;
}
int
SDLGui::sdl_to_gnash_modifier(int state)
{
int modifier = gnash::key::GNASH_MOD_NONE;
if (state & KMOD_SHIFT) {
modifier = modifier | gnash::key::GNASH_MOD_SHIFT;
}
if (state & KMOD_CTRL) {
modifier = modifier | gnash::key::GNASH_MOD_CONTROL;
}
if (state & KMOD_ALT) {
modifier = modifier | gnash::key::GNASH_MOD_ALT;
}
return modifier;
}
void SDLGui::key_event(SDL_KeyboardEvent* key, bool down)
// For forwarding SDL key events.
{
gnash::key::code c = sdl_to_gnash_key(key);
if (c != gnash::key::INVALID)
{
int mod = sdl_to_gnash_modifier(key->keysym.mod);
notify_key_event(c, mod, down);
}
}
void
SDLGui::resize_event()
{
log_debug("got resize_event ");
}
void
SDLGui::expose_event()
{
// TODO: implement and use setInvalidatedRegion instead?
renderBuffer();
}
} // namespace gnash