From b2a753891884f0b0488df8796179b8d4beda600c Mon Sep 17 00:00:00 2001 From: norad Date: Sun, 22 Apr 2012 12:42:59 +0000 Subject: Patch:graphics/sdl:split into multiple files git-svn-id: http://svn.code.sf.net/p/navit/code/trunk/navit@5028 ffa7fe5e-494d-0410-b361-a75ebd5db220 --- navit/graphics/sdl/event.c | 381 ++++++++++++++++++++++++++++++++++++++ navit/graphics/sdl/event_sdl.c | 343 ++++++++++++++++++++++++++++++++++ navit/graphics/sdl/event_sdl.h | 44 +++++ navit/graphics/sdl/graphics_sdl.h | 13 ++ 4 files changed, 781 insertions(+) create mode 100644 navit/graphics/sdl/event.c create mode 100644 navit/graphics/sdl/event_sdl.c create mode 100644 navit/graphics/sdl/event_sdl.h create mode 100644 navit/graphics/sdl/graphics_sdl.h (limited to 'navit') diff --git a/navit/graphics/sdl/event.c b/navit/graphics/sdl/event.c new file mode 100644 index 000000000..9636736ea --- /dev/null +++ b/navit/graphics/sdl/event.c @@ -0,0 +1,381 @@ +/* + * event.c + * + * Created on: 01.05.2011 + * Author: norad + */ + +#include "webos/webos.h" + +struct event_timeout { + SDL_TimerID id; + int multi; + struct callback *cb; +}; + +struct idle_task { + int priority; + struct callback *cb; +}; + +struct event_watch { + struct pollfd *pfd; + struct callback *cb; +}; + +static void event_sdl_watch_thread(GPtrArray *); +static void event_sdl_watch_startthread(GPtrArray *watch_list); +static void event_sdl_watch_stopthread(void); +static struct event_watch *event_sdl_add_watch(void *, enum event_watch_cond, + struct callback *); +static void event_sdl_remove_watch(struct event_watch *); +static struct event_timeout *event_sdl_add_timeout(int, int, struct callback *); +static void event_sdl_remove_timeout(struct event_timeout *); +static struct event_idle *event_sdl_add_idle(int, struct callback *); +static void event_sdl_remove_idle(struct event_idle *); +static void event_sdl_call_callback(struct callback_list *); + +# ifdef USE_WEBOS_ACCELEROMETER +static unsigned int sdl_orientation_count = 2 ^ 16; +static char sdl_next_orientation = WEBOS_ORIENTATION_PORTRAIT; +static SDL_Joystick *accelerometer = NULL; +static unsigned int orientation = WEBOS_ORIENTATION_PORTRAIT; + +static void sdl_accelerometer_handler(void* param) { + struct graphics_priv *gr = (struct graphics_priv *) param; + int xAxis = SDL_JoystickGetAxis(accelerometer, 0); + int yAxis = SDL_JoystickGetAxis(accelerometer, 1); + int zAxis = SDL_JoystickGetAxis(accelerometer, 2); + unsigned char new_orientation; + + dbg(2, "x(%d) y(%d) z(%d) c(%d)\n", xAxis, yAxis, zAxis, + sdl_orientation_count); + + if (zAxis > -30000) { + if (xAxis < -15000 && yAxis > -5000 && yAxis < 5000) + new_orientation = WEBOS_ORIENTATION_LANDSCAPE; + else if (yAxis > 15000 && xAxis > -5000 && xAxis < 5000) + new_orientation = WEBOS_ORIENTATION_PORTRAIT; + else + return; + } else + return; + + if (new_orientation == sdl_next_orientation) { + if (sdl_orientation_count < 3) + sdl_orientation_count++; + } else { + sdl_orientation_count = 0; + sdl_next_orientation = new_orientation; + return; + } + + if (sdl_orientation_count == 3) { + sdl_orientation_count++; + + if (new_orientation != orientation) { + dbg(1, "x(%d) y(%d) z(%d) o(%d)\n", xAxis, yAxis, zAxis, + new_orientation); + orientation = new_orientation; + + SDL_Event event; + SDL_UserEvent userevent; + + userevent.type = SDL_USEREVENT; + userevent.code = SDL_USEREVENT_CODE_ROTATE; + userevent.data1 = NULL; + userevent.data2 = NULL; + + event.type = SDL_USEREVENT; + event.user = userevent; + + SDL_PushEvent(&event); + } + } +} +#endif + +/* ---------- SDL Eventhandling ---------- */ + +static Uint32 sdl_timer_callback(Uint32 interval, void* param) { + struct event_timeout *timeout = (struct event_timeout*) param; + + dbg(1, "timer(%p) multi(%d) interval(%d) fired\n", param, timeout->multi, + interval); + + SDL_Event event; + SDL_UserEvent userevent; + + userevent.type = SDL_USEREVENT; + userevent.code = SDL_USEREVENT_CODE_TIMER; + userevent.data1 = timeout->cb; + userevent.data2 = NULL; + + event.type = SDL_USEREVENT; + event.user = userevent; + + SDL_PushEvent(&event); + + if (timeout->multi == 0) { + g_free(timeout); + timeout = NULL; + return 0; // cancel timer + } + return interval; // reactivate timer +} + +/* SDL Mainloop */ + +static void event_sdl_main_loop_run(void) { +#ifdef USE_WEBOS_ACCELEROMETER + struct callback* accel_cb = NULL; + struct event_timeout* accel_to = NULL; + if (PDL_GetPDKVersion() > 100) { + accel_cb = callback_new_1(callback_cast(sdl_accelerometer_handler), gr); + accel_to = event_add_timeout(200, 1, accel_cb); + } +#endif + graphics_sdl_idle(NULL); + + event_sdl_watch_stopthread(); + +#ifdef USE_WEBOS_ACCELEROMETER + SDL_JoystickClose(accelerometer); + if (PDL_GetPDKVersion() > 100) { + event_remove_timeout(accel_to); + callback_destroy(accel_cb); + } +#endif +} + +static void event_sdl_main_loop_quit(void) { + quit_event_loop = 1; +} + +/* Watch */ + +static void event_sdl_watch_thread(GPtrArray *watch_list) { + struct pollfd *pfds = g_new0 (struct pollfd, watch_list->len); + struct event_watch *ew; + int ret; + int idx; + + for (idx = 0; idx < watch_list->len; idx++) { + ew = g_ptr_array_index(watch_list, idx); + g_memmove(&pfds[idx], ew->pfd, sizeof(struct pollfd)); + } + + while ((ret = ppoll(pfds, watch_list->len, NULL, NULL)) > 0) { + for (idx = 0; idx < watch_list->len; idx++) { + if (pfds[idx].revents == pfds[idx].events) { /* The requested event happened, notify mainloop! */ + ew = g_ptr_array_index(watch_list, idx); + dbg(1, "watch(%p) event(%d) encountered\n", ew, + pfds[idx].revents); + + SDL_Event event; + SDL_UserEvent userevent; + + userevent.type = SDL_USEREVENT; + userevent.code = SDL_USEREVENT_CODE_WATCH; + userevent.data1 = ew->cb; + userevent.data2 = NULL; + + event.type = SDL_USEREVENT; + event.user = userevent; + + SDL_PushEvent(&event); + } + } + } + + g_free(pfds); + + pthread_exit(0); +} + +static void event_sdl_watch_startthread(GPtrArray *watch_list) { + dbg(1, "enter\n"); + if (sdl_watch_thread) + event_sdl_watch_stopthread(); + + int ret; + ret = pthread_create(&sdl_watch_thread, NULL, + (void *) event_sdl_watch_thread, (void *) watch_list); + + dbg_assert(ret == 0); +} + +static void event_sdl_watch_stopthread() { + dbg(1, "enter\n"); + if (sdl_watch_thread) { + /* Notify the watch thread that the list of FDs will change */ + pthread_kill(sdl_watch_thread, SIGUSR1); + pthread_join(sdl_watch_thread, NULL); + sdl_watch_thread = 0; + } +} + +static struct event_watch * +event_sdl_add_watch(void *fd, enum event_watch_cond cond, struct callback *cb) { + dbg(1, "fd(%d) cond(%x) cb(%x)\n", fd, cond, cb); + + event_sdl_watch_stopthread(); + + if (!sdl_watch_list) + sdl_watch_list = g_ptr_array_new(); + + struct event_watch *new_ew = g_new0 (struct event_watch, 1); + struct pollfd *pfd = g_new0 (struct pollfd, 1); + + pfd->fd = (int) fd; + + /* Modify watchlist here */ + switch (cond) { + case event_watch_cond_read: + pfd->events = POLLIN; + break; + case event_watch_cond_write: + pfd->events = POLLOUT; + break; + case event_watch_cond_except: + pfd->events = POLLERR | POLLHUP; + break; + } + + new_ew->pfd = (struct pollfd*) pfd; + new_ew->cb = cb; + + g_ptr_array_add(sdl_watch_list, (gpointer) new_ew); + + event_sdl_watch_startthread(sdl_watch_list); + + return new_ew; +} + +static void event_sdl_remove_watch(struct event_watch *ew) { + dbg(1, "enter %p\n", ew); + + event_sdl_watch_stopthread(); + + g_ptr_array_remove(sdl_watch_list, ew); + g_free(ew->pfd); + g_free(ew); + + if (sdl_watch_list->len > 0) + event_sdl_watch_startthread(sdl_watch_list); +} + +/* Timeout */ + +static struct event_timeout * +event_sdl_add_timeout(int timeout, int multi, struct callback *cb) { + struct event_timeout * ret = g_new0(struct event_timeout, 1); + if (!ret) + return ret; + dbg(1, "timer(%p) multi(%d) interval(%d) cb(%p) added\n", ret, multi, + timeout, cb); + ret->multi = multi; + ret->cb = cb; + ret->id = SDL_AddTimer(timeout, sdl_timer_callback, ret); + + return ret; +} + +static void event_sdl_remove_timeout(struct event_timeout *to) { + dbg(2, "enter %p\n", to); + if (to != NULL) { + int ret = to->id ? SDL_RemoveTimer(to->id) : SDL_TRUE; + if (ret == SDL_FALSE) { + dbg(0, "SDL_RemoveTimer (%p) failed\n", to->id); + } else { + g_free(to); + dbg(1, "timer(%p) removed\n", to); + } + } +} + +/* Idle */ + +/* sort ptr_array by priority, increasing order */ +static gint sdl_sort_idle_tasks(gconstpointer parama, gconstpointer paramb) { + struct idle_task *a = (struct idle_task *) parama; + struct idle_task *b = (struct idle_task *) paramb; + if (a->priority < b->priority) + return -1; + if (a->priority > b->priority) + return 1; + return 0; +} + +static struct event_idle * +event_sdl_add_idle(int priority, struct callback *cb) { + dbg(1, "add idle priority(%d) cb(%p)\n", priority, cb); + + struct idle_task *task = g_new0(struct idle_task, 1); + task->priority = priority; + task->cb = cb; + + g_ptr_array_add(idle_tasks, (gpointer) task); + + if (idle_tasks->len < 2) { + SDL_Event event; + SDL_UserEvent userevent; + + dbg(1, "poking eventloop because of new idle_events\n"); + + userevent.type = SDL_USEREVENT; + userevent.code = SDL_USEREVENT_CODE_IDLE_EVENT; + userevent.data1 = NULL; + userevent.data2 = NULL; + + event.type = SDL_USEREVENT; + event.user = userevent; + + SDL_PushEvent(&event); + } else + // more than one entry => sort the list + g_ptr_array_sort(idle_tasks, sdl_sort_idle_tasks); + + return (struct event_idle *) task; +} + +static void event_sdl_remove_idle(struct event_idle *task) { + dbg(1, "remove task(%p)\n", task); + g_ptr_array_remove(idle_tasks, (gpointer) task); +} + +/* callback */ + +static void event_sdl_call_callback(struct callback_list *cbl) { + dbg(1, "call_callback cbl(%p)\n", cbl); + SDL_Event event; + SDL_UserEvent userevent; + + userevent.type = SDL_USEREVENT; + userevent.code = SDL_USEREVENT_CODE_CALL_CALLBACK; + userevent.data1 = cbl; + userevent.data2 = NULL; + + event.type = SDL_USEREVENT; + event.user = userevent; + + SDL_PushEvent(&event); +} + +static struct event_methods event_sdl_methods = { event_sdl_main_loop_run, + event_sdl_main_loop_quit, event_sdl_add_watch, event_sdl_remove_watch, + event_sdl_add_timeout, event_sdl_remove_timeout, event_sdl_add_idle, + event_sdl_remove_idle, event_sdl_call_callback, }; + +static struct event_priv * +event_sdl_new(struct event_methods* methods) { + idle_tasks = g_ptr_array_new(); + *methods = event_sdl_methods; + return NULL; +} + +/* ---------- SDL Eventhandling ---------- */ + +void sdl_event_init(void) { + plugin_register_event_type("sdl", event_sdl_new); +} diff --git a/navit/graphics/sdl/event_sdl.c b/navit/graphics/sdl/event_sdl.c new file mode 100644 index 000000000..fb35e7b16 --- /dev/null +++ b/navit/graphics/sdl/event_sdl.c @@ -0,0 +1,343 @@ +/** + * Navit, a modular navigation system. + * Copyright (C) 2005-2008 Navit Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include "config.h" +#include "event.h" +#include "event_sdl.h" +#include "graphics_sdl.h" +#include "debug.h" +#include "callback.h" +#include "plugin.h" + +static pthread_t sdl_watch_thread = 0; +static GPtrArray *sdl_watch_list = NULL; + +static void event_sdl_watch_startthread(GPtrArray *); +static void event_sdl_watch_stopthread(void); +static struct event_watch *event_sdl_add_watch(void *, enum event_watch_cond, struct callback *); +static void event_sdl_remove_watch(struct event_watch *); +static struct event_timeout *event_sdl_add_timeout(int, int, struct callback *); +static void event_sdl_remove_timeout(struct event_timeout *); +static struct event_idle *event_sdl_add_idle(int, struct callback *); +static void event_sdl_remove_idle(struct event_idle *); +static void event_sdl_call_callback(struct callback_list *); + +static Uint32 +sdl_timer_callback(Uint32 interval, void* param) +{ + struct event_timeout *timeout=(struct event_timeout*)param; + + dbg(1,"timer(%p) multi(%d) interval(%d) fired\n", param, timeout->multi, interval); + + SDL_Event event; + SDL_UserEvent userevent; + + userevent.type = SDL_USEREVENT; + userevent.code = SDL_USEREVENT_CODE_TIMER; + userevent.data1 = timeout->cb; + userevent.data2 = NULL; + + event.type = SDL_USEREVENT; + event.user = userevent; + + SDL_PushEvent (&event); + + if (timeout->multi == 0) { + timeout->id = 0; + return 0; // cancel timer + } + return interval; // reactivate timer +} + +/* SDL Mainloop */ + +static void +event_sdl_main_loop_run(void) +{ + graphics_sdl_idle(NULL); + event_sdl_watch_stopthread(); +} + +static void +event_sdl_main_loop_quit(void) +{ + quit_event_loop = 1; +} + +/* Watch */ + +void +event_sdl_watch_thread (GPtrArray *watch_list) +{ + struct pollfd *pfds = g_new0 (struct pollfd, watch_list->len); + struct event_watch *ew; + int ret; + int idx; + + for (idx = 0; idx < watch_list->len; idx++ ) { + ew = g_ptr_array_index (watch_list, idx); + g_memmove (&pfds[idx], ew->pfd, sizeof(struct pollfd)); + } + + while ((ret = ppoll(pfds, watch_list->len, NULL, NULL)) > 0) { + for (idx = 0; idx < watch_list->len; idx++ ) { + if (pfds[idx].revents == pfds[idx].events) { /* The requested event happened, notify mainloop! */ + ew = g_ptr_array_index (watch_list, idx); + dbg(1,"watch(%p) event(%d) encountered\n", ew, pfds[idx].revents); + + SDL_Event event; + SDL_UserEvent userevent; + + userevent.type = SDL_USEREVENT; + userevent.code = SDL_USEREVENT_CODE_WATCH; + userevent.data1 = ew->cb; + userevent.data2 = NULL; + + event.type = SDL_USEREVENT; + event.user = userevent; + + SDL_PushEvent (&event); + } + } + } + + g_free(pfds); + + pthread_exit(0); +} + +static void +event_sdl_watch_startthread(GPtrArray *watch_list) +{ + dbg(1,"enter\n"); + if (sdl_watch_thread) + event_sdl_watch_stopthread(); + + int ret; + ret = pthread_create (&sdl_watch_thread, NULL, (void *)event_sdl_watch_thread, (void *)watch_list); + + dbg_assert (ret == 0); +} + +static void +event_sdl_watch_stopthread() +{ + dbg(1,"enter\n"); + if (sdl_watch_thread) { + /* Notify the watch thread that the list of FDs will change */ + pthread_kill(sdl_watch_thread, SIGUSR1); + pthread_join(sdl_watch_thread, NULL); + sdl_watch_thread = 0; + } +} + +static struct event_watch * +event_sdl_add_watch(void *fd, enum event_watch_cond cond, struct callback *cb) +{ + dbg(1,"fd(%d) cond(%x) cb(%x)\n", fd, cond, cb); + + event_sdl_watch_stopthread(); + + if (!sdl_watch_list) + sdl_watch_list = g_ptr_array_new(); + + struct event_watch *new_ew = g_new0 (struct event_watch, 1); + struct pollfd *pfd = g_new0 (struct pollfd, 1); + + pfd->fd = (int) fd; + + /* Modify watchlist here */ + switch (cond) { + case event_watch_cond_read: + pfd->events = POLLIN; + break; + case event_watch_cond_write: + pfd->events = POLLOUT; + break; + case event_watch_cond_except: + pfd->events = POLLERR|POLLHUP; + break; + } + + new_ew->pfd = (struct pollfd*) pfd; + new_ew->cb = cb; + + g_ptr_array_add (sdl_watch_list, (gpointer)new_ew); + + event_sdl_watch_startthread(sdl_watch_list); + + return new_ew; +} + +static void +event_sdl_remove_watch(struct event_watch *ew) +{ + dbg(1,"enter %p\n",ew); + + event_sdl_watch_stopthread(); + + g_ptr_array_remove (sdl_watch_list, ew); + g_free (ew->pfd); + g_free (ew); + + if (sdl_watch_list->len > 0) + event_sdl_watch_startthread(sdl_watch_list); +} + +/* Timeout */ + +static struct event_timeout * +event_sdl_add_timeout(int timeout, int multi, struct callback *cb) +{ + struct event_timeout * ret = g_new0(struct event_timeout, 1); + if(!ret) { + dbg (0,"g_new0 failed\n"); + return ret; + } + dbg(1,"timer(%p) multi(%d) interval(%d) cb(%p) added\n",ret, multi, timeout, cb); + ret->multi = multi; + ret->cb = cb; + ret->id = SDL_AddTimer(timeout, sdl_timer_callback, ret); + + return ret; +} + +static void +event_sdl_remove_timeout(struct event_timeout *to) +{ + dbg(2,"enter %p\n", to); + if(to) + { + /* do not SDL_RemoveTimer if oneshot timer has already fired */ + int ret = to->id == 0 ? SDL_TRUE : SDL_RemoveTimer(to->id); + + if (ret == SDL_FALSE) + dbg(0,"SDL_RemoveTimer (%p) failed\n", to->id); + + g_free(to); + dbg(1,"timer(%p) removed\n", to); + } +} + +/* Idle */ + +/* sort ptr_array by priority, increasing order */ +static gint +sdl_sort_idle_tasks(gconstpointer parama, gconstpointer paramb) +{ + struct idle_task *a = (struct idle_task *)parama; + struct idle_task *b = (struct idle_task *)paramb; + if (a->priority < b->priority) + return -1; + if (a->priority > b->priority) + return 1; + return 0; +} + +static struct event_idle * +event_sdl_add_idle(int priority, struct callback *cb) +{ + dbg(1,"add idle priority(%d) cb(%p)\n", priority, cb); + + struct idle_task *task = g_new0(struct idle_task, 1); + task->priority = priority; + task->cb = cb; + + g_ptr_array_add(idle_tasks, (gpointer)task); + + if (idle_tasks->len < 2) + { + SDL_Event event; + SDL_UserEvent userevent; + + dbg(1,"poking eventloop because of new idle_events\n"); + + userevent.type = SDL_USEREVENT; + userevent.code = SDL_USEREVENT_CODE_IDLE_EVENT; + userevent.data1 = NULL; + userevent.data2 = NULL; + + event.type = SDL_USEREVENT; + event.user = userevent; + + SDL_PushEvent (&event); + } + else // more than one entry => sort the list + g_ptr_array_sort(idle_tasks, sdl_sort_idle_tasks); + + return (struct event_idle *)task; +} + +static void +event_sdl_remove_idle(struct event_idle *task) +{ + dbg(1,"remove task(%p)\n", task); + g_ptr_array_remove(idle_tasks, (gpointer)task); +} + +/* callback */ + +static void +event_sdl_call_callback(struct callback_list *cbl) +{ + dbg(1,"call_callback cbl(%p)\n",cbl); + SDL_Event event; + SDL_UserEvent userevent; + + userevent.type = SDL_USEREVENT; + userevent.code = SDL_USEREVENT_CODE_CALL_CALLBACK; + userevent.data1 = cbl; + userevent.data2 = NULL; + + event.type = SDL_USEREVENT; + event.user = userevent; + + SDL_PushEvent (&event); +} + +static struct event_methods event_sdl_methods = { + event_sdl_main_loop_run, + event_sdl_main_loop_quit, + event_sdl_add_watch, + event_sdl_remove_watch, + event_sdl_add_timeout, + event_sdl_remove_timeout, + event_sdl_add_idle, + event_sdl_remove_idle, + event_sdl_call_callback, +}; + +static struct event_priv * +event_sdl_new(struct event_methods* methods) +{ + idle_tasks = g_ptr_array_new(); + *methods = event_sdl_methods; + return NULL; +} + +void +event_sdl_register(void) +{ + plugin_register_event_type("sdl", event_sdl_new); +} diff --git a/navit/graphics/sdl/event_sdl.h b/navit/graphics/sdl/event_sdl.h new file mode 100644 index 000000000..7dceedec5 --- /dev/null +++ b/navit/graphics/sdl/event_sdl.h @@ -0,0 +1,44 @@ + +#ifndef __EVENT_SDL_H +#define __EVENT_SDL_H + +#include +#include "config.h" +#include "callback.h" +#include "event.h" +#include "graphics_sdl.h" + +#ifdef USE_WEBOS +# define SDL_USEREVENT_CODE_TIMER 0x1 +# define SDL_USEREVENT_CODE_CALL_CALLBACK 0x2 +# define SDL_USEREVENT_CODE_IDLE_EVENT 0x4 +# define SDL_USEREVENT_CODE_WATCH 0x8 +# ifdef USE_WEBOS_ACCELEROMETER +# define SDL_USEREVENT_CODE_ROTATE 0xA +# endif +#endif + +struct event_timeout { + SDL_TimerID id; + int multi; + struct callback *cb; +}; + +struct idle_task { + int priority; + struct callback *cb; +}; + +struct event_watch { + struct pollfd *pfd; + struct callback *cb; +}; + +int quit_event_loop = 0; // quit the main event loop +static GPtrArray *idle_tasks = NULL; + +void event_sdl_watch_thread (GPtrArray *); + +void event_sdl_register(void); + +#endif diff --git a/navit/graphics/sdl/graphics_sdl.h b/navit/graphics/sdl/graphics_sdl.h new file mode 100644 index 000000000..5934abee0 --- /dev/null +++ b/navit/graphics/sdl/graphics_sdl.h @@ -0,0 +1,13 @@ + +#ifndef __GRAPHICS_SDL_H +#define __GRAPHICS_SDL_H + +#include + +#ifdef USE_WEBOS +# define USE_WEBOS_ACCELEROMETER +#endif + +gboolean graphics_sdl_idle(void *); + +#endif -- cgit v1.2.1