1 /* graphics_sdl.c -- barebones sdl graphics layer
3 copyright (c) 2008 bryan rittmeyer <bryanr@bryanr.org>
9 - proper image transparency (libsdl-image xpm does not work)
14 2008-06-15 SDL_DOUBLEBUF+SDL_Flip for linux fb. fix FT leaks.
15 2008-06-18 defer initial resize_callback
16 2008-06-21 linux touchscreen
17 2008-07-04 custom rastering
36 #include "font/freetype/font_freetype.h"
44 # define USE_WEBOS_ACCELEROMETER
54 #undef LINUX_TOUCHSCREEN
68 #define OVERLAY_MAX 32
79 #include <SDL/SDL_gfxPrimitives.h>
83 #include <SDL/SDL_ttf.h>
86 #include FT_FREETYPE_H
87 #include <freetype/ftglyph.h>
92 #include <SDL/SDL_image.h>
95 #ifdef LINUX_TOUCHSCREEN
96 /* we use Linux evdev directly for the touchscreen. */
97 #include <sys/types.h>
100 #include <linux/input.h>
106 #include <sys/time.h>
111 /* TODO: union overlay + non-overlay to reduce size */
112 struct graphics_priv;
113 struct graphics_priv {
117 uint32_t video_flags;
124 struct graphics_priv *overlay_parent;
129 struct graphics_priv *overlay_array[OVERLAY_MAX];
131 enum draw_mode_num draw_mode;
133 int resize_callback_initial;
136 struct callback_list *cbl;
138 #ifdef USE_WEBOS_ACCELEROMETER
139 SDL_Joystick *accelerometer;
144 #ifdef LINUX_TOUCHSCREEN
156 struct timeval draw_begin_tv;
157 unsigned long draw_time_peak;
159 struct font_freetype_methods freetype_methods;
166 #define WEBOS_KEY_SHIFT 0x130
167 #define WEBOS_KEY_SYM 0x131
168 #define WEBOS_KEY_ORANGE 0x133
170 #define WEBOS_KEY_MOD_SHIFT 0x1
171 #define WEBOS_KEY_MOD_ORANGE 0x2
172 #define WEBOS_KEY_MOD_SYM 0x4
174 #define WEBOS_KEY_MOD_SHIFT_STICKY 0x11
175 #define WEBOS_KEY_MOD_ORANGE_STICKY 0x22
176 #define WEBOS_KEY_MOD_SYM_STICKY 0x44
178 #ifdef USE_WEBOS_ACCELEROMETER
179 # define WEBOS_ORIENTATION_PORTRAIT 0x0
180 # define WEBOS_ORIENTATION_LANDSCAPE 0x1
183 #define SDL_USEREVENT_CODE_TIMER 0x1
184 #define SDL_USEREVENT_CODE_CALL_CALLBACK 0x2
185 #define SDL_USEREVENT_CODE_IDLE_EVENT 0x4
186 #define SDL_USEREVENT_CODE_WATCH 0x8
187 #ifdef USE_WEBOS_ACCELEROMETER
188 # define SDL_USEREVENT_CODE_ROTATE 0xA
191 struct event_timeout {
207 static struct graphics_priv* the_graphics = NULL;
208 static int quit_event_loop = 0; // quit the main event loop
209 static int the_graphics_count = 0; // count how many graphics objects are created
210 static GPtrArray *idle_tasks = NULL;
211 static pthread_t sdl_watch_thread = 0;
212 static GPtrArray *sdl_watch_list = NULL;
214 static void event_sdl_watch_thread (GPtrArray *);
215 static void event_sdl_watch_startthread(GPtrArray *watch_list);
216 static void event_sdl_watch_stopthread(void);
217 static struct event_watch *event_sdl_add_watch(void *, enum event_watch_cond, struct callback *);
218 static void event_sdl_remove_watch(struct event_watch *);
219 static struct event_timeout *event_sdl_add_timeout(int, int, struct callback *);
220 static void event_sdl_remove_timeout(struct event_timeout *);
221 static struct event_idle *event_sdl_add_idle(int, struct callback *);
222 static void event_sdl_remove_idle(struct event_idle *);
223 static void event_sdl_call_callback(struct callback_list *);
224 # ifdef USE_WEBOS_ACCELEROMETER
225 static unsigned int sdl_orientation_count = 2^16;
226 static char sdl_next_orientation = WEBOS_ORIENTATION_PORTRAIT;
229 static unsigned char * ft_buffer = NULL;
230 static unsigned int ft_buffer_size = 0;
232 struct graphics_font_priv {
240 struct graphics_gc_priv {
241 struct graphics_priv *gr;
253 struct graphics_image_priv {
258 #ifdef LINUX_TOUCHSCREEN
259 static int input_ts_exit(struct graphics_priv *gr);
263 graphics_destroy(struct graphics_priv *gr)
265 dbg(0, "graphics_destroy %p %u\n", gr, gr->overlay_mode);
271 SDL_FreeSurface(gr->screen);
272 gr->overlay_parent->overlay_array[gr->overlay_idx] = NULL;
279 FT_Done_FreeType(gr->library);
281 #ifdef LINUX_TOUCHSCREEN
284 #ifdef USE_WEBOS_ACCELEROMETER
285 SDL_JoystickClose(gr->accelerometer);
299 gc_destroy(struct graphics_gc_priv *gc)
305 gc_set_linewidth(struct graphics_gc_priv *gc, int w)
308 printf("gc_set_linewidth %p %d\n", gc, w);
314 gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
320 gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
323 printf("gc_set_foreground: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
325 gc->fore_r = c->r/256;
326 gc->fore_g = c->g/256;
327 gc->fore_b = c->b/256;
328 gc->fore_a = c->a/256;
332 gc_set_background(struct graphics_gc_priv *gc, struct color *c)
335 printf("gc_set_background: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
337 gc->back_r = c->r/256;
338 gc->back_g = c->g/256;
339 gc->back_b = c->b/256;
340 gc->back_a = c->a/256;
343 static struct graphics_gc_methods gc_methods = {
351 static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
353 struct graphics_gc_priv *gc=g_new0(struct graphics_gc_priv, 1);
356 gc->linewidth=1; /* upper layer should override anyway? */
361 #if 0 /* unused by core? */
362 static void image_destroy(struct graphics_image_priv *gi)
365 SDL_FreeSurface(gi->img);
370 static struct graphics_image_methods gi_methods =
376 static struct graphics_image_priv *
377 image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name, int *w, int *h,
378 struct point *hot, int rotation)
381 struct graphics_image_priv *gi;
383 /* FIXME: meth is not used yet.. so gi leaks. at least xpm is small */
385 gi = g_new0(struct graphics_image_priv, 1);
386 gi->img = IMG_Load(name);
389 /* TBD: improves blit performance? */
390 #if !SDL_VERSION_ATLEAST(1,3,0)
391 SDL_SetColorKey(gi->img, SDL_RLEACCEL, gi->img->format->colorkey);
400 /* TODO: debug "colour parse errors" on xpm */
401 printf("graphics_sdl: image_new on '%s' failed: %s\n", name, IMG_GetError());
413 image_free(struct graphics_priv *gr, struct graphics_image_priv * gi)
416 SDL_FreeSurface(gi->img);
422 get_text_bbox(struct graphics_priv *gr, struct graphics_font_priv *font, char *text, int dx, int dy, struct point *ret, int estimate)
427 FT_GlyphSlot slot = font->face->glyph; // a small shortcut
439 bbox.xMin = bbox.yMin = 32000;
440 bbox.xMax = bbox.yMax = -32000;
441 FT_Set_Transform( font->face, &matrix, &pen );
442 len=g_utf8_strlen(text, -1);
443 for ( n = 0; n < len; n++ ) {
445 glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p));
446 p=g_utf8_next_char(p);
447 FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT );
448 FT_Get_Glyph(font->face->glyph, &glyph);
449 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox );
450 FT_Done_Glyph(glyph);
451 glyph_bbox.xMin += x >> 6;
452 glyph_bbox.xMax += x >> 6;
453 glyph_bbox.yMin += y >> 6;
454 glyph_bbox.yMax += y >> 6;
455 x += slot->advance.x;
456 y -= slot->advance.y;
457 if ( glyph_bbox.xMin < bbox.xMin )
458 bbox.xMin = glyph_bbox.xMin;
459 if ( glyph_bbox.yMin < bbox.yMin )
460 bbox.yMin = glyph_bbox.yMin;
461 if ( glyph_bbox.xMax > bbox.xMax )
462 bbox.xMax = glyph_bbox.xMax;
463 if ( glyph_bbox.yMax > bbox.yMax )
464 bbox.yMax = glyph_bbox.yMax;
466 if ( bbox.xMin > bbox.xMax ) {
483 draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
485 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
494 vx = alloca(count * sizeof(Sint16));
495 vy = alloca(count * sizeof(Sint16));
497 for(i = 0; i < count; i++)
517 printf("draw_polygon: %p %i %d,%d\n", gc, i, p[i].x, p[i].y);
524 raster_aapolygon(gr->screen, count, vx, vy,
525 SDL_MapRGBA(gr->screen->format,
533 raster_polygon(gr->screen, count, vx, vy,
534 SDL_MapRGBA(gr->screen->format,
543 sge_FilledPolygonAlpha(gr->screen, count, vx, vy,
544 SDL_MapRGB(gr->screen->format,
551 sge_AAFilledPolygon(gr->screen, count, vx, vy,
552 SDL_MapRGB(gr->screen->format,
557 sge_FilledPolygon(gr->screen, count, vx, vy,
558 SDL_MapRGB(gr->screen->format,
565 filledPolygonRGBA(gr->screen, vx, vy, count,
566 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
574 draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
576 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
582 printf("draw_rectangle: %d %d %d %d r=%d g=%d b=%d a=%d\n", p->x, p->y, w, h,
583 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
585 if(w > gr->screen->w)
589 if(h > gr->screen->h)
595 raster_rect(gr->screen, p->x, p->y, w, h,
596 SDL_MapRGBA(gr->screen->format,
604 sge_FilledRectAlpha(gr->screen, p->x, p->y, p->x + w, p->y + h,
605 SDL_MapRGB(gr->screen->format,
611 /* no AA -- should use poly instead for that */
612 sge_FilledRect(gr->screen, p->x, p->y, p->x + w, p->y + h,
613 SDL_MapRGB(gr->screen->format,
619 boxRGBA(gr->screen, p->x, p->y, p->x + w, p->y + h,
620 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
627 draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
629 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
635 if(gc->fore_a != 0xff)
637 dbg(0, "%d %d %d %u %u:%u:%u:%u\n", p->x, p->y, r, gc->linewidth,
638 gc->fore_a, gc->fore_r, gc->fore_g, gc->fore_b);
642 /* FIXME: does not quite match gtk */
644 /* hack for osd compass.. why is this needed!? */
653 raster_aacircle(gr->screen, p->x, p->y, r,
654 SDL_MapRGBA(gr->screen->format,
662 raster_circle(gr->screen, p->x, p->y, r,
663 SDL_MapRGBA(gr->screen->format,
672 sge_FilledCircleAlpha(gr->screen, p->x, p->y, r,
673 SDL_MapRGB(gr->screen->format,
674 gc->fore_r, gc->fore_g, gc->fore_b),
678 sge_AAFilledCircle(gr->screen, p->x, p->y, r,
679 SDL_MapRGB(gr->screen->format,
680 gc->fore_r, gc->fore_g, gc->fore_b));
682 sge_FilledCircle(gr->screen, p->x, p->y, r,
683 SDL_MapRGB(gr->screen->format,
684 gc->fore_r, gc->fore_g, gc->fore_b));
689 aacircleRGBA(gr->screen, p->x, p->y, r,
690 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
692 filledCircleRGBA(gr->screen, p->x, p->y, r,
693 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
701 draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
703 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
708 /* you might expect lines to be simpler than the other shapes.
709 but, that would be wrong. 1 line can generate 1 polygon + 2 circles
710 and even worse, we have to calculate their parameters!
711 go dust off your trigonometry hat.
714 int i, l, x_inc, y_inc, lw;
718 for(i = 0; i < count-1; i++)
721 printf("draw_lines: %p %d %d,%d->%d,%d %d\n", gc, i, p[i].x, p[i].y, p[i+1].x, p[i+1].y, gc->linewidth);
723 for(l = 0; l < lw; l++)
727 if(p[i].x != p[i+1].x)
736 if(p[i].y != p[i+1].y)
750 aalineRGBA(gr->screen, p[i].x + x_inc, p[i].y + y_inc, p[i+1].x + x_inc, p[i+1].y + y_inc,
751 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
753 lineRGBA(gr->screen, p[i].x + x_inc, p[i].y + y_inc, p[i+1].x + x_inc, p[i+1].y + y_inc,
754 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
759 /* sort of based on graphics_opengl.c::draw_lines */
760 /* FIXME: should honor ./configure flag for no fp.
761 this could be 100% integer code pretty easily,
762 except that i am lazy
764 struct point vert[4];
765 int lw = gc->linewidth;
769 for(i = 0; i < count-1; i++)
771 float dx=p[i+1].x-p[i].x;
772 float dy=p[i+1].y-p[i].y;
775 float cx=(p[i+1].x+p[i].x)/2;
776 float cy=(p[i+1].y+p[i].y)/2;
781 int x_lw_adj, y_lw_adj;
788 raster_aaline(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
789 SDL_MapRGBA(gr->screen->format,
797 raster_line(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
798 SDL_MapRGBA(gr->screen->format,
807 sge_LineAlpha(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
808 SDL_MapRGB(gr->screen->format,
809 gc->fore_r, gc->fore_g, gc->fore_b),
813 sge_AALine(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
814 SDL_MapRGB(gr->screen->format,
815 gc->fore_r, gc->fore_g, gc->fore_b));
817 sge_Line(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
818 SDL_MapRGB(gr->screen->format,
819 gc->fore_r, gc->fore_g, gc->fore_b));
824 aalineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
825 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
827 lineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
828 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
835 /* there is probably a much simpler way but this works ok */
837 /* FIXME: float + double mixture */
838 /* FIXME: lrint(round())? */
843 y_lw_adj = round((float)lw/2.0);
848 x_lw_adj = round((float)lw/2.0);
853 angle = (M_PI/2.0) - atan(abs(dx)/abs(dy));
854 x_lw_adj = round(sin(angle)*(float)lw/2.0);
855 y_lw_adj = round(cos(angle)*(float)lw/2.0);
856 if((x_lw_adj < 0) || (y_lw_adj < 0))
859 printf(" %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y);
860 printf(" lw=%d angle=%f\n", lw, 180.0 * angle / M_PI);
861 printf(" x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj);
865 if(p[i+1].x > p[i].x)
867 x_lw_adj = -x_lw_adj;
869 if(p[i+1].y > p[i].y)
871 y_lw_adj = -y_lw_adj;
875 if(((y_lw_adj*y_lw_adj)+(x_lw_adj*x_lw_adj)) != (lw/2)*(lw/2))
878 printf(" %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y);
879 printf(" lw=%d angle=%f\n", lw, 180.0 * angle / M_PI);
880 printf(" x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj);
884 /* FIXME: draw a circle/square if p[i]==p[i+1]? */
885 /* FIXME: clipping, check for neg values. hoping sdl-gfx does this */
886 vert[0].x = p[i].x + x_lw_adj;
887 vert[0].y = p[i].y - y_lw_adj;
888 vert[1].x = p[i].x - x_lw_adj;
889 vert[1].y = p[i].y + y_lw_adj;
890 vert[2].x = p[i+1].x - x_lw_adj;
891 vert[2].y = p[i+1].y + y_lw_adj;
892 vert[3].x = p[i+1].x + x_lw_adj;
893 vert[3].y = p[i+1].y - y_lw_adj;
895 draw_polygon(gr, gc, vert, 4);
897 /* draw small circles at the ends. this looks better than nothing, and slightly
898 * better than the triangle used by graphics_opengl, but is more expensive.
899 * should have an ifdef/xml attr?
902 /* FIXME: should just draw a half circle */
904 /* now some circular endcaps, if the width is over 2 */
909 draw_circle(gr, gc, &p[i], lw/2);
911 /* we truncate on the divide on purpose, so we don't go outside the line */
912 draw_circle(gr, gc, &p[i+1], lw/2);
921 set_pixel(SDL_Surface *surface, int x, int y, Uint8 r2, Uint8 g2, Uint8 b2, Uint8 a2)
923 if(x<0 || y<0 || x>=surface->w || y>=surface->h) {
927 void *target_pixel = ((Uint8*)surface->pixels + y * surface->pitch + x * surface->format->BytesPerPixel);
931 switch(surface->format->BytesPerPixel) {
934 SDL_GetRGBA(*(Uint16 *)target_pixel, surface->format, &r1, &g1, &b1, &a1);
935 *(Uint16 *)target_pixel = SDL_MapRGBA(surface->format,
936 (r1*(0xff-a2)/0xff) + (r2*a2/0xff),
937 (g1*(0xff-a2)/0xff) + (g2*a2/0xff),
938 (b1*(0xff-a2)/0xff) + (b2*a2/0xff),
939 a2 + a1*(0xff-a2)/0xff );
944 SDL_GetRGBA(*(Uint32 *)target_pixel, surface->format, &r1, &g1, &b1, &a1);
945 *(Uint32 *)target_pixel = SDL_MapRGBA(surface->format,
946 (r1*(0xff-a2)/0xff) + (r2*a2/0xff),
947 (g1*(0xff-a2)/0xff) + (g2*a2/0xff),
948 (b1*(0xff-a2)/0xff) + (b2*a2/0xff),
949 a2 + a1*(0xff-a2)/0xff );
957 resize_ft_buffer (unsigned int new_size)
959 if (new_size > ft_buffer_size) {
961 ft_buffer = g_malloc (new_size);
962 dbg(1, "old_size(%i) new_size(%i) ft_buffer(%i)\n", ft_buffer_size, new_size, ft_buffer);
963 ft_buffer_size = new_size;
968 display_text_draw(struct font_freetype_text *text,
969 struct graphics_priv *gr, struct graphics_gc_priv *fg,
970 struct graphics_gc_priv *bg, int color, struct point *p)
973 struct font_freetype_glyph *g, **gp;
974 struct color transparent = { 0x0000, 0x0000, 0x0000, 0x0000 };
976 { fg->fore_r * 255, fg->fore_g * 255, fg->fore_b * 255, fg->fore_a * 255
978 struct color white = { 0xffff, 0xffff, 0xffff, 0xffff };
981 if (COLOR_IS_WHITE(black) && COLOR_IS_BLACK(white)) {
991 } else if (COLOR_IS_BLACK(black) && COLOR_IS_WHITE(white)) {
1002 white.r = bg->fore_r * 255;
1003 white.g = bg->fore_g * 255;
1004 white.b = bg->fore_b * 255;
1005 white.a = bg->fore_a * 255;
1016 i = text->glyph_count;
1021 if (g->w && g->h && bg) {
1022 stride = (g->w + 2) * 4;
1024 resize_ft_buffer(stride * (g->h + 2));
1025 gr->freetype_methods.get_shadow(g, ft_buffer, 32, stride, &white, &transparent);
1027 SDL_Surface *glyph_surface =
1028 SDL_CreateRGBSurfaceFrom(ft_buffer, g->w + 2, g->h + 2,
1031 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
1032 if (glyph_surface) {
1034 r.x = (x + g->x) >> 6;
1035 r.y = (y + g->y) >> 6;
1039 SDL_BlitSurface(glyph_surface, NULL, gr->screen, &r);
1040 SDL_FreeSurface(glyph_surface);
1049 i = text->glyph_count;
1058 resize_ft_buffer(stride * g->h * 4);
1059 gr->freetype_methods.get_glyph(g, ft_buffer, 32,
1061 &white, &transparent);
1062 SDL_Surface *glyph_surface =
1063 SDL_CreateRGBSurfaceFrom(ft_buffer, g->w, g->h, 32,
1065 0x000000ff,0x0000ff00, 0x00ff0000,0xff000000);
1066 if (glyph_surface) {
1068 r.x = (x + g->x) >> 6;
1069 r.y = (y + g->y) >> 6;
1073 SDL_BlitSurface(glyph_surface, NULL, gr->screen,&r);
1074 SDL_FreeSurface(glyph_surface);
1078 resize_ft_buffer(stride * g->h);
1079 gr->freetype_methods.get_glyph(g, ft_buffer, 32, stride,
1083 unsigned char* pGlyph = ft_buffer;
1084 for (jj = 0; jj < g->h; ++jj) {
1085 for (ii = 0; ii < g->w; ++ii) {
1086 if(*(pGlyph+3) > 0) {
1087 set_pixel(gr->screen,
1088 ii+((x + g->x) >> 6),
1089 jj+((y + g->y) >> 6),
1090 *(pGlyph+2), // Pixels are in BGRA format
1107 draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1108 struct graphics_gc_priv *bg, struct graphics_font_priv *font,
1109 char *text, struct point *p, int dx, int dy)
1111 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable)
1112 || (gr->overlay_parent && gr->overlay_parent->overlay_enable
1113 && !gr->overlay_enable)) {
1117 struct font_freetype_text *t;
1121 dbg(0, "no font, returning\n");
1124 t = gr->freetype_methods.text_new(text,
1125 (struct font_freetype_font *) font,
1132 display_text_draw(t, gr, fg, bg, color, &p_eff);
1133 gr->freetype_methods.text_destroy(t);
1137 draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
1139 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
1152 SDL_BlitSurface(img->img, NULL, gr->screen, &r);
1157 draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
1163 draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
1166 printf("draw_restore\n");
1171 background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
1174 printf("background_gc\n");
1180 draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
1184 unsigned long elapsed;
1186 struct graphics_priv *ov;
1190 if(gr->overlay_mode)
1192 /* will be drawn below */
1197 printf("draw_mode: %d\n", mode);
1201 if(mode == draw_mode_begin)
1203 gettimeofday(&gr->draw_begin_tv, NULL);
1207 if(mode == draw_mode_end)
1209 if((gr->draw_mode == draw_mode_begin) && gr->overlay_enable)
1211 for(i = 0; i < OVERLAY_MAX; i++)
1213 ov = gr->overlay_array[i];
1214 if(ov && ov->overlay_enable)
1216 rect.x = ov->overlay_x;
1217 if(rect.x<0) rect.x += gr->screen->w;
1218 rect.y = ov->overlay_y;
1219 if(rect.y<0) rect.y += gr->screen->h;
1220 rect.w = ov->screen->w;
1221 rect.h = ov->screen->h;
1222 SDL_BlitSurface(ov->screen, NULL,
1228 SDL_Flip(gr->screen);
1231 gettimeofday(&now, NULL);
1232 elapsed = 1000000 * (now.tv_sec - gr->draw_begin_tv.tv_sec);
1233 elapsed += (now.tv_usec - gr->draw_begin_tv.tv_usec);
1234 if(elapsed >= gr->draw_time_peak)
1236 dbg(0, "draw elapsed %u usec\n", elapsed);
1237 gr->draw_time_peak = elapsed;
1242 gr->draw_mode = mode;
1246 static void overlay_disable(struct graphics_priv *gr, int disable)
1248 gr->overlay_enable = !disable;
1249 struct graphics_priv *curr_gr = gr;
1250 if(gr->overlay_parent) {
1251 curr_gr = gr->overlay_parent;
1253 draw_mode(curr_gr,draw_mode_end);
1256 static struct graphics_priv *
1257 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h, int alpha, int wraparound);
1259 static int window_fullscreen(struct window *win, int on)
1261 struct graphics_priv *gr=(struct graphics_priv *)win->priv;
1263 /* Update video flags */
1265 gr->video_flags |= SDL_FULLSCREEN;
1267 gr->video_flags &= ~SDL_FULLSCREEN;
1270 /* Update video mode */
1271 gr->screen = SDL_SetVideoMode(gr->screen->w, gr->screen->h, gr->video_bpp, gr->video_flags);
1272 if(gr->screen == NULL) {
1273 navit_destroy(gr->nav);
1276 callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
1282 get_data(struct graphics_priv *this, char const *type)
1284 if(strcmp(type, "window") == 0) {
1286 win=g_new(struct window, 1);
1288 win->fullscreen=window_fullscreen;
1289 win->disable_suspend=NULL;
1296 static void draw_drag(struct graphics_priv *gr, struct point *p)
1299 gr->overlay_x = p->x;
1300 gr->overlay_y = p->y;
1304 static struct graphics_methods graphics_methods = {
1310 NULL /*draw_circle*/,
1327 static struct graphics_priv *
1328 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h,int alpha, int wraparound)
1330 struct graphics_priv *ov;
1331 Uint32 rmask, gmask, bmask, amask;
1334 for(i = 0; i < OVERLAY_MAX; i++)
1336 if(gr->overlay_array[i] == NULL)
1341 if(i == OVERLAY_MAX)
1343 dbg(0, "too many overlays! increase OVERLAY_MAX\n");
1347 dbg(1, "overlay_new %d %d %d %u %u (%x, %x, %x ,%x, %d)\n", i,
1352 gr->screen->format->Rmask,
1353 gr->screen->format->Gmask,
1354 gr->screen->format->Bmask,
1355 gr->screen->format->Amask,
1356 gr->screen->format->BitsPerPixel
1359 ov = g_new0(struct graphics_priv, 1);
1361 switch(gr->screen->format->BitsPerPixel) {
1381 rmask = gr->screen->format->Rmask;
1382 gmask = gr->screen->format->Gmask;
1383 bmask = gr->screen->format->Bmask;
1384 amask = gr->screen->format->Amask;
1387 ov->screen = SDL_CreateRGBSurface(SDL_SWSURFACE,
1389 gr->screen->format->BitsPerPixel,
1390 rmask, gmask, bmask, amask);
1392 ov->overlay_mode = 1;
1393 ov->overlay_enable = 1;
1394 ov->overlay_x = p->x;
1395 ov->overlay_y = p->y;
1396 ov->overlay_parent = gr;
1397 ov->overlay_idx = i;
1398 gr->overlay_array[i] = ov;
1401 struct font_priv *(*font_freetype_new) (void *meth);
1402 font_freetype_new = plugin_get_font_type ("freetype");
1404 if (!font_freetype_new)
1410 font_freetype_new (&ov->freetype_methods);
1412 *meth=graphics_methods;
1415 (struct graphics_font_priv *
1416 (*)(struct graphics_priv *, struct graphics_font_methods *, char *, int,
1417 int)) ov->freetype_methods.font_new;
1418 meth->get_text_bbox = (void *)ov->freetype_methods.get_text_bbox;
1427 #ifdef LINUX_TOUCHSCREEN
1429 #define EVFN "/dev/input/eventX"
1431 static int input_ts_init(struct graphics_priv *gr)
1449 fn[sizeof(EVFN)-2] = '0' + n;
1451 fd = open(fn, O_RDONLY);
1455 ret = ioctl(fd, EVIOCGNAME(64), (void *)name);
1458 printf("input_ts: %s\n", name);
1462 ret = ioctl(fd, EVIOCGID, (void *)&ii);
1466 printf("bustype %04x vendor %04x product %04x version %04x\n",
1473 if((ii.bustype == BUS_USB) &&
1474 (ii.vendor == 0x0eef) &&
1475 (ii.product == 0x0001))
1477 ret = fcntl(fd, F_SETFL, O_NONBLOCK);
1496 /* FIXME: should check all 32 minors */
1509 /* returns 0-based display coordinate for the given ts coord */
1510 static void input_ts_map(int *disp_x, int *disp_y,
1511 uint32_t ts_x, uint32_t ts_y)
1513 /* Dynamix 7" (eGalax TS)
1516 bot left = 1986,1897
1519 calibrate your TS using input_event_dump
1520 and touching all four corners. use the most extreme values.
1523 #define INPUT_TS_LEFT 1978
1524 #define INPUT_TS_RIGHT 48
1525 #define INPUT_TS_TOP 115
1526 #define INPUT_TS_BOT 1870
1529 if(ts_x > INPUT_TS_LEFT)
1531 ts_x = INPUT_TS_LEFT;
1533 if(ts_x < INPUT_TS_RIGHT)
1535 ts_x = INPUT_TS_RIGHT;
1538 ts_x = ts_x - INPUT_TS_RIGHT;
1540 *disp_x = ((DISPLAY_W-1) * ts_x) / (INPUT_TS_LEFT - INPUT_TS_RIGHT);
1541 *disp_x = (DISPLAY_W-1) - *disp_x;
1544 if(ts_y > INPUT_TS_BOT)
1546 ts_y = INPUT_TS_BOT;
1548 if(ts_y < INPUT_TS_TOP)
1550 ts_y = INPUT_TS_TOP;
1553 ts_y = ts_y - INPUT_TS_TOP;
1555 *disp_y = ((DISPLAY_H-1) * ts_y) / (INPUT_TS_BOT - INPUT_TS_TOP);
1556 /* *disp_y = (DISPLAY_H-1) - *disp_y; */
1560 static void input_event_dump(struct input_event *ie)
1562 printf("input_event:\n"
1568 (unsigned int)ie->time.tv_sec,
1576 static int input_ts_exit(struct graphics_priv *gr)
1585 #ifdef USE_WEBOS_ACCELEROMETER
1587 sdl_accelerometer_handler(void* param)
1589 struct graphics_priv *gr = (struct graphics_priv *)param;
1590 int xAxis = SDL_JoystickGetAxis(gr->accelerometer, 0);
1591 int yAxis = SDL_JoystickGetAxis(gr->accelerometer, 1);
1592 int zAxis = SDL_JoystickGetAxis(gr->accelerometer, 2);
1593 unsigned char new_orientation;
1595 dbg(2,"x(%d) y(%d) z(%d) c(%d)\n",xAxis, yAxis, zAxis, sdl_orientation_count);
1597 if (zAxis > -30000) {
1598 if (xAxis < -15000 && yAxis > -5000 && yAxis < 5000)
1599 new_orientation = WEBOS_ORIENTATION_LANDSCAPE;
1600 else if (yAxis > 15000 && xAxis > -5000 && xAxis < 5000)
1601 new_orientation = WEBOS_ORIENTATION_PORTRAIT;
1608 if (new_orientation == sdl_next_orientation) {
1609 if (sdl_orientation_count < 3) sdl_orientation_count++;
1612 sdl_orientation_count = 0;
1613 sdl_next_orientation = new_orientation;
1618 if (sdl_orientation_count == 3)
1620 sdl_orientation_count++;
1622 if (new_orientation != gr->orientation) {
1623 dbg(1,"x(%d) y(%d) z(%d) o(%d)\n",xAxis, yAxis, zAxis, new_orientation);
1624 gr->orientation = new_orientation;
1627 SDL_UserEvent userevent;
1629 userevent.type = SDL_USEREVENT;
1630 userevent.code = SDL_USEREVENT_CODE_ROTATE;
1631 userevent.data1 = NULL;
1632 userevent.data2 = NULL;
1634 event.type = SDL_USEREVENT;
1635 event.user = userevent;
1637 SDL_PushEvent (&event);
1643 static gboolean graphics_sdl_idle(void *data)
1645 struct graphics_priv *gr = (struct graphics_priv *)data;
1648 #ifdef LINUX_TOUCHSCREEN
1649 struct input_event ie;
1658 if(the_graphics!=NULL) {
1662 dbg(0,"graphics_idle: graphics not set!\n");
1668 /* generate the initial resize callback, so the gui knows W/H
1670 its unsafe to do this directly inside register_resize_callback;
1671 graphics_gtk does it during Configure, but SDL does not have
1672 an equivalent event, so we use our own flag
1674 if(gr->resize_callback_initial != 0)
1676 callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
1677 gr->resize_callback_initial = 0;
1680 #ifdef LINUX_TOUCHSCREEN
1683 ss = read(gr->ts_fd, (void *)&ie, sizeof(ie));
1684 if(ss == sizeof(ie))
1686 /* we (usually) get three events on a touchscreen hit:
1688 code =330 [BTN_TOUCH]
1701 once hit, if the contact point changes, we'll get more
1702 EV_ABS (for 1 or both axes), followed by an EV_SYN.
1707 code =330 [BTN_TOUCH]
1716 if(ie.code == BTN_TOUCH)
1718 gr->ts_hit = ie.value;
1728 gr->ts_x = ie.value;
1730 else if(ie.code == 1)
1732 gr->ts_y = ie.value;
1740 input_ts_map(&p.x, &p.y, gr->ts_x, gr->ts_y);
1742 /* always send MOUSE_MOTION (first) */
1743 callback_list_call_attr_1(gr->cbl, attr_motion, (void *)&p);
1746 callback_list_call_attr_3(gr->cbl, attr_button, (void *)1, (void *)SDL_BUTTON_LEFT, (void *)&p);
1748 else if(gr->ts_hit == 0)
1750 callback_list_call_attr_3(gr->cbl, attr_button, (void *)0, (void *)SDL_BUTTON_LEFT, (void *)&p);
1768 #ifdef USE_WEBOS_ACCELEROMETER
1769 struct callback* accel_cb = NULL;
1770 struct event_timeout* accel_to = NULL;
1771 if (PDL_GetPDKVersion() > 100) {
1772 accel_cb = callback_new_1(callback_cast(sdl_accelerometer_handler), gr);
1773 accel_to = event_add_timeout(200, 1, accel_cb);
1777 unsigned int idle_tasks_idx=0;
1778 unsigned int idle_tasks_cur_priority=0;
1779 struct idle_task *task;
1781 while(!quit_event_loop)
1788 if(idle_tasks->len > 0)
1790 while (!(ret = SDL_PollEvent(&ev)) && idle_tasks->len > 0)
1792 if (idle_tasks_idx >= idle_tasks->len)
1795 dbg(3,"idle_tasks_idx(%d)\n",idle_tasks_idx);
1796 task = (struct idle_task *)g_ptr_array_index(idle_tasks,idle_tasks_idx);
1798 if (idle_tasks_idx == 0) // only execute tasks with lowest priority value
1799 idle_tasks_cur_priority = task->priority;
1800 if (task->priority > idle_tasks_cur_priority)
1804 callback_call_0(task->cb);
1809 if (!ret) // If we get here there are no idle_tasks and we have no events pending
1810 ret = SDL_WaitEvent(&ev);
1812 ret = SDL_PollEvent(&ev);
1820 dbg(1,"SDL_Event %d\n", ev.type);
1824 case SDL_MOUSEMOTION:
1828 callback_list_call_attr_1(gr->cbl, attr_motion, (void *)&p);
1835 switch(ev.key.keysym.sym)
1839 keybuf[0] = NAVIT_KEY_LEFT;
1844 keybuf[0] = NAVIT_KEY_RIGHT;
1847 case SDLK_BACKSPACE:
1849 keybuf[0] = NAVIT_KEY_BACKSPACE;
1854 keybuf[0] = NAVIT_KEY_RETURN;
1859 keybuf[0] = NAVIT_KEY_DOWN;
1864 keybuf[0] = NAVIT_KEY_ZOOM_OUT;
1869 keybuf[0] = NAVIT_KEY_UP;
1874 keybuf[0] = NAVIT_KEY_ZOOM_IN;
1878 case WEBOS_KEY_SHIFT:
1880 if ((key_mod & WEBOS_KEY_MOD_SHIFT_STICKY) == WEBOS_KEY_MOD_SHIFT_STICKY)
1881 key_mod &= ~(WEBOS_KEY_MOD_SHIFT_STICKY);
1882 else if ((key_mod & WEBOS_KEY_MOD_SHIFT) == WEBOS_KEY_MOD_SHIFT)
1883 key_mod |= WEBOS_KEY_MOD_SHIFT_STICKY;
1885 key_mod |= WEBOS_KEY_MOD_SHIFT;
1888 case WEBOS_KEY_ORANGE:
1890 if ((key_mod & WEBOS_KEY_MOD_ORANGE_STICKY) == WEBOS_KEY_MOD_ORANGE_STICKY)
1891 key_mod &= ~(WEBOS_KEY_MOD_ORANGE_STICKY);
1892 else if ((key_mod & WEBOS_KEY_MOD_ORANGE) == WEBOS_KEY_MOD_ORANGE)
1893 key_mod |= WEBOS_KEY_MOD_ORANGE_STICKY;
1895 key_mod |= WEBOS_KEY_MOD_ORANGE;
1900 /* Toggle the on-screen keyboard */
1901 //callback_list_call_attr_1(gr->cbl, attr_keyboard_toggle); // Not implemented yet
1904 case PDLK_GESTURE_BACK:
1906 keybuf[0] = NAVIT_KEY_BACK;
1909 case PDLK_GESTURE_FORWARD:
1910 case PDLK_GESTURE_AREA:
1918 if (ev.key.keysym.unicode < 0x80 && ev.key.keysym.unicode > 0) {
1919 keybuf[0] = (char)ev.key.keysym.unicode;
1920 if ((key_mod & WEBOS_KEY_MOD_ORANGE) == WEBOS_KEY_MOD_ORANGE) {
1922 case 'e': keybuf[0] = '1'; break;
1923 case 'r': keybuf[0] = '2'; break;
1924 case 't': keybuf[0] = '3'; break;
1925 case 'd': keybuf[0] = '4'; break;
1926 case 'f': keybuf[0] = '5'; break;
1927 case 'g': keybuf[0] = '6'; break;
1928 case 'x': keybuf[0] = '7'; break;
1929 case 'c': keybuf[0] = '8'; break;
1930 case 'v': keybuf[0] = '9'; break;
1931 case '@': keybuf[0] = '0'; break;
1932 case ',': keybuf[0] = '-'; break;
1933 case 'u': strncpy(keybuf, "ü", sizeof(keybuf)); break;
1934 case 'a': strncpy(keybuf, "ä", sizeof(keybuf)); break;
1935 case 'o': strncpy(keybuf, "ö", sizeof(keybuf)); break;
1936 case 's': strncpy(keybuf, "ß", sizeof(keybuf)); break;
1939 /*if ((key_mod & WEBOS_KEY_MOD_SHIFT) == WEBOS_KEY_MOD_SHIFT)
1941 if ((key_mod & WEBOS_KEY_MOD_SHIFT_STICKY) != WEBOS_KEY_MOD_SHIFT_STICKY)
1942 key_mod &= ~(WEBOS_KEY_MOD_SHIFT_STICKY);
1943 if ((key_mod & WEBOS_KEY_MOD_ORANGE_STICKY) != WEBOS_KEY_MOD_ORANGE_STICKY)
1944 key_mod &= ~(WEBOS_KEY_MOD_ORANGE_STICKY);
1947 dbg(0,"Unknown key sym: %x\n", ev.key.keysym.sym);
1950 /* return unicode chars when they can be converted to ascii */
1951 keybuf[0] = ev.key.keysym.unicode<=127 ? ev.key.keysym.unicode : 0;
1957 dbg(2,"key mod: 0x%x\n", key_mod);
1960 dbg(2,"key: %s 0x%x\n", keybuf, keybuf);
1961 callback_list_call_attr_1(gr->cbl, attr_keypress, (void *)keybuf);
1971 case SDL_MOUSEBUTTONDOWN:
1974 printf("SDL_MOUSEBUTTONDOWN %d %d %d %d %d\n",
1984 callback_list_call_attr_3(gr->cbl, attr_button, (void *)1, (void *)(int)ev.button.button, (void *)&p);
1988 case SDL_MOUSEBUTTONUP:
1991 printf("SDL_MOUSEBUTTONUP %d %d %d %d %d\n",
2001 callback_list_call_attr_3(gr->cbl, attr_button, (void *)0, (void *)(int)ev.button.button, (void *)&p);
2008 quit_event_loop = 1;
2009 navit_destroy(gr->nav);
2014 case SDL_VIDEORESIZE:
2017 gr->screen = SDL_SetVideoMode(ev.resize.w, ev.resize.h, gr->video_bpp, gr->video_flags);
2018 if(gr->screen == NULL)
2020 navit_destroy(gr->nav);
2024 callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
2033 SDL_UserEvent userevent = ev.user;
2034 dbg(9,"received SDL_USEREVENT type(%x) code(%x)\n",userevent.type,userevent.code);
2035 if (userevent.type != SDL_USEREVENT)
2038 if (userevent.code == PDL_GPS_UPDATE)
2040 struct attr vehicle_attr;
2042 navit_get_attr(gr->nav, attr_vehicle, &vehicle_attr, NULL);
2043 v = vehicle_attr.u.vehicle;
2046 attr.type = attr_pdl_gps_update;
2047 attr.u.data = userevent.data1;
2048 vehicle_set_attr(v, &attr);
2051 else if(userevent.code == SDL_USEREVENT_CODE_TIMER)
2053 struct callback *cb = (struct callback *)userevent.data1;
2054 dbg(1, "SDL_USEREVENT timer received cb(%p)\n", cb);
2055 callback_call_0(cb);
2057 else if(userevent.code == SDL_USEREVENT_CODE_WATCH)
2059 struct callback *cb = (struct callback *)userevent.data1;
2060 dbg(1, "SDL_USEREVENT watch received cb(%p)\n", cb);
2061 callback_call_0(cb);
2063 else if(userevent.code == SDL_USEREVENT_CODE_CALL_CALLBACK)
2065 struct callback_list *cbl = (struct callback_list *)userevent.data1;
2066 dbg(1, "SDL_USEREVENT call_callback received cbl(%p)\n", cbl);
2067 callback_list_call_0(cbl);
2069 else if(userevent.code == SDL_USEREVENT_CODE_IDLE_EVENT) {
2070 dbg(1, "SDL_USEREVENT idle_event received\n");
2072 #ifdef USE_WEBOS_ACCELEROMETER
2073 else if(userevent.code == SDL_USEREVENT_CODE_ROTATE)
2075 dbg(1, "SDL_USEREVENT rotate received\n");
2076 switch(gr->orientation)
2078 case WEBOS_ORIENTATION_PORTRAIT:
2079 gr->screen = SDL_SetVideoMode(gr->real_w, gr->real_h, gr->video_bpp, gr->video_flags);
2080 PDL_SetOrientation(PDL_ORIENTATION_0);
2082 case WEBOS_ORIENTATION_LANDSCAPE:
2083 gr->screen = SDL_SetVideoMode(gr->real_h, gr->real_w, gr->video_bpp, gr->video_flags);
2084 PDL_SetOrientation(PDL_ORIENTATION_270);
2087 if(gr->screen == NULL)
2089 navit_destroy(gr->nav);
2093 callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
2098 dbg(1, "unknown SDL_USEREVENT\n");
2106 printf("SDL_Event %d\n", ev.type);
2114 event_sdl_watch_stopthread();
2117 #ifdef USE_WEBOS_ACCELEROMETER
2118 if (PDL_GetPDKVersion() > 100) {
2119 event_remove_timeout(accel_to);
2120 callback_destroy(accel_cb);
2128 static struct graphics_priv *
2129 graphics_sdl_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
2131 struct graphics_priv *this=g_new0(struct graphics_priv, 1);
2134 int w=DISPLAY_W,h=DISPLAY_H;
2136 struct font_priv *(*font_freetype_new) (void *meth);
2137 font_freetype_new = plugin_get_font_type ("freetype");
2139 if (!font_freetype_new)
2144 font_freetype_new (&this->freetype_methods);
2149 dbg(1,"Calling SDL_Init\n");
2151 # ifdef USE_WEBOS_ACCELEROMETER
2152 ret = SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_JOYSTICK);
2154 ret = SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER);
2157 ret = SDL_Init(SDL_INIT_VIDEO);
2161 dbg(0,"SDL_Init failed %d\n", ret);
2167 dbg(1,"Calling PDL_Init(0)\n");
2171 dbg(0,"PDL_Init failed %d\n", ret);
2176 if (! event_request_system("sdl","graphics_sdl_new")) {
2178 if (! event_request_system("glib","graphics_sdl_new")) {
2180 dbg(0,"event_request_system failed");
2185 this->video_bpp = 0;
2186 this->video_flags = SDL_SWSURFACE | SDL_ANYFORMAT | SDL_RESIZABLE;
2188 this->video_bpp = 16;
2189 this->video_flags = SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE;
2192 if ((attr=attr_search(attrs, NULL, attr_w)))
2194 if ((attr=attr_search(attrs, NULL, attr_h)))
2196 if ((attr=attr_search(attrs, NULL, attr_bpp)))
2197 this->video_bpp=attr->u.num;
2198 if ((attr=attr_search(attrs, NULL, attr_flags))) {
2199 if (attr->u.num & 1)
2200 this->video_flags = SDL_SWSURFACE;
2202 if ((attr=attr_search(attrs, NULL, attr_frame))) {
2204 this->video_flags |= SDL_NOFRAME;
2207 this->screen = SDL_SetVideoMode(w, h, this->video_bpp, this->video_flags);
2209 if(this->screen == NULL)
2211 dbg(0,"SDL_SetVideoMode failed\n");
2220 /* Use screen size instead of requested */
2221 w = this->screen->w;
2222 h = this->screen->h;
2224 dbg(0, "using screen %ix%i@%i\n",
2225 this->screen->w, this->screen->h,
2226 this->screen->format->BytesPerPixel * 8);
2227 #ifdef USE_WEBOS_ACCELEROMETER
2230 this->accelerometer = SDL_JoystickOpen(0);
2233 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
2235 PDL_SetOrientation(PDL_ORIENTATION_0);
2238 SDL_EnableUNICODE(1);
2239 SDL_WM_SetCaption("navit", NULL);
2241 #ifdef LINUX_TOUCHSCREEN
2242 input_ts_init(this);
2243 if(this->ts_fd >= 0)
2245 /* mouse cursor does not always display correctly in Linux FB.
2246 anyway, it is unnecessary w/ a touch screen
2257 *meth=graphics_methods;
2261 (struct graphics_font_priv *
2262 (*)(struct graphics_priv *, struct graphics_font_methods *, char *, int,
2263 int)) this->freetype_methods.font_new;
2264 meth->get_text_bbox = (void*) this->freetype_methods.get_text_bbox;
2269 if(the_graphics!=NULL) {
2270 dbg(0,"graphics_sdl_new: graphics struct already set: %d!\n", the_graphics_count);
2272 the_graphics = this;
2273 the_graphics_count++;
2275 g_timeout_add(G_PRIORITY_DEFAULT+10, graphics_sdl_idle, this);
2278 this->overlay_enable = 1;
2281 if((attr=attr_search(attrs, NULL, attr_antialias)))
2282 this->aa = attr->u.num;
2284 this->resize_callback_initial=1;
2289 /* ---------- SDL Eventhandling ---------- */
2292 sdl_timer_callback(Uint32 interval, void* param)
2294 struct event_timeout *timeout=(struct event_timeout*)param;
2296 dbg(1,"timer(%p) multi(%d) interval(%d) fired\n", param, timeout->multi, interval);
2299 SDL_UserEvent userevent;
2301 userevent.type = SDL_USEREVENT;
2302 userevent.code = SDL_USEREVENT_CODE_TIMER;
2303 userevent.data1 = timeout->cb;
2304 userevent.data2 = NULL;
2306 event.type = SDL_USEREVENT;
2307 event.user = userevent;
2309 SDL_PushEvent (&event);
2311 if (timeout->multi==0) {
2314 return 0; // cancel timer
2316 return interval; // reactivate timer
2322 event_sdl_main_loop_run(void)
2324 PDL_ScreenTimeoutEnable(PDL_FALSE);
2325 graphics_sdl_idle(NULL);
2326 PDL_ScreenTimeoutEnable(PDL_TRUE);
2330 event_sdl_main_loop_quit(void)
2332 quit_event_loop = 1;
2338 event_sdl_watch_thread (GPtrArray *watch_list)
2340 struct pollfd *pfds = g_new0 (struct pollfd, watch_list->len);
2341 struct event_watch *ew;
2345 for (idx = 0; idx < watch_list->len; idx++ ) {
2346 ew = g_ptr_array_index (watch_list, idx);
2347 g_memmove (&pfds[idx], ew->pfd, sizeof(struct pollfd));
2350 while ((ret = ppoll(pfds, watch_list->len, NULL, NULL)) > 0) {
2351 for (idx = 0; idx < watch_list->len; idx++ ) {
2352 if (pfds[idx].revents == pfds[idx].events) { /* The requested event happened, notify mainloop! */
2353 ew = g_ptr_array_index (watch_list, idx);
2354 dbg(1,"watch(%p) event(%d) encountered\n", ew, pfds[idx].revents);
2357 SDL_UserEvent userevent;
2359 userevent.type = SDL_USEREVENT;
2360 userevent.code = SDL_USEREVENT_CODE_WATCH;
2361 userevent.data1 = ew->cb;
2362 userevent.data2 = NULL;
2364 event.type = SDL_USEREVENT;
2365 event.user = userevent;
2367 SDL_PushEvent (&event);
2378 event_sdl_watch_startthread(GPtrArray *watch_list)
2381 if (sdl_watch_thread)
2382 event_sdl_watch_stopthread();
2385 ret = pthread_create (&sdl_watch_thread, NULL, (void *)event_sdl_watch_thread, (void *)watch_list);
2387 dbg_assert (ret == 0);
2391 event_sdl_watch_stopthread()
2394 if (sdl_watch_thread) {
2395 /* Notify the watch thread that the list of FDs will change */
2396 pthread_kill(sdl_watch_thread, SIGUSR1);
2397 pthread_join(sdl_watch_thread, NULL);
2398 sdl_watch_thread = 0;
2402 static struct event_watch *
2403 event_sdl_add_watch(void *fd, enum event_watch_cond cond, struct callback *cb)
2405 dbg(1,"fd(%d) cond(%x) cb(%x)\n", fd, cond, cb);
2407 event_sdl_watch_stopthread();
2409 if (!sdl_watch_list)
2410 sdl_watch_list = g_ptr_array_new();
2412 struct event_watch *new_ew = g_new0 (struct event_watch, 1);
2413 struct pollfd *pfd = g_new0 (struct pollfd, 1);
2417 /* Modify watchlist here */
2419 case event_watch_cond_read:
2420 pfd->events = POLLIN;
2422 case event_watch_cond_write:
2423 pfd->events = POLLOUT;
2425 case event_watch_cond_except:
2426 pfd->events = POLLERR|POLLHUP;
2430 new_ew->pfd = (struct pollfd*) pfd;
2433 g_ptr_array_add (sdl_watch_list, (gpointer)new_ew);
2435 event_sdl_watch_startthread(sdl_watch_list);
2441 event_sdl_remove_watch(struct event_watch *ew)
2443 dbg(1,"enter %p\n",ew);
2445 event_sdl_watch_stopthread();
2447 g_ptr_array_remove (sdl_watch_list, ew);
2451 if (sdl_watch_list->len > 0)
2452 event_sdl_watch_startthread(sdl_watch_list);
2457 static struct event_timeout *
2458 event_sdl_add_timeout(int timeout, int multi, struct callback *cb)
2460 struct event_timeout * ret = g_new0(struct event_timeout, 1);
2463 dbg(1,"timer(%p) multi(%d) interval(%d) cb(%p) added\n",ret, multi, timeout, cb);
2466 ret->id = SDL_AddTimer(timeout, sdl_timer_callback, ret);
2472 event_sdl_remove_timeout(struct event_timeout *to)
2474 dbg(2,"enter %p\n", to);
2477 int ret = to->id ? SDL_RemoveTimer(to->id) : SDL_TRUE;
2478 if (ret == SDL_FALSE) {
2479 dbg(0,"SDL_RemoveTimer (%p) failed\n", to->id);
2483 dbg(1,"timer(%p) removed\n", to);
2490 /* sort ptr_array by priority, increasing order */
2492 sdl_sort_idle_tasks(gconstpointer parama, gconstpointer paramb)
2494 struct idle_task *a = (struct idle_task *)parama;
2495 struct idle_task *b = (struct idle_task *)paramb;
2496 if (a->priority < b->priority)
2498 if (a->priority > b->priority)
2503 static struct event_idle *
2504 event_sdl_add_idle(int priority, struct callback *cb)
2506 dbg(1,"add idle priority(%d) cb(%p)\n", priority, cb);
2508 struct idle_task *task = g_new0(struct idle_task, 1);
2509 task->priority = priority;
2512 g_ptr_array_add(idle_tasks, (gpointer)task);
2514 if (idle_tasks->len < 2)
2517 SDL_UserEvent userevent;
2519 dbg(1,"poking eventloop because of new idle_events\n");
2521 userevent.type = SDL_USEREVENT;
2522 userevent.code = SDL_USEREVENT_CODE_IDLE_EVENT;
2523 userevent.data1 = NULL;
2524 userevent.data2 = NULL;
2526 event.type = SDL_USEREVENT;
2527 event.user = userevent;
2529 SDL_PushEvent (&event);
2531 else // more than one entry => sort the list
2532 g_ptr_array_sort(idle_tasks, sdl_sort_idle_tasks);
2534 return (struct event_idle *)task;
2538 event_sdl_remove_idle(struct event_idle *task)
2540 dbg(1,"remove task(%p)\n", task);
2541 g_ptr_array_remove(idle_tasks, (gpointer)task);
2547 event_sdl_call_callback(struct callback_list *cbl)
2549 dbg(1,"call_callback cbl(%p)\n",cbl);
2551 SDL_UserEvent userevent;
2553 userevent.type = SDL_USEREVENT;
2554 userevent.code = SDL_USEREVENT_CODE_CALL_CALLBACK;
2555 userevent.data1 = cbl;
2556 userevent.data2 = NULL;
2558 event.type = SDL_USEREVENT;
2559 event.user = userevent;
2561 SDL_PushEvent (&event);
2564 static struct event_methods event_sdl_methods = {
2565 event_sdl_main_loop_run,
2566 event_sdl_main_loop_quit,
2567 event_sdl_add_watch,
2568 event_sdl_remove_watch,
2569 event_sdl_add_timeout,
2570 event_sdl_remove_timeout,
2572 event_sdl_remove_idle,
2573 event_sdl_call_callback,
2576 static struct event_priv *
2577 event_sdl_new(struct event_methods* methods)
2579 idle_tasks = g_ptr_array_new();
2580 *methods = event_sdl_methods;
2584 /* ---------- SDL Eventhandling ---------- */
2591 plugin_register_event_type("sdl", event_sdl_new);
2593 plugin_register_graphics_type("sdl", graphics_sdl_new);