Fix:SDL:Removed useless references to fontconfig.
[profile/ivi/navit.git] / navit / navit / graphics / sdl / graphics_sdl.c
1 /* graphics_sdl.c -- barebones sdl graphics layer
2
3    copyright (c) 2008 bryan rittmeyer <bryanr@bryanr.org>
4    license: GPLv2
5
6    TODO:
7    - dashed lines
8    - ifdef DEBUG -> dbg()
9    - proper image transparency (libsdl-image xpm does not work)
10    - valgrind
11
12    revision history:
13    2008-06-01 initial
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
18 */
19
20 #include <glib.h>
21 #include <pthread.h>
22 #include <poll.h>
23 #include <signal.h>
24 #include "config.h"
25 #include "debug.h"
26 #include "point.h"
27 #include "graphics.h"
28 #include "color.h"
29 #include "plugin.h"
30 #include "window.h"
31 #include "navit.h"
32 #include "keys.h"
33 #include "item.h"
34 #include "attr.h"
35 #include "callback.h"
36 #include "font/freetype/font_freetype.h"
37
38 #include <SDL/SDL.h>
39 #include <math.h>
40
41 #ifdef USE_WEBOS
42 # include "vehicle.h"
43 # include <PDL.h>
44 //# define USE_WEBOS_ACCELEROMETER
45 #endif
46
47 #define RASTER
48 #undef SDL_SGE
49 #undef SDL_GFX
50 #undef ALPHA
51
52 #undef SDL_TTF
53 #define SDL_IMAGE
54 #undef LINUX_TOUCHSCREEN
55
56 #ifdef USE_WEBOS
57 #define DISPLAY_W 0
58 #define DISPLAY_H 0
59 #else
60 #define DISPLAY_W 800
61 #define DISPLAY_H 600
62 #endif
63
64
65 #undef DEBUG
66 #undef PROFILE
67
68 #define OVERLAY_MAX 32
69
70 #ifdef RASTER
71 #include "raster.h"
72 #endif
73
74 #ifdef SDL_SGE
75 #include <SDL/sge.h>
76 #endif
77
78 #ifdef SDL_GFX
79 #include <SDL/SDL_gfxPrimitives.h>
80 #endif
81
82 #ifdef SDL_TTF
83 #include <SDL/SDL_ttf.h>
84 #else
85 #include <ft2build.h>
86 #include FT_FREETYPE_H
87 #include <freetype/ftglyph.h>
88 #endif
89 #include <event.h>
90
91 #ifdef SDL_IMAGE
92 #include <SDL/SDL_image.h>
93 #endif
94
95 #ifdef LINUX_TOUCHSCREEN
96 /* we use Linux evdev directly for the touchscreen.  */
97 #include <sys/types.h>
98 #include <sys/stat.h>
99 #include <fcntl.h>
100 #include <linux/input.h>
101 #endif
102
103 #include <alloca.h>
104
105 #ifdef PROFILE
106 #include <sys/time.h>
107 #include <time.h>
108 #endif
109
110
111 /* TODO: union overlay + non-overlay to reduce size */
112 struct graphics_priv;
113 struct graphics_priv {
114     SDL_Surface *screen;
115     int aa;
116     /* video modes */
117     uint32_t video_flags;
118     int video_bpp;
119
120     /* <overlay> */
121     int overlay_mode;
122     int overlay_x;
123     int overlay_y;
124     struct graphics_priv *overlay_parent;
125     int overlay_idx;
126     /* </overlay> */
127
128     /* <main> */
129     struct graphics_priv *overlay_array[OVERLAY_MAX];
130     int overlay_enable;
131     enum draw_mode_num draw_mode;
132
133         int resize_callback_initial;
134
135     struct navit *nav;
136     struct callback_list *cbl;
137
138 #ifdef USE_WEBOS_ACCELEROMETER
139     SDL_Joystick *accelerometer;
140     char orientation;
141     int real_w, real_h;
142 #endif
143
144 #ifdef LINUX_TOUCHSCREEN
145     int ts_fd;
146     int32_t ts_hit;
147     uint32_t ts_x;
148     uint32_t ts_y;
149 #endif
150
151 #ifndef SDL_TTF
152     FT_Library library;
153 #endif
154
155 #ifdef PROFILE
156     struct timeval draw_begin_tv;
157     unsigned long draw_time_peak;
158 #endif
159   struct font_freetype_methods freetype_methods;
160     /* </main> */
161 };
162
163 static int dummy;
164
165 #ifdef USE_WEBOS
166 #define WEBOS_KEY_SHIFT 0x130
167 #define WEBOS_KEY_SYM 0x131
168 #define WEBOS_KEY_ORANGE 0x133
169
170 #define WEBOS_KEY_MOD_SHIFT 0x1
171 #define WEBOS_KEY_MOD_ORANGE 0x2
172 #define WEBOS_KEY_MOD_SYM 0x4
173
174 #define WEBOS_KEY_MOD_SHIFT_STICKY 0x11
175 #define WEBOS_KEY_MOD_ORANGE_STICKY 0x22
176 #define WEBOS_KEY_MOD_SYM_STICKY 0x44
177
178 #ifdef USE_WEBOS_ACCELEROMETER
179 # define WEBOS_ORIENTATION_PORTRAIT 0x0
180 # define WEBOS_ORIENTATION_LANDSCAPE 0x1
181 #endif
182
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
189 #endif
190
191 struct event_timeout {
192     SDL_TimerID id;
193     int multi;
194     struct callback *cb;
195 };
196
197 struct idle_task {
198     int priority;
199     struct callback *cb;
200 };
201
202 struct event_watch {
203     struct pollfd *pfd;
204     struct callback *cb;
205 };
206
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;
213
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 #endif
225 static unsigned char * ft_buffer = NULL;
226 static unsigned int    ft_buffer_size = 0;
227
228 struct graphics_font_priv {
229 #ifdef SDL_TTF
230     TTF_Font *font;
231 #else
232     FT_Face face;
233 #endif
234 };
235
236 struct graphics_gc_priv {
237     struct graphics_priv *gr;
238     Uint8 fore_r;
239     Uint8 fore_g;
240     Uint8 fore_b;
241     Uint8 fore_a;
242     Uint8 back_r;
243     Uint8 back_g;
244     Uint8 back_b;
245     Uint8 back_a;
246     int linewidth;
247 };
248
249 struct graphics_image_priv {
250     SDL_Surface *img;
251 };
252
253
254 #ifdef LINUX_TOUCHSCREEN
255 static int input_ts_exit(struct graphics_priv *gr);
256 #endif
257
258 static void
259 graphics_destroy(struct graphics_priv *gr)
260 {
261     dbg(0, "graphics_destroy %p %u\n", gr, gr->overlay_mode);
262
263     g_free (ft_buffer);
264
265     if(gr->overlay_mode)
266     {
267         SDL_FreeSurface(gr->screen);
268         gr->overlay_parent->overlay_array[gr->overlay_idx] = NULL;
269     }
270     else
271     {
272 #ifdef SDL_TTF
273         TTF_Quit();
274 #else
275         FT_Done_FreeType(gr->library);
276 #endif
277 #ifdef LINUX_TOUCHSCREEN
278         input_ts_exit(gr);
279 #endif
280 #ifdef USE_WEBOS_ACCELEROMETER
281         SDL_JoystickClose(gr->accelerometer);
282 #endif
283 #ifdef USE_WEBOS
284         PDL_Quit();
285 #endif
286         SDL_Quit();
287     }
288
289     g_free(gr);
290 }
291
292 /* graphics_gc */
293
294 static void
295 gc_destroy(struct graphics_gc_priv *gc)
296 {
297     g_free(gc);
298 }
299
300 static void
301 gc_set_linewidth(struct graphics_gc_priv *gc, int w)
302 {
303 #ifdef DEBUG
304     printf("gc_set_linewidth %p %d\n", gc, w);
305 #endif
306     gc->linewidth = w;
307 }
308
309 static void
310 gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
311 {
312     /* TODO */
313 }
314
315 static void
316 gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
317 {
318 #ifdef DEBUG
319     printf("gc_set_foreground: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
320 #endif
321     gc->fore_r = c->r/256;
322     gc->fore_g = c->g/256;
323     gc->fore_b = c->b/256;
324     gc->fore_a = c->a/256;
325 }
326
327 static void
328 gc_set_background(struct graphics_gc_priv *gc, struct color *c)
329 {
330 #ifdef DEBUG
331     printf("gc_set_background: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
332 #endif
333     gc->back_r = c->r/256;
334     gc->back_g = c->g/256;
335     gc->back_b = c->b/256;
336     gc->back_a = c->a/256;
337 }
338
339 static struct graphics_gc_methods gc_methods = {
340         gc_destroy,
341         gc_set_linewidth,
342         gc_set_dashes,
343         gc_set_foreground,
344         gc_set_background
345 };
346
347 static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
348 {
349     struct graphics_gc_priv *gc=g_new0(struct graphics_gc_priv, 1);
350         *meth=gc_methods;
351     gc->gr=gr;
352     gc->linewidth=1; /* upper layer should override anyway? */
353         return gc;
354 }
355
356
357 #if 0 /* unused by core? */
358 static void image_destroy(struct graphics_image_priv *gi)
359 {
360 #ifdef SDL_IMAGE
361     SDL_FreeSurface(gi->img);
362     g_free(gi);
363 #endif
364 }
365
366 static struct graphics_image_methods gi_methods =
367 {
368     image_destroy
369 };
370 #endif
371
372 static struct graphics_image_priv *
373 image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name, int *w, int *h,
374           struct point *hot, int rotation)
375 {
376 #ifdef SDL_IMAGE
377     struct graphics_image_priv *gi;
378
379     /* FIXME: meth is not used yet.. so gi leaks. at least xpm is small */
380
381     gi = g_new0(struct graphics_image_priv, 1);
382     gi->img = IMG_Load(name);
383     if(gi->img)
384     {
385         /* TBD: improves blit performance? */
386 #if !SDL_VERSION_ATLEAST(1,3,0)
387         SDL_SetColorKey(gi->img, SDL_RLEACCEL, gi->img->format->colorkey);
388 #endif
389         *w=gi->img->w;
390         *h=gi->img->h;
391         hot->x=*w/2;
392         hot->y=*h/2;
393     }
394     else
395     {
396         /* TODO: debug "colour parse errors" on xpm */
397         printf("graphics_sdl: image_new on '%s' failed: %s\n", name, IMG_GetError());
398         g_free(gi);
399         gi = NULL;
400     }
401
402     return gi;
403 #else
404     return NULL;
405 #endif
406 }
407
408 static void
409 image_free(struct graphics_priv *gr, struct graphics_image_priv * gi)
410 {
411 #ifdef SDL_IMAGE
412     SDL_FreeSurface(gi->img);
413     g_free(gi);
414 #endif
415 }
416
417 static void
418 get_text_bbox(struct graphics_priv *gr, struct graphics_font_priv *font, char *text, int dx, int dy, struct point *ret, int estimate)
419 {
420         char *p=text;
421         FT_BBox bbox;
422         FT_UInt  glyph_index;
423         FT_GlyphSlot  slot = font->face->glyph;  // a small shortcut
424         FT_Glyph glyph;
425         FT_Matrix matrix;
426         FT_Vector pen;
427         pen.x = 0 * 64;
428         pen.y = 0 * 64;
429         matrix.xx = dx;
430         matrix.xy = dy;
431         matrix.yx = -dy;
432         matrix.yy = dx;
433         int n,len,x=0,y=0;
434
435         bbox.xMin = bbox.yMin = 32000;
436         bbox.xMax = bbox.yMax = -32000;
437         FT_Set_Transform( font->face, &matrix, &pen );
438         len=g_utf8_strlen(text, -1);
439         for ( n = 0; n < len; n++ ) {
440                 FT_BBox glyph_bbox;
441                 glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p));
442                 p=g_utf8_next_char(p);
443                 FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT );
444                 FT_Get_Glyph(font->face->glyph, &glyph);
445                 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox );
446                 FT_Done_Glyph(glyph);
447                 glyph_bbox.xMin += x >> 6;
448                 glyph_bbox.xMax += x >> 6;
449                 glyph_bbox.yMin += y >> 6;
450                 glyph_bbox.yMax += y >> 6;
451                 x += slot->advance.x;
452                 y -= slot->advance.y;
453                 if ( glyph_bbox.xMin < bbox.xMin )
454                         bbox.xMin = glyph_bbox.xMin;
455                 if ( glyph_bbox.yMin < bbox.yMin )
456                         bbox.yMin = glyph_bbox.yMin;
457                 if ( glyph_bbox.xMax > bbox.xMax )
458                         bbox.xMax = glyph_bbox.xMax;
459                 if ( glyph_bbox.yMax > bbox.yMax )
460                         bbox.yMax = glyph_bbox.yMax;
461         }
462         if ( bbox.xMin > bbox.xMax ) {
463                 bbox.xMin = 0;
464                 bbox.yMin = 0;
465                 bbox.xMax = 0;
466                 bbox.yMax = 0;
467         }
468         ret[0].x=bbox.xMin;
469         ret[0].y=-bbox.yMin;
470         ret[1].x=bbox.xMin;
471         ret[1].y=-bbox.yMax;
472         ret[2].x=bbox.xMax;
473         ret[2].y=-bbox.yMax;
474         ret[3].x=bbox.xMax;
475         ret[3].y=-bbox.yMin;
476 }
477
478 static void
479 draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
480 {
481   if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
482     {
483       return;
484     }
485
486     Sint16 *vx, *vy;
487     Sint16 x, y;
488     int i;
489
490     vx = alloca(count * sizeof(Sint16));
491     vy = alloca(count * sizeof(Sint16));
492
493     for(i = 0; i < count; i++)
494     {
495         x = (Sint16)p[i].x;
496         y = (Sint16)p[i].y;
497
498 #if 0
499         if(x < 0)
500         {
501             x = 0;
502         }
503         if(y < 0)
504         {
505             y = 0;
506         }
507 #endif
508
509         vx[i] = x;
510         vy[i] = y;
511
512 #ifdef DEBUG
513         printf("draw_polygon: %p %i %d,%d\n", gc, i, p[i].x, p[i].y);
514 #endif
515     }
516
517 #ifdef RASTER
518     if(gr->aa)
519     {
520         raster_aapolygon(gr->screen, count, vx, vy,
521                        SDL_MapRGBA(gr->screen->format,
522                                   gc->fore_r,
523                                   gc->fore_g,
524                                   gc->fore_b,
525                                   gc->fore_a));
526     }
527     else
528     {
529         raster_polygon(gr->screen, count, vx, vy,
530                        SDL_MapRGBA(gr->screen->format,
531                                   gc->fore_r,
532                                   gc->fore_g,
533                                   gc->fore_b,
534                                   gc->fore_a));
535     }
536 #else
537 #ifdef SDL_SGE
538 #ifdef ALPHA
539     sge_FilledPolygonAlpha(gr->screen, count, vx, vy,
540                            SDL_MapRGB(gr->screen->format,
541                                       gc->fore_r,
542                                       gc->fore_g,
543                                       gc->fore_b),
544                            gc->fore_a);
545 #else
546 #ifdef ANTI_ALIAS
547     sge_AAFilledPolygon(gr->screen, count, vx, vy,
548                            SDL_MapRGB(gr->screen->format,
549                                       gc->fore_r,
550                                       gc->fore_g,
551                                       gc->fore_b));
552 #else
553     sge_FilledPolygon(gr->screen, count, vx, vy,
554                            SDL_MapRGB(gr->screen->format,
555                                       gc->fore_r,
556                                       gc->fore_g,
557                                       gc->fore_b));
558 #endif
559 #endif
560 #else
561     filledPolygonRGBA(gr->screen, vx, vy, count,
562                       gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
563 #endif
564 #endif
565 }
566
567
568
569 static void
570 draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
571 {
572   if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
573     {
574       return;
575     }
576
577 #ifdef DEBUG
578         printf("draw_rectangle: %d %d %d %d r=%d g=%d b=%d a=%d\n", p->x, p->y, w, h,
579                gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
580 #endif
581     if(w > gr->screen->w)
582     {
583         w = gr->screen->w;
584     }
585     if(h > gr->screen->h)
586     {
587         h = gr->screen->h;
588     }
589
590 #ifdef RASTER
591     raster_rect(gr->screen, p->x, p->y, w, h,
592                 SDL_MapRGBA(gr->screen->format,
593                            gc->fore_r,
594                            gc->fore_g,
595                            gc->fore_b,
596                            gc->fore_a));
597 #else
598 #ifdef SDL_SGE
599 #ifdef ALPHA
600     sge_FilledRectAlpha(gr->screen, p->x, p->y, p->x + w, p->y + h,
601                         SDL_MapRGB(gr->screen->format,
602                                    gc->fore_r,
603                                    gc->fore_g,
604                                    gc->fore_b),
605                         gc->fore_a);
606 #else
607     /* no AA -- should use poly instead for that */
608     sge_FilledRect(gr->screen, p->x, p->y, p->x + w, p->y + h,
609                         SDL_MapRGB(gr->screen->format,
610                                    gc->fore_r,
611                                    gc->fore_g,
612                                    gc->fore_b));
613 #endif
614 #else
615     boxRGBA(gr->screen, p->x, p->y, p->x + w, p->y + h,
616             gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
617 #endif
618 #endif
619
620 }
621
622 static void
623 draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
624 {
625   if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
626     {
627       return;
628     }
629
630 #if 0
631         if(gc->fore_a != 0xff)
632         {
633         dbg(0, "%d %d %d %u %u:%u:%u:%u\n", p->x, p->y, r, gc->linewidth,
634             gc->fore_a, gc->fore_r, gc->fore_g, gc->fore_b);
635         }
636 #endif
637
638     /* FIXME: does not quite match gtk */
639
640     /* hack for osd compass.. why is this needed!? */
641     if(gr->overlay_mode)
642     {
643         r = r / 2;
644     }
645
646 #ifdef RASTER
647         if(gr->aa)
648         {
649             raster_aacircle(gr->screen, p->x, p->y, r,
650                             SDL_MapRGBA(gr->screen->format,
651                                        gc->fore_r,
652                                        gc->fore_g,
653                                        gc->fore_b,
654                                        gc->fore_a));
655         }
656         else
657         {
658             raster_circle(gr->screen, p->x, p->y, r,
659                           SDL_MapRGBA(gr->screen->format,
660                                      gc->fore_r,
661                                      gc->fore_g,
662                                      gc->fore_b,
663                                      gc->fore_a));
664         }
665 #else
666 #ifdef SDL_SGE
667 #ifdef ALPHA
668         sge_FilledCircleAlpha(gr->screen, p->x, p->y, r,
669                          SDL_MapRGB(gr->screen->format,
670                                     gc->fore_r, gc->fore_g, gc->fore_b),
671                          gc->fore_a);
672 #else
673 #ifdef ANTI_ALIAS
674         sge_AAFilledCircle(gr->screen, p->x, p->y, r,
675                          SDL_MapRGB(gr->screen->format,
676                                     gc->fore_r, gc->fore_g, gc->fore_b));
677 #else
678         sge_FilledCircle(gr->screen, p->x, p->y, r,
679                          SDL_MapRGB(gr->screen->format,
680                                     gc->fore_r, gc->fore_g, gc->fore_b));
681 #endif
682 #endif
683 #else
684 #ifdef ANTI_ALIAS
685         aacircleRGBA(gr->screen, p->x, p->y, r,
686                    gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
687 #else
688         filledCircleRGBA(gr->screen, p->x, p->y, r,
689                          gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
690 #endif
691 #endif
692 #endif
693 }
694
695
696 static void
697 draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
698 {
699   if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
700     {
701       return;
702     }
703
704     /* you might expect lines to be simpler than the other shapes.
705        but, that would be wrong. 1 line can generate 1 polygon + 2 circles
706        and even worse, we have to calculate their parameters!
707        go dust off your trigonometry hat.
708     */
709 #if 0
710     int i, l, x_inc, y_inc, lw;
711
712     lw = gc->linewidth;
713
714     for(i = 0; i < count-1; i++)
715     {
716 #ifdef DEBUG
717         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);
718 #endif
719         for(l = 0; l < lw; l++)
720         {
721             /* FIXME: center? */
722 #if 1
723             if(p[i].x != p[i+1].x)
724             {
725                 x_inc = l - (lw/2);
726             }
727             else
728             {
729                 x_inc = 0;
730             }
731
732             if(p[i].y != p[i+1].y)
733             {
734                 y_inc = l - (lw/2);
735             }
736             else
737             {
738                 y_inc = 0;
739             }
740 #else
741             x_inc = 0;
742             y_inc = 0;
743 #endif
744
745 #ifdef ANTI_ALIAS
746             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,
747                      gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
748 #else
749             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,
750                      gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
751 #endif
752         }
753     }
754 #else
755     /* sort of based on graphics_opengl.c::draw_lines */
756     /* FIXME: should honor ./configure flag for no fp.
757               this could be 100% integer code pretty easily,
758               except that i am lazy
759     */
760     struct point vert[4];
761     int lw = gc->linewidth;
762     //int lw = 1;
763     int i;
764
765     for(i = 0; i < count-1; i++)
766     {
767                 float dx=p[i+1].x-p[i].x;
768                 float dy=p[i+1].y-p[i].y;
769
770 #if 0
771                 float cx=(p[i+1].x+p[i].x)/2;
772                 float cy=(p[i+1].y+p[i].y)/2;
773 #endif
774
775         float angle;
776
777         int x_lw_adj, y_lw_adj;
778
779         if(lw == 1)
780         {
781 #ifdef RASTER
782             if(gr->aa)
783             {
784                 raster_aaline(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
785                          SDL_MapRGBA(gr->screen->format,
786                                     gc->fore_r,
787                                     gc->fore_g,
788                                     gc->fore_b,
789                                     gc->fore_a));
790             }
791             else
792             {
793                 raster_line(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
794                          SDL_MapRGBA(gr->screen->format,
795                                     gc->fore_r,
796                                     gc->fore_g,
797                                     gc->fore_b,
798                                     gc->fore_a));
799             }
800 #else
801 #ifdef SDL_SGE
802 #ifdef ALPHA
803             sge_LineAlpha(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
804                      SDL_MapRGB(gr->screen->format,
805                                 gc->fore_r, gc->fore_g, gc->fore_b),
806                      gc->fore_a);
807 #else
808 #ifdef ANTI_ALIAS
809             sge_AALine(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
810                      SDL_MapRGB(gr->screen->format,
811                                 gc->fore_r, gc->fore_g, gc->fore_b));
812 #else
813             sge_Line(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));
816 #endif
817 #endif
818 #else
819 #ifdef ANTI_ALIAS
820             aalineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
821                      gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
822 #else
823             lineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
824                      gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
825 #endif
826 #endif
827 #endif
828         }
829         else
830         {
831             /* there is probably a much simpler way but this works ok */
832
833             /* FIXME: float + double mixture */
834             /* FIXME: lrint(round())? */
835             if(dy == 0.0)
836             {
837                 angle = 0.0;
838                 x_lw_adj = 0;
839                 y_lw_adj = round((float)lw/2.0);
840             }
841             else if(dx == 0.0)
842             {
843                 angle = 0.0;
844                 x_lw_adj = round((float)lw/2.0);
845                 y_lw_adj = 0;
846             }
847             else
848             {
849                 angle = (M_PI/2.0) - atan(abs(dx)/abs(dy));
850                 x_lw_adj = round(sin(angle)*(float)lw/2.0);
851                 y_lw_adj = round(cos(angle)*(float)lw/2.0);
852                 if((x_lw_adj < 0) || (y_lw_adj < 0))
853                 {
854                     printf("i=%d\n", i);
855                     printf("   %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y);
856                     printf("   lw=%d angle=%f\n", lw, 180.0 * angle / M_PI);
857                     printf("   x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj);
858                 }
859             }
860
861             if(p[i+1].x > p[i].x)
862             {
863                 x_lw_adj = -x_lw_adj;
864             }
865             if(p[i+1].y > p[i].y)
866             {
867                 y_lw_adj = -y_lw_adj;
868             }
869
870 #if 0
871             if(((y_lw_adj*y_lw_adj)+(x_lw_adj*x_lw_adj)) != (lw/2)*(lw/2))
872             {
873                 printf("i=%d\n", i);
874                 printf("   %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y);
875                 printf("   lw=%d angle=%f\n", lw, 180.0 * angle / M_PI);
876                 printf("   x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj);
877             }
878 #endif
879
880             /* FIXME: draw a circle/square if p[i]==p[i+1]? */
881             /* FIXME: clipping, check for neg values. hoping sdl-gfx does this */
882             vert[0].x = p[i].x + x_lw_adj;
883             vert[0].y = p[i].y - y_lw_adj;
884             vert[1].x = p[i].x - x_lw_adj;
885             vert[1].y = p[i].y + y_lw_adj;
886             vert[2].x = p[i+1].x - x_lw_adj;
887             vert[2].y = p[i+1].y + y_lw_adj;
888             vert[3].x = p[i+1].x + x_lw_adj;
889             vert[3].y = p[i+1].y - y_lw_adj;
890
891             draw_polygon(gr, gc, vert, 4);
892
893             /* draw small circles at the ends. this looks better than nothing, and slightly
894              * better than the triangle used by graphics_opengl, but is more expensive.
895              * should have an ifdef/xml attr?
896             */
897
898             /* FIXME: should just draw a half circle */
899
900             /* now some circular endcaps, if the width is over 2 */
901             if(lw > 2)
902             {
903                 if(i == 0)
904                 {
905                     draw_circle(gr, gc, &p[i], lw/2);
906                 }
907                 /* we truncate on the divide on purpose, so we don't go outside the line */
908                 draw_circle(gr, gc, &p[i+1], lw/2);
909             }
910         }
911     }
912 #endif
913 }
914
915
916 static void
917 set_pixel(SDL_Surface *surface, int x, int y, Uint8 r2, Uint8 g2, Uint8 b2, Uint8 a2)
918 {
919     if(x<0 || y<0 || x>=surface->w || y>=surface->h) {
920         return;
921     }
922
923     void *target_pixel = ((Uint8*)surface->pixels + y * surface->pitch + x * surface->format->BytesPerPixel);
924
925     Uint8 r1,g1,b1,a1;
926
927     switch(surface->format->BytesPerPixel) {
928         case 2:
929             {
930                 SDL_GetRGBA(*(Uint16 *)target_pixel, surface->format, &r1, &g1, &b1, &a1);
931                 *(Uint16 *)target_pixel = SDL_MapRGBA(surface->format,
932                         (r1*(0xff-a2)/0xff) + (r2*a2/0xff),
933                         (g1*(0xff-a2)/0xff) + (g2*a2/0xff),
934                         (b1*(0xff-a2)/0xff) + (b2*a2/0xff),
935                         a2 + a1*(0xff-a2)/0xff );
936                 break;
937             }
938         case 4:
939             {
940                 SDL_GetRGBA(*(Uint32 *)target_pixel, surface->format, &r1, &g1, &b1, &a1);
941                 *(Uint32 *)target_pixel = SDL_MapRGBA(surface->format,
942                         (r1*(0xff-a2)/0xff) + (r2*a2/0xff),
943                         (g1*(0xff-a2)/0xff) + (g2*a2/0xff),
944                         (b1*(0xff-a2)/0xff) + (b2*a2/0xff),
945                         a2 + a1*(0xff-a2)/0xff );
946                 break;
947             }
948     }
949 }
950
951
952 static void
953 resize_ft_buffer (unsigned int new_size)
954 {
955     if (new_size > ft_buffer_size) {
956         g_free (ft_buffer);
957         ft_buffer = g_malloc (new_size);
958         dbg(1, "old_size(%i) new_size(%i) ft_buffer(%i)\n", ft_buffer_size, new_size, ft_buffer);
959         ft_buffer_size = new_size;
960     }
961 }
962
963 static void
964 display_text_draw(struct font_freetype_text *text,
965                   struct graphics_priv *gr, struct graphics_gc_priv *fg,
966                   struct graphics_gc_priv *bg, int color, struct point *p)
967 {
968     int i, x, y, stride;
969     struct font_freetype_glyph *g, **gp;
970     struct color transparent = { 0x0000, 0x0000, 0x0000, 0x0000 };
971     struct color black =
972         { fg->fore_r * 255, fg->fore_g * 255, fg->fore_b * 255, fg->fore_a * 255
973     };
974     struct color white = { 0xffff, 0xffff, 0xffff, 0xffff };
975
976     if (bg) {
977         if (COLOR_IS_WHITE(black) && COLOR_IS_BLACK(white)) {
978             black.r = 65535;
979             black.g = 65535;
980             black.b = 65535;
981             black.a = 65535;
982
983             white.r = 0;
984             white.g = 0;
985             white.b = 0;
986             white.a = 65535;
987         } else if (COLOR_IS_BLACK(black) && COLOR_IS_WHITE(white)) {
988             white.r = 65535;
989             white.g = 65535;
990             white.b = 65535;
991             white.a = 65535;
992
993             black.r = 0;
994             black.g = 0;
995             black.b = 0;
996             black.a = 65535;
997         } else {
998             white.r = bg->fore_r * 255;
999             white.g = bg->fore_g * 255;
1000             white.b = bg->fore_b * 255;
1001             white.a = bg->fore_a * 255;
1002         }
1003     } else {
1004         white.r = 0;
1005         white.g = 0;
1006         white.b = 0;
1007         white.a = 0;
1008     }
1009
1010
1011     gp = text->glyph;
1012     i = text->glyph_count;
1013     x = p->x << 6;
1014     y = p->y << 6;
1015     while (i-- > 0) {
1016         g = *gp++;
1017         if (g->w && g->h && bg) {
1018             stride = (g->w + 2) * 4;
1019             if (color) {
1020                 resize_ft_buffer(stride * (g->h + 2));
1021                 gr->freetype_methods.get_shadow(g, ft_buffer, 32, stride, &white, &transparent);
1022
1023                 SDL_Surface *glyph_surface =
1024                     SDL_CreateRGBSurfaceFrom(ft_buffer, g->w + 2, g->h + 2,
1025                                              32,
1026                                              stride,
1027                                              0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
1028                 if (glyph_surface) {
1029                     SDL_Rect r;
1030                     r.x = (x + g->x) >> 6;
1031                     r.y = (y + g->y) >> 6;
1032                     r.w = g->w + 2;
1033                     r.h = g->h + 2;
1034
1035                     SDL_BlitSurface(glyph_surface, NULL, gr->screen, &r);
1036                     SDL_FreeSurface(glyph_surface);
1037                 }
1038             }
1039         }
1040         x += g->dx;
1041         y += g->dy;
1042     }
1043
1044     gp = text->glyph;
1045     i = text->glyph_count;
1046     x = p->x << 6;
1047     y = p->y << 6;
1048     while (i-- > 0) {
1049         g = *gp++;
1050         if (g->w && g->h) {
1051             if (color) {
1052                 stride = g->w;
1053                 if (bg) {
1054                     resize_ft_buffer(stride * g->h * 4);
1055                     gr->freetype_methods.get_glyph(g, ft_buffer, 32,
1056                                                    stride * 4, &black,
1057                                                    &white, &transparent);
1058                     SDL_Surface *glyph_surface =
1059                         SDL_CreateRGBSurfaceFrom(ft_buffer, g->w, g->h, 32,
1060                                                  stride * 4,
1061                                                  0x000000ff,0x0000ff00, 0x00ff0000,0xff000000);
1062                     if (glyph_surface) {
1063                         SDL_Rect r;
1064                         r.x = (x + g->x) >> 6;
1065                         r.y = (y + g->y) >> 6;
1066                         r.w = g->w;
1067                         r.h = g->h;
1068
1069                         SDL_BlitSurface(glyph_surface, NULL, gr->screen,&r);
1070                         SDL_FreeSurface(glyph_surface);
1071                     }
1072                 }
1073                 stride *= 4;
1074                 resize_ft_buffer(stride * g->h);
1075                 gr->freetype_methods.get_glyph(g, ft_buffer, 32, stride,
1076                                                &black, &white,
1077                                                &transparent);
1078                 int ii, jj;
1079                 unsigned char* pGlyph = ft_buffer;
1080                 for (jj = 0; jj < g->h; ++jj) {
1081                     for (ii = 0; ii < g->w; ++ii) {
1082                         if(*(pGlyph+3) > 0) {
1083                             set_pixel(gr->screen,
1084                                       ii+((x + g->x) >> 6),
1085                                       jj+((y + g->y) >> 6),
1086                                       *(pGlyph+2),                      // Pixels are in BGRA format
1087                                       *(pGlyph+1),
1088                                       *(pGlyph+0),
1089                                       *(pGlyph+3)
1090                                      );
1091                         }
1092                         pGlyph += 4;
1093                     }
1094                 }
1095             }
1096         }
1097         x += g->dx;
1098         y += g->dy;
1099     }
1100 }
1101
1102 static void
1103 draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1104           struct graphics_gc_priv *bg, struct graphics_font_priv *font,
1105           char *text, struct point *p, int dx, int dy)
1106 {
1107     if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable)
1108         || (gr->overlay_parent && gr->overlay_parent->overlay_enable
1109             && !gr->overlay_enable)) {
1110         return;
1111     }
1112
1113     struct font_freetype_text *t;
1114     int color = 1;
1115
1116     if (!font) {
1117         dbg(0, "no font, returning\n");
1118         return;
1119     }
1120     t = gr->freetype_methods.text_new(text,
1121                                       (struct font_freetype_font *) font,
1122                                       dx, dy);
1123
1124     struct point p_eff;
1125     p_eff.x = p->x;
1126     p_eff.y = p->y;
1127
1128     display_text_draw(t, gr, fg, bg, color, &p_eff);
1129     gr->freetype_methods.text_destroy(t);
1130 }
1131
1132 static void
1133 draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
1134 {
1135   if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
1136     {
1137       return;
1138     }
1139
1140 #ifdef SDL_IMAGE
1141     SDL_Rect r;
1142
1143     r.x = p->x;
1144     r.y = p->y;
1145     r.w = img->img->w;
1146     r.h = img->img->h;
1147
1148     SDL_BlitSurface(img->img, NULL, gr->screen, &r);
1149 #endif
1150 }
1151
1152 static void
1153 draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
1154 {
1155     /* TODO */
1156 }
1157
1158 static void
1159 draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
1160 {
1161 #ifdef DEBUG
1162     printf("draw_restore\n");
1163 #endif
1164 }
1165
1166 static void
1167 background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
1168 {
1169 #ifdef DEBUG
1170     printf("background_gc\n");
1171 #endif
1172 }
1173
1174
1175 static void
1176 draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
1177 {
1178 #ifdef PROFILE
1179     struct timeval now;
1180     unsigned long elapsed;
1181 #endif
1182     struct graphics_priv *ov;
1183     SDL_Rect rect;
1184     int i;
1185
1186     if(gr->overlay_mode)
1187     {
1188         /* will be drawn below */
1189     }
1190     else
1191     {
1192 #ifdef DEBUG
1193         printf("draw_mode: %d\n", mode);
1194 #endif
1195
1196 #ifdef PROFILE
1197         if(mode == draw_mode_begin)
1198         {
1199             gettimeofday(&gr->draw_begin_tv, NULL);
1200         }
1201 #endif
1202
1203         if(mode == draw_mode_end)
1204         {
1205             if((gr->draw_mode == draw_mode_begin) && gr->overlay_enable)
1206             {
1207                 for(i = 0; i < OVERLAY_MAX; i++)
1208                 {
1209                     ov = gr->overlay_array[i];
1210                     if(ov && ov->overlay_enable)
1211                     {
1212                         rect.x = ov->overlay_x;
1213                         if(rect.x<0) rect.x += gr->screen->w;
1214                         rect.y = ov->overlay_y;
1215                         if(rect.y<0) rect.y += gr->screen->h;
1216                         rect.w = ov->screen->w;
1217                         rect.h = ov->screen->h;
1218                         SDL_BlitSurface(ov->screen, NULL,
1219                                         gr->screen, &rect);
1220                     }
1221                 }
1222             }
1223
1224             SDL_Flip(gr->screen);
1225
1226 #ifdef PROFILE
1227             gettimeofday(&now, NULL);
1228             elapsed = 1000000 * (now.tv_sec - gr->draw_begin_tv.tv_sec);
1229             elapsed += (now.tv_usec - gr->draw_begin_tv.tv_usec);
1230             if(elapsed >= gr->draw_time_peak)
1231             {
1232                dbg(0, "draw elapsed %u usec\n", elapsed);
1233                gr->draw_time_peak = elapsed;
1234             }
1235 #endif
1236         }
1237
1238         gr->draw_mode = mode;
1239     }
1240 }
1241
1242 static void overlay_disable(struct graphics_priv *gr, int disable)
1243 {
1244     gr->overlay_enable = !disable;
1245     struct graphics_priv *curr_gr = gr;
1246     if(gr->overlay_parent) {
1247       curr_gr = gr->overlay_parent;
1248     }
1249     draw_mode(curr_gr,draw_mode_end);
1250 }
1251
1252 static struct graphics_priv *
1253 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h, int alpha, int wraparound);
1254
1255 static int window_fullscreen(struct window *win, int on)
1256 {
1257         struct graphics_priv *gr=(struct graphics_priv *)win->priv;
1258
1259         /* Update video flags */
1260         if(on) {
1261                 gr->video_flags |= SDL_FULLSCREEN;
1262         } else {
1263                 gr->video_flags &= ~SDL_FULLSCREEN;
1264         }
1265
1266         /* Update video mode */
1267         gr->screen = SDL_SetVideoMode(gr->screen->w, gr->screen->h, gr->video_bpp, gr->video_flags);
1268         if(gr->screen == NULL) {
1269                 navit_destroy(gr->nav);
1270         }
1271         else {
1272                 callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
1273         }
1274         return 1;
1275 }
1276
1277 static void *
1278 get_data(struct graphics_priv *this, char const *type)
1279 {
1280         if(strcmp(type, "window") == 0) {
1281                 struct window *win;
1282                 win=g_new(struct window, 1);
1283                 win->priv=this;
1284                 win->fullscreen=window_fullscreen;
1285                 win->disable_suspend=NULL;
1286                 return win;
1287         } else {
1288                 return &dummy;
1289         }
1290 }
1291
1292 static void draw_drag(struct graphics_priv *gr, struct point *p)
1293 {
1294         if(p) {
1295             gr->overlay_x = p->x;
1296             gr->overlay_y = p->y;
1297         }
1298 }
1299
1300 static struct graphics_methods graphics_methods = {
1301         graphics_destroy,
1302         draw_mode,
1303         draw_lines,
1304         draw_polygon,
1305         draw_rectangle,
1306         NULL /*draw_circle*/,
1307         draw_text,
1308         draw_image,
1309         draw_image_warp,
1310         draw_restore,
1311         draw_drag,
1312         NULL,
1313         gc_new,
1314         background_gc,
1315         overlay_new,
1316         image_new,
1317         get_data,
1318         image_free,
1319         get_text_bbox,
1320         overlay_disable,
1321 };
1322
1323 static struct graphics_priv *
1324 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h,int alpha, int wraparound)
1325 {
1326         struct graphics_priv *ov;
1327         Uint32 rmask, gmask, bmask, amask;
1328         int i;
1329
1330         for(i = 0; i < OVERLAY_MAX; i++)
1331         {
1332                 if(gr->overlay_array[i] == NULL)
1333                 {
1334                         break;
1335                 }
1336         }
1337         if(i == OVERLAY_MAX)
1338         {
1339                 dbg(0, "too many overlays! increase OVERLAY_MAX\n");
1340                 return NULL;
1341         }
1342
1343         dbg(1, "overlay_new %d %d %d %u %u (%x, %x, %x ,%x, %d)\n", i,
1344                         p->x,
1345                         p->y,
1346                         w,
1347                         h,
1348                         gr->screen->format->Rmask,
1349                         gr->screen->format->Gmask,
1350                         gr->screen->format->Bmask,
1351                         gr->screen->format->Amask,
1352                         gr->screen->format->BitsPerPixel
1353            );
1354
1355         ov = g_new0(struct graphics_priv, 1);
1356
1357         switch(gr->screen->format->BitsPerPixel) {
1358         case 8:
1359                 rmask = 0xc0;
1360                 gmask = 0x30;
1361                 bmask = 0x0c;
1362                 amask = 0x03;
1363                 break;
1364         case 16:
1365                 rmask = 0xf000;
1366                 gmask = 0x0f00;
1367                 bmask = 0x00f0;
1368                 amask = 0x000f;
1369                 break;
1370         case 32:
1371                 rmask = 0xff000000;
1372                 gmask = 0x00ff0000;
1373                 bmask = 0x0000ff00;
1374                 amask = 0x000000ff;
1375                 break;
1376         default:
1377                 rmask = gr->screen->format->Rmask;
1378                 gmask = gr->screen->format->Gmask;
1379                 bmask = gr->screen->format->Bmask;
1380                 amask = gr->screen->format->Amask;
1381         }
1382
1383         ov->screen = SDL_CreateRGBSurface(SDL_SWSURFACE,
1384                         w, h,
1385                         gr->screen->format->BitsPerPixel,
1386                         rmask, gmask, bmask, amask);
1387
1388         ov->overlay_mode = 1;
1389         ov->overlay_enable = 1;
1390         ov->overlay_x = p->x;
1391         ov->overlay_y = p->y;
1392         ov->overlay_parent = gr;
1393         ov->overlay_idx = i;
1394         gr->overlay_array[i] = ov;
1395
1396
1397   struct font_priv *(*font_freetype_new) (void *meth);
1398   font_freetype_new = plugin_get_font_type ("freetype");
1399
1400   if (!font_freetype_new)
1401     {
1402       return NULL;
1403     }
1404
1405
1406   font_freetype_new (&ov->freetype_methods);
1407
1408         *meth=graphics_methods;
1409
1410   meth->font_new =
1411     (struct graphics_font_priv *
1412      (*)(struct graphics_priv *, struct graphics_font_methods *, char *, int,
1413          int)) ov->freetype_methods.font_new;
1414   meth->get_text_bbox = (void *)ov->freetype_methods.get_text_bbox;
1415
1416
1417
1418
1419         return ov;
1420 }
1421
1422
1423 #ifdef LINUX_TOUCHSCREEN
1424
1425 #define EVFN "/dev/input/eventX"
1426
1427 static int input_ts_init(struct graphics_priv *gr)
1428 {
1429     struct input_id ii;
1430     char fn[32];
1431 #if 0
1432     char name[64];
1433 #endif
1434     int n, fd, ret;
1435
1436     gr->ts_fd = -1;
1437     gr->ts_hit = -1;
1438     gr->ts_x = 0;
1439     gr->ts_y = 0;
1440
1441     strcpy(fn, EVFN);
1442     n = 0;
1443     while(1)
1444     {
1445         fn[sizeof(EVFN)-2] = '0' + n;
1446
1447         fd = open(fn, O_RDONLY);
1448         if(fd >= 0)
1449         {
1450 #if 0
1451             ret = ioctl(fd, EVIOCGNAME(64), (void *)name);
1452             if(ret > 0)
1453             {
1454                 printf("input_ts: %s\n", name);
1455             }
1456 #endif
1457
1458             ret = ioctl(fd, EVIOCGID, (void *)&ii);
1459             if(ret == 0)
1460             {
1461 #if 1
1462                 printf("bustype %04x vendor %04x product %04x version %04x\n",
1463                        ii.bustype,
1464                        ii.vendor,
1465                        ii.product,
1466                        ii.version);
1467 #endif
1468
1469                 if((ii.bustype == BUS_USB) &&
1470                    (ii.vendor == 0x0eef) &&
1471                    (ii.product == 0x0001))
1472                 {
1473                     ret = fcntl(fd, F_SETFL, O_NONBLOCK);
1474                     if(ret == 0)
1475                     {
1476                         gr->ts_fd = fd;
1477                     }
1478                     else
1479                     {
1480                         close(fd);
1481                     }
1482
1483                     break;
1484                 }
1485             }
1486
1487             close(fd);
1488         }
1489
1490         n = n + 1;
1491
1492         /* FIXME: should check all 32 minors */
1493         if(n == 10)
1494         {
1495             /* not found */
1496             ret = -1;
1497             break;
1498         }
1499     }
1500
1501     return ret;
1502 }
1503
1504
1505 /* returns 0-based display coordinate for the given ts coord */
1506 static void input_ts_map(int *disp_x, int *disp_y,
1507                          uint32_t ts_x, uint32_t ts_y)
1508 {
1509     /* Dynamix 7" (eGalax TS)
1510        top left  = 1986,103
1511        top right =   61,114
1512        bot left  = 1986,1897
1513        bot right =   63,1872
1514
1515        calibrate your TS using input_event_dump
1516        and touching all four corners. use the most extreme values.
1517     */
1518
1519 #define INPUT_TS_LEFT 1978
1520 #define INPUT_TS_RIGHT  48
1521 #define INPUT_TS_TOP   115
1522 #define INPUT_TS_BOT  1870
1523
1524     /* clamp first */
1525     if(ts_x > INPUT_TS_LEFT)
1526     {
1527         ts_x = INPUT_TS_LEFT;
1528     }
1529     if(ts_x < INPUT_TS_RIGHT)
1530     {
1531         ts_x = INPUT_TS_RIGHT;
1532     }
1533
1534     ts_x = ts_x - INPUT_TS_RIGHT;
1535
1536     *disp_x = ((DISPLAY_W-1) * ts_x) / (INPUT_TS_LEFT - INPUT_TS_RIGHT);
1537     *disp_x = (DISPLAY_W-1) - *disp_x;
1538
1539
1540     if(ts_y > INPUT_TS_BOT)
1541     {
1542         ts_y = INPUT_TS_BOT;
1543     }
1544     if(ts_y < INPUT_TS_TOP)
1545     {
1546         ts_y = INPUT_TS_TOP;
1547     }
1548
1549     ts_y = ts_y - INPUT_TS_TOP;
1550
1551     *disp_y = ((DISPLAY_H-1) * ts_y) / (INPUT_TS_BOT - INPUT_TS_TOP);
1552 /*  *disp_y = (DISPLAY_H-1) - *disp_y; */
1553 }
1554
1555 #if 0
1556 static void input_event_dump(struct input_event *ie)
1557 {
1558     printf("input_event:\n"
1559            "\ttv_sec\t%u\n"
1560            "\ttv_usec\t%lu\n"
1561            "\ttype\t%u\n"
1562            "\tcode\t%u\n"
1563            "\tvalue\t%d\n",
1564            (unsigned int)ie->time.tv_sec,
1565            ie->time.tv_usec,
1566            ie->type,
1567            ie->code,
1568            ie->value);
1569 }
1570 #endif
1571
1572 static int input_ts_exit(struct graphics_priv *gr)
1573 {
1574     close(gr->ts_fd);
1575     gr->ts_fd = -1;
1576
1577     return 0;
1578 }
1579 #endif
1580
1581 #ifdef USE_WEBOS_ACCELEROMETER
1582 static void
1583 sdl_accelerometer_handler(void* param)
1584 {
1585     struct graphics_priv *gr = (struct graphics_priv *)param;
1586     int xAxis = SDL_JoystickGetAxis(gr->accelerometer, 0);
1587     int yAxis = SDL_JoystickGetAxis(gr->accelerometer, 1);
1588     int zAxis = SDL_JoystickGetAxis(gr->accelerometer, 2);
1589     char new_orientation;
1590
1591     if (xAxis < -15000 && yAxis > -7000 && yAxis < 7000)
1592         new_orientation = WEBOS_ORIENTATION_LANDSCAPE;
1593     else if (yAxis > 15000 && xAxis > -7000 && xAxis < 7000)
1594         new_orientation = WEBOS_ORIENTATION_PORTRAIT;
1595     else
1596         return;
1597
1598     if (new_orientation != gr->orientation)
1599     {
1600         dbg(1,"x(%d) y(%d) z(%d) o(%d)\n",xAxis, yAxis, zAxis, new_orientation);
1601         gr->orientation = new_orientation;
1602
1603         SDL_Event event;
1604         SDL_UserEvent userevent;
1605
1606         userevent.type = SDL_USEREVENT;
1607         userevent.code = SDL_USEREVENT_CODE_ROTATE;
1608         userevent.data1 = NULL;
1609         userevent.data2 = NULL;
1610
1611         event.type = SDL_USEREVENT;
1612         event.user = userevent;
1613
1614         SDL_PushEvent (&event);
1615     }
1616 }
1617 #endif
1618
1619 static gboolean graphics_sdl_idle(void *data)
1620 {
1621     struct graphics_priv *gr = (struct graphics_priv *)data;
1622     struct point p;
1623     SDL_Event ev;
1624 #ifdef LINUX_TOUCHSCREEN
1625     struct input_event ie;
1626     ssize_t ss;
1627 #endif
1628     int ret;
1629     char key_mod = 0;
1630     char keybuf[8];
1631
1632 #ifdef USE_WEBOS
1633     if(data==NULL) {
1634         if(the_graphics!=NULL) {
1635             gr = the_graphics;
1636         }
1637         else {
1638             dbg(0,"graphics_idle: graphics not set!\n");
1639             return FALSE;
1640         }
1641     }
1642 #endif
1643
1644     /* generate the initial resize callback, so the gui knows W/H
1645
1646        its unsafe to do this directly inside register_resize_callback;
1647        graphics_gtk does it during Configure, but SDL does not have
1648        an equivalent event, so we use our own flag
1649     */
1650     if(gr->resize_callback_initial != 0)
1651     {
1652         callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
1653         gr->resize_callback_initial = 0;
1654     }
1655
1656 #ifdef LINUX_TOUCHSCREEN
1657     if(gr->ts_fd >= 0)
1658     {
1659         ss = read(gr->ts_fd, (void *)&ie, sizeof(ie));
1660         if(ss == sizeof(ie))
1661         {
1662             /* we (usually) get three events on a touchscreen hit:
1663               1: type =EV_KEY
1664                  code =330 [BTN_TOUCH]
1665                  value=1
1666
1667               2: type =EV_ABS
1668                  code =0 [X]
1669                  value=X pos
1670
1671               3: type =EV_ABS
1672                  code =1 [Y]
1673                  value=Y pos
1674
1675               4: type =EV_SYN
1676
1677               once hit, if the contact point changes, we'll get more
1678               EV_ABS (for 1 or both axes), followed by an EV_SYN.
1679
1680               and, on a lift:
1681
1682               5: type =EV_KEY
1683                  code =330 [BTN_TOUCH]
1684                  value=0
1685
1686               6: type =EV_SYN
1687             */
1688             switch(ie.type)
1689             {
1690                 case EV_KEY:
1691                 {
1692                     if(ie.code == BTN_TOUCH)
1693                     {
1694                         gr->ts_hit = ie.value;
1695                     }
1696
1697                     break;
1698                 }
1699
1700                 case EV_ABS:
1701                 {
1702                     if(ie.code == 0)
1703                     {
1704                         gr->ts_x = ie.value;
1705                     }
1706                     else if(ie.code == 1)
1707                     {
1708                         gr->ts_y = ie.value;
1709                     }
1710
1711                     break;
1712                 }
1713
1714                 case EV_SYN:
1715                 {
1716                     input_ts_map(&p.x, &p.y, gr->ts_x, gr->ts_y);
1717
1718                     /* always send MOUSE_MOTION (first) */
1719                     callback_list_call_attr_1(gr->cbl, attr_motion, (void *)&p);
1720                     if(gr->ts_hit > 0)
1721                     {
1722                         callback_list_call_attr_3(gr->cbl, attr_button, (void *)1, (void *)SDL_BUTTON_LEFT, (void *)&p);
1723                     }
1724                     else if(gr->ts_hit == 0)
1725                     {
1726                         callback_list_call_attr_3(gr->cbl, attr_button, (void *)0, (void *)SDL_BUTTON_LEFT, (void *)&p);
1727                     }
1728
1729                     /* reset ts_hit */
1730                     gr->ts_hit = -1;
1731
1732                     break;
1733                 }
1734
1735                 default:
1736                 {
1737                     break;
1738                 }
1739             }
1740         }
1741     }
1742 #endif
1743
1744 #ifdef USE_WEBOS_ACCELEROMETER
1745     struct callback* accel_cb = callback_new_1(callback_cast(sdl_accelerometer_handler), gr);
1746     struct event_timeout* accel_to = event_add_timeout(200, 1, accel_cb);
1747 #endif
1748 #ifdef USE_WEBOS
1749     unsigned int idle_tasks_idx=0;
1750     unsigned int idle_tasks_cur_priority=0;
1751     struct idle_task *task;
1752
1753     while(!quit_event_loop)
1754 #else
1755     while(1)
1756 #endif
1757     {
1758 #ifdef USE_WEBOS
1759         ret = 0;
1760         if(idle_tasks->len > 0)
1761         {
1762             while (!(ret = SDL_PollEvent(&ev)) && idle_tasks->len > 0)
1763             {
1764                 if (idle_tasks_idx >= idle_tasks->len)
1765                     idle_tasks_idx = 0;
1766
1767                 dbg(3,"idle_tasks_idx(%d)\n",idle_tasks_idx);
1768                 task = (struct idle_task *)g_ptr_array_index(idle_tasks,idle_tasks_idx);
1769
1770                 if (idle_tasks_idx == 0)        // only execute tasks with lowest priority value
1771                     idle_tasks_cur_priority = task->priority;
1772                 if (task->priority > idle_tasks_cur_priority)
1773                     idle_tasks_idx = 0;
1774                 else
1775                 {
1776                     callback_call_0(task->cb);
1777                     idle_tasks_idx++;
1778                 }
1779             }
1780         }
1781         if (!ret)       // If we get here there are no idle_tasks and we have no events pending
1782             ret = SDL_WaitEvent(&ev);
1783 #else
1784         ret = SDL_PollEvent(&ev);
1785 #endif
1786         if(ret == 0)
1787         {
1788             break;
1789         }
1790
1791 #ifdef USE_WEBOS
1792         dbg(1,"SDL_Event %d\n", ev.type);
1793 #endif
1794         switch(ev.type)
1795         {
1796             case SDL_MOUSEMOTION:
1797             {
1798                 p.x = ev.motion.x;
1799                 p.y = ev.motion.y;
1800                 callback_list_call_attr_1(gr->cbl, attr_motion, (void *)&p);
1801                 break;
1802             }
1803
1804             case SDL_KEYDOWN:
1805             {
1806                 keybuf[1] = 0;
1807                 switch(ev.key.keysym.sym)
1808                 {
1809                     case SDLK_LEFT:
1810                     {
1811                         keybuf[0] = NAVIT_KEY_LEFT;
1812                         break;
1813                     }
1814                     case SDLK_RIGHT:
1815                     {
1816                         keybuf[0] = NAVIT_KEY_RIGHT;
1817                         break;
1818                     }
1819                     case SDLK_BACKSPACE:
1820                     {
1821                         keybuf[0] = NAVIT_KEY_BACKSPACE;
1822                         break;
1823                     }
1824                     case SDLK_RETURN:
1825                     {
1826                         keybuf[0] = NAVIT_KEY_RETURN;
1827                         break;
1828                     }
1829                     case SDLK_DOWN:
1830                     {
1831                         keybuf[0] = NAVIT_KEY_DOWN;
1832                         break;
1833                     }
1834                     case SDLK_PAGEUP:
1835                     {
1836                         keybuf[0] = NAVIT_KEY_ZOOM_OUT;
1837                         break;
1838                     }
1839                     case SDLK_UP:
1840                     {
1841                         keybuf[0] = NAVIT_KEY_UP;
1842                         break;
1843                     }
1844                     case SDLK_PAGEDOWN:
1845                     {
1846                         keybuf[0] = NAVIT_KEY_ZOOM_IN;
1847                         break;
1848                     }
1849 #ifdef USE_WEBOS
1850                     case WEBOS_KEY_SHIFT:
1851                     {
1852                         if ((key_mod & WEBOS_KEY_MOD_SHIFT_STICKY) == WEBOS_KEY_MOD_SHIFT_STICKY)
1853                             key_mod &= ~(WEBOS_KEY_MOD_SHIFT_STICKY);
1854                         else if ((key_mod & WEBOS_KEY_MOD_SHIFT) == WEBOS_KEY_MOD_SHIFT)
1855                             key_mod |= WEBOS_KEY_MOD_SHIFT_STICKY;
1856                         else
1857                             key_mod |= WEBOS_KEY_MOD_SHIFT;
1858                         break;
1859                     }
1860                     case WEBOS_KEY_ORANGE:
1861                     {
1862                         if ((key_mod & WEBOS_KEY_MOD_ORANGE_STICKY) == WEBOS_KEY_MOD_ORANGE_STICKY)
1863                             key_mod &= ~(WEBOS_KEY_MOD_ORANGE_STICKY);
1864                         else if ((key_mod & WEBOS_KEY_MOD_ORANGE) == WEBOS_KEY_MOD_ORANGE)
1865                             key_mod |= WEBOS_KEY_MOD_ORANGE_STICKY;
1866                         else
1867                             key_mod |= WEBOS_KEY_MOD_ORANGE;
1868                         break;
1869                     }
1870                     case WEBOS_KEY_SYM:
1871                     {
1872                         /* Toggle the on-screen keyboard */
1873                         //callback_list_call_attr_1(gr->cbl, attr_keyboard_toggle);     // Not implemented yet
1874                         break;
1875                     }
1876                     case PDLK_GESTURE_BACK:
1877                     {
1878                         keybuf[0] = NAVIT_KEY_BACK;
1879                         break;
1880                     }
1881                     case PDLK_GESTURE_FORWARD:
1882                     case PDLK_GESTURE_AREA:
1883                     {
1884                         break;
1885                     }
1886 #endif
1887                     default:
1888                     {
1889 #ifdef USE_WEBOS
1890                         if (ev.key.keysym.unicode < 0x80 && ev.key.keysym.unicode > 0) {
1891                             keybuf[0] = (char)ev.key.keysym.unicode;
1892                             if ((key_mod & WEBOS_KEY_MOD_ORANGE) == WEBOS_KEY_MOD_ORANGE) {
1893                                 switch(keybuf[0]) {
1894                                     case 'e': keybuf[0] = '1'; break;
1895                                     case 'r': keybuf[0] = '2'; break;
1896                                     case 't': keybuf[0] = '3'; break;
1897                                     case 'd': keybuf[0] = '4'; break;
1898                                     case 'f': keybuf[0] = '5'; break;
1899                                     case 'g': keybuf[0] = '6'; break;
1900                                     case 'x': keybuf[0] = '7'; break;
1901                                     case 'c': keybuf[0] = '8'; break;
1902                                     case 'v': keybuf[0] = '9'; break;
1903                                     case '@': keybuf[0] = '0'; break;
1904                                     case ',': keybuf[0] = '-'; break;
1905                                     case 'u': strncpy(keybuf, "ü", sizeof(keybuf)); break;
1906                                     case 'a': strncpy(keybuf, "ä", sizeof(keybuf)); break;
1907                                     case 'o': strncpy(keybuf, "ö", sizeof(keybuf)); break;
1908                                     case 's': strncpy(keybuf, "ß", sizeof(keybuf)); break;
1909                                 }
1910                             }
1911                             /*if ((key_mod & WEBOS_KEY_MOD_SHIFT) == WEBOS_KEY_MOD_SHIFT)
1912                                 key -= 32;*/
1913                             if ((key_mod & WEBOS_KEY_MOD_SHIFT_STICKY) != WEBOS_KEY_MOD_SHIFT_STICKY)
1914                                 key_mod &= ~(WEBOS_KEY_MOD_SHIFT_STICKY);
1915                             if ((key_mod & WEBOS_KEY_MOD_ORANGE_STICKY) != WEBOS_KEY_MOD_ORANGE_STICKY)
1916                                 key_mod &= ~(WEBOS_KEY_MOD_ORANGE_STICKY);
1917                         }
1918                         else {
1919                             dbg(0,"Unknown key sym: %x\n", ev.key.keysym.sym);
1920                         }
1921 #else
1922                         /* return unicode chars when they can be converted to ascii */
1923                         keybuf[0] = ev.key.keysym.unicode<=127 ? ev.key.keysym.unicode : 0;
1924 #endif
1925                         break;
1926                     }
1927                 }
1928
1929                 dbg(2,"key mod: 0x%x\n", key_mod);
1930
1931                 if (keybuf[0]) {
1932                     dbg(2,"key: %s 0x%x\n", keybuf, keybuf);
1933                     callback_list_call_attr_1(gr->cbl, attr_keypress, (void *)keybuf);
1934                 }
1935                 break;
1936             }
1937
1938             case SDL_KEYUP:
1939             {
1940                 break;
1941             }
1942
1943             case SDL_MOUSEBUTTONDOWN:
1944             {
1945 #ifdef DEBUG
1946                 printf("SDL_MOUSEBUTTONDOWN %d %d %d %d %d\n",
1947                        ev.button.which,
1948                        ev.button.button,
1949                        ev.button.state,
1950                        ev.button.x,
1951                        ev.button.y);
1952 #endif
1953
1954                 p.x = ev.button.x;
1955                 p.y = ev.button.y;
1956                 callback_list_call_attr_3(gr->cbl, attr_button, (void *)1, (void *)(int)ev.button.button, (void *)&p);
1957                 break;
1958             }
1959
1960             case SDL_MOUSEBUTTONUP:
1961             {
1962 #ifdef DEBUG
1963                 printf("SDL_MOUSEBUTTONUP %d %d %d %d %d\n",
1964                        ev.button.which,
1965                        ev.button.button,
1966                        ev.button.state,
1967                        ev.button.x,
1968                        ev.button.y);
1969 #endif
1970
1971                 p.x = ev.button.x;
1972                 p.y = ev.button.y;
1973                 callback_list_call_attr_3(gr->cbl, attr_button, (void *)0, (void *)(int)ev.button.button, (void *)&p);
1974                 break;
1975             }
1976
1977             case SDL_QUIT:
1978             {
1979 #ifdef USE_WEBOS
1980                 quit_event_loop = 1;
1981                 navit_destroy(gr->nav);
1982 #endif
1983                 break;
1984             }
1985
1986             case SDL_VIDEORESIZE:
1987             {
1988
1989                 gr->screen = SDL_SetVideoMode(ev.resize.w, ev.resize.h, gr->video_bpp, gr->video_flags);
1990                 if(gr->screen == NULL)
1991                 {
1992                     navit_destroy(gr->nav);
1993                 }
1994                 else
1995                 {
1996                     callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
1997                 }
1998
1999                 break;
2000             }
2001
2002 #ifdef USE_WEBOS
2003             case SDL_USEREVENT:
2004             {
2005                 SDL_UserEvent userevent = ev.user;
2006                 dbg(9,"received SDL_USEREVENT type(%x) code(%x)\n",userevent.type,userevent.code);
2007                 if (userevent.type != SDL_USEREVENT)
2008                     break;
2009
2010                 if (userevent.code == PDL_GPS_UPDATE)
2011                 {
2012                     struct attr vehicle_attr;
2013                     struct vehicle *v;
2014                     navit_get_attr(gr->nav, attr_vehicle,  &vehicle_attr, NULL);
2015                     v = vehicle_attr.u.vehicle;
2016                     if (v) {
2017                         struct attr attr;
2018                         attr.type = attr_pdl_gps_update;
2019                         attr.u.data = userevent.data1;
2020                         vehicle_set_attr(v, &attr);
2021                     }
2022                 }
2023                 else if(userevent.code == SDL_USEREVENT_CODE_TIMER)
2024                 {
2025                     struct callback *cb = (struct callback *)userevent.data1;
2026                     dbg(1, "SDL_USEREVENT timer received cb(%p)\n", cb);
2027                     callback_call_0(cb);
2028                 }
2029                 else if(userevent.code == SDL_USEREVENT_CODE_WATCH)
2030                 {
2031                     struct callback *cb = (struct callback *)userevent.data1;
2032                     dbg(1, "SDL_USEREVENT watch received cb(%p)\n", cb);
2033                     callback_call_0(cb);
2034                 }
2035                 else if(userevent.code == SDL_USEREVENT_CODE_CALL_CALLBACK)
2036                 {
2037                     struct callback_list *cbl = (struct callback_list *)userevent.data1;
2038                     dbg(1, "SDL_USEREVENT call_callback received cbl(%p)\n", cbl);
2039                     callback_list_call_0(cbl);
2040                 }
2041                 else if(userevent.code == SDL_USEREVENT_CODE_IDLE_EVENT) {
2042                     dbg(1, "SDL_USEREVENT idle_event received\n");
2043                 }
2044 #ifdef USE_WEBOS_ACCELEROMETER
2045                 else if(userevent.code == SDL_USEREVENT_CODE_ROTATE)
2046                 {
2047                     dbg(1, "SDL_USEREVENT rotate received\n");
2048                     switch(gr->orientation)
2049                     {
2050                         case WEBOS_ORIENTATION_PORTRAIT:
2051                             gr->screen = SDL_SetVideoMode(gr->real_w, gr->real_h, gr->video_bpp, gr->video_flags);
2052                             PDL_SetOrientation(PDL_ORIENTATION_0);
2053                             break;
2054                         case WEBOS_ORIENTATION_LANDSCAPE:
2055                             gr->screen = SDL_SetVideoMode(gr->real_h, gr->real_w, gr->video_bpp, gr->video_flags);
2056                             PDL_SetOrientation(PDL_ORIENTATION_270);
2057                             break;
2058                     }
2059                     if(gr->screen == NULL)
2060                     {
2061                         navit_destroy(gr->nav);
2062                     }
2063                     else
2064                     {
2065                         callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
2066                     }
2067                 }
2068 #endif
2069                 else
2070                     dbg(1, "unknown SDL_USEREVENT\n");
2071
2072                 break;
2073             }
2074 #endif
2075             default:
2076             {
2077 #ifdef DEBUG
2078                 printf("SDL_Event %d\n", ev.type);
2079 #endif
2080                 break;
2081             }
2082         }
2083     }
2084
2085 #ifdef USE_WEBOS
2086     event_sdl_watch_stopthread();
2087 #endif
2088
2089 #ifdef USE_WEBOS_ACCELEROMETER
2090     event_remove_timeout(accel_to);
2091     callback_destroy(accel_cb);
2092 #endif
2093
2094     return TRUE;
2095 }
2096
2097
2098 static struct graphics_priv *
2099 graphics_sdl_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
2100 {
2101     struct graphics_priv *this=g_new0(struct graphics_priv, 1);
2102     struct attr *attr;
2103     int ret;
2104     int w=DISPLAY_W,h=DISPLAY_H;
2105
2106     struct font_priv *(*font_freetype_new) (void *meth);
2107     font_freetype_new = plugin_get_font_type ("freetype");
2108
2109     if (!font_freetype_new)
2110       {
2111         return NULL;
2112       }
2113
2114     font_freetype_new (&this->freetype_methods);
2115
2116     this->nav = nav;
2117     this->cbl = cbl;
2118
2119     dbg(1,"Calling SDL_Init\n");
2120 #ifdef USE_WEBOS
2121 # ifdef USE_WEBOS_ACCELEROMETER
2122     ret = SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_JOYSTICK);
2123 # else
2124     ret = SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER);
2125 # endif
2126 #else
2127     ret = SDL_Init(SDL_INIT_VIDEO);
2128 #endif
2129     if(ret < 0)
2130     {
2131         dbg(0,"SDL_Init failed %d\n", ret);
2132         g_free(this);
2133         return NULL;
2134     }
2135
2136 #ifdef USE_WEBOS
2137     dbg(1,"Calling PDL_Init(0)\n");
2138     ret = PDL_Init(0);
2139     if(ret < 0)
2140     {
2141         dbg(0,"PDL_Init failed %d\n", ret);
2142         g_free(this);
2143         return NULL;
2144     }
2145
2146     if (! event_request_system("sdl","graphics_sdl_new")) {
2147 #else
2148     if (! event_request_system("glib","graphics_sdl_new")) {
2149 #endif
2150         dbg(0,"event_request_system failed");
2151         return NULL;
2152     }
2153
2154 #ifdef USE_WEBOS
2155     this->video_bpp = 0;
2156     this->video_flags = SDL_SWSURFACE | SDL_ANYFORMAT | SDL_RESIZABLE;
2157 #else
2158     this->video_bpp = 16;
2159     this->video_flags = SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE;
2160 #endif
2161
2162     if ((attr=attr_search(attrs, NULL, attr_w)))
2163         w=attr->u.num;
2164     if ((attr=attr_search(attrs, NULL, attr_h)))
2165         h=attr->u.num;
2166     if ((attr=attr_search(attrs, NULL, attr_bpp)))
2167         this->video_bpp=attr->u.num;
2168     if ((attr=attr_search(attrs, NULL, attr_flags))) {
2169         if (attr->u.num & 1)
2170             this->video_flags = SDL_SWSURFACE;
2171     }
2172     if ((attr=attr_search(attrs, NULL, attr_frame))) {
2173         if(!attr->u.num)
2174             this->video_flags |= SDL_NOFRAME;
2175     }
2176
2177     this->screen = SDL_SetVideoMode(w, h, this->video_bpp, this->video_flags);
2178
2179     if(this->screen == NULL)
2180     {
2181         dbg(0,"SDL_SetVideoMode failed\n");
2182         g_free(this);
2183 #ifdef USE_WEBOS
2184         PDL_Quit();
2185 #endif
2186         SDL_Quit();
2187         return NULL;
2188     }
2189
2190     /* Use screen size instead of requested */
2191     w = this->screen->w;
2192     h = this->screen->h;
2193
2194     dbg(0, "using screen %ix%i@%i\n",
2195             this->screen->w, this->screen->h,
2196             this->screen->format->BytesPerPixel * 8);
2197 #ifdef USE_WEBOS_ACCELEROMETER
2198     this->real_w = w;
2199     this->real_h = h;
2200     this->accelerometer = SDL_JoystickOpen(0);
2201 #endif
2202
2203     SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
2204 #ifdef USE_WEBOS
2205     PDL_SetOrientation(PDL_ORIENTATION_0);
2206 #endif
2207
2208     SDL_EnableUNICODE(1);
2209     SDL_WM_SetCaption("navit", NULL);
2210
2211 #ifdef LINUX_TOUCHSCREEN
2212     input_ts_init(this);
2213     if(this->ts_fd >= 0)
2214     {
2215         /* mouse cursor does not always display correctly in Linux FB.
2216            anyway, it is unnecessary w/ a touch screen
2217         */
2218         SDL_ShowCursor(0);
2219     }
2220 #endif
2221
2222 #ifdef SDL_SGE
2223     sge_Update_OFF();
2224     sge_Lock_ON();
2225 #endif
2226
2227     *meth=graphics_methods;
2228
2229
2230     meth->font_new =
2231        (struct graphics_font_priv *
2232        (*)(struct graphics_priv *, struct graphics_font_methods *, char *, int,
2233         int)) this->freetype_methods.font_new;
2234     meth->get_text_bbox = (void*) this->freetype_methods.get_text_bbox;
2235
2236
2237
2238 #ifdef USE_WEBOS
2239     if(the_graphics!=NULL) {
2240         dbg(0,"graphics_sdl_new: graphics struct already set: %d!\n", the_graphics_count);
2241     }
2242     the_graphics = this;
2243     the_graphics_count++;
2244 #else
2245     g_timeout_add(G_PRIORITY_DEFAULT+10, graphics_sdl_idle, this);
2246 #endif
2247
2248     this->overlay_enable = 1;
2249
2250     this->aa = 1;
2251     if((attr=attr_search(attrs, NULL, attr_antialias)))
2252         this->aa = attr->u.num;
2253
2254     this->resize_callback_initial=1;
2255     return this;
2256 }
2257
2258 #ifdef USE_WEBOS
2259 /* ---------- SDL Eventhandling ---------- */
2260
2261 static Uint32
2262 sdl_timer_callback(Uint32 interval, void* param)
2263 {
2264     struct event_timeout *timeout=(struct event_timeout*)param;
2265
2266     dbg(1,"timer(%p) multi(%d) interval(%d) fired\n", param, timeout->multi, interval);
2267
2268     SDL_Event event;
2269     SDL_UserEvent userevent;
2270
2271     userevent.type = SDL_USEREVENT;
2272     userevent.code = SDL_USEREVENT_CODE_TIMER;
2273     userevent.data1 = timeout->cb;
2274     userevent.data2 = NULL;
2275
2276     event.type = SDL_USEREVENT;
2277     event.user = userevent;
2278
2279     SDL_PushEvent (&event);
2280
2281     if (timeout->multi==0) {
2282         g_free(timeout);
2283         timeout = NULL;
2284         return 0; // cancel timer
2285     }
2286     return interval; // reactivate timer
2287 }
2288
2289 /* SDL Mainloop */
2290
2291 static void
2292 event_sdl_main_loop_run(void)
2293 {
2294     PDL_ScreenTimeoutEnable(PDL_FALSE);
2295     graphics_sdl_idle(NULL);
2296     PDL_ScreenTimeoutEnable(PDL_TRUE);
2297 }
2298
2299 static void
2300 event_sdl_main_loop_quit(void)
2301 {
2302     quit_event_loop = 1;
2303 }
2304
2305 /* Watch */
2306
2307 static void
2308 event_sdl_watch_thread (GPtrArray *watch_list)
2309 {
2310     struct pollfd *pfds = g_new0 (struct pollfd, watch_list->len);
2311     struct event_watch *ew;
2312     int ret;
2313     int idx;
2314
2315     for (idx = 0; idx < watch_list->len; idx++ ) {
2316         ew = g_ptr_array_index (watch_list, idx);
2317         g_memmove (&pfds[idx], ew->pfd, sizeof(struct pollfd));
2318     }
2319
2320     while ((ret = ppoll(pfds, watch_list->len, NULL, NULL)) > 0) {
2321         for (idx = 0; idx < watch_list->len; idx++ ) {
2322             if (pfds[idx].revents == pfds[idx].events) {        /* The requested event happened, notify mainloop! */
2323                 ew = g_ptr_array_index (watch_list, idx);
2324                 dbg(1,"watch(%p) event(%d) encountered\n", ew, pfds[idx].revents);
2325
2326                 SDL_Event event;
2327                 SDL_UserEvent userevent;
2328
2329                 userevent.type = SDL_USEREVENT;
2330                 userevent.code = SDL_USEREVENT_CODE_WATCH;
2331                 userevent.data1 = ew->cb;
2332                 userevent.data2 = NULL;
2333
2334                 event.type = SDL_USEREVENT;
2335                 event.user = userevent;
2336
2337                 SDL_PushEvent (&event);
2338             }
2339         }
2340     }
2341
2342     g_free(pfds);
2343
2344     pthread_exit(0);
2345 }
2346
2347 static void
2348 event_sdl_watch_startthread(GPtrArray *watch_list)
2349 {
2350     dbg(1,"enter\n");
2351     if (sdl_watch_thread)
2352         event_sdl_watch_stopthread();
2353
2354     int ret;
2355     ret = pthread_create (&sdl_watch_thread, NULL, (void *)event_sdl_watch_thread, (void *)watch_list);
2356
2357     dbg_assert (ret == 0);
2358 }
2359
2360 static void
2361 event_sdl_watch_stopthread()
2362 {
2363     dbg(1,"enter\n");
2364     if (sdl_watch_thread) {
2365         /* Notify the watch thread that the list of FDs will change */
2366         pthread_kill(sdl_watch_thread, SIGUSR1);
2367         pthread_join(sdl_watch_thread, NULL);
2368         sdl_watch_thread = 0;
2369     }
2370 }
2371
2372 static struct event_watch *
2373 event_sdl_add_watch(void *fd, enum event_watch_cond cond, struct callback *cb)
2374 {
2375     dbg(1,"fd(%d) cond(%x) cb(%x)\n", fd, cond, cb);
2376
2377     event_sdl_watch_stopthread();
2378
2379     if (!sdl_watch_list)
2380         sdl_watch_list = g_ptr_array_new();
2381
2382     struct event_watch *new_ew = g_new0 (struct event_watch, 1);
2383     struct pollfd *pfd = g_new0 (struct pollfd, 1);
2384
2385     pfd->fd = (int) fd;
2386
2387     /* Modify watchlist here */
2388     switch (cond) {
2389         case event_watch_cond_read:
2390             pfd->events = POLLIN;
2391             break;
2392         case event_watch_cond_write:
2393             pfd->events = POLLOUT;
2394             break;
2395         case event_watch_cond_except:
2396             pfd->events = POLLERR|POLLHUP;
2397             break;
2398     }
2399
2400     new_ew->pfd = (struct pollfd*) pfd;
2401     new_ew->cb = cb;
2402
2403     g_ptr_array_add (sdl_watch_list, (gpointer)new_ew);
2404
2405     event_sdl_watch_startthread(sdl_watch_list);
2406
2407     return new_ew;
2408 }
2409
2410 static void
2411 event_sdl_remove_watch(struct event_watch *ew)
2412 {
2413     dbg(1,"enter %p\n",ew);
2414
2415     event_sdl_watch_stopthread();
2416
2417     g_ptr_array_remove (sdl_watch_list, ew);
2418     g_free (ew->pfd);
2419     g_free (ew);
2420
2421     if (sdl_watch_list->len > 0)
2422         event_sdl_watch_startthread(sdl_watch_list);
2423 }
2424
2425 /* Timeout */
2426
2427 static struct event_timeout *
2428 event_sdl_add_timeout(int timeout, int multi, struct callback *cb)
2429 {
2430     struct event_timeout * ret =  g_new0(struct event_timeout, 1);
2431     if(!ret)
2432         return ret;
2433     dbg(1,"timer(%p) multi(%d) interval(%d) cb(%p) added\n",ret, multi, timeout, cb);
2434     ret->multi = multi;
2435     ret->cb = cb;
2436     ret->id = SDL_AddTimer(timeout, sdl_timer_callback, ret);
2437
2438     return ret;
2439 }
2440
2441 static void
2442 event_sdl_remove_timeout(struct event_timeout *to)
2443 {
2444     dbg(2,"enter %p\n", to);
2445     if(to!=NULL)
2446     {
2447         int ret = to->id ? SDL_RemoveTimer(to->id) : SDL_TRUE;
2448         if (ret == SDL_FALSE) {
2449             dbg(0,"SDL_RemoveTimer (%p) failed\n", to->id);
2450         }
2451         else {
2452             g_free(to);
2453             dbg(1,"timer(%p) removed\n", to);
2454         }
2455     }
2456 }
2457
2458 /* Idle */
2459
2460 /* sort ptr_array by priority, increasing order */
2461 static gint
2462 sdl_sort_idle_tasks(gconstpointer parama, gconstpointer paramb)
2463 {
2464     struct idle_task *a = (struct idle_task *)parama;
2465     struct idle_task *b = (struct idle_task *)paramb;
2466     if (a->priority < b->priority)
2467         return -1;
2468     if (a->priority > b->priority)
2469         return 1;
2470     return 0;
2471 }
2472
2473 static struct event_idle *
2474 event_sdl_add_idle(int priority, struct callback *cb)
2475 {
2476     dbg(1,"add idle priority(%d) cb(%p)\n", priority, cb);
2477
2478     struct idle_task *task = g_new0(struct idle_task, 1);
2479     task->priority = priority;
2480     task->cb = cb;
2481
2482     g_ptr_array_add(idle_tasks, (gpointer)task);
2483
2484     if (idle_tasks->len < 2)
2485     {
2486         SDL_Event event;
2487         SDL_UserEvent userevent;
2488
2489         dbg(1,"poking eventloop because of new idle_events\n");
2490
2491         userevent.type = SDL_USEREVENT;
2492         userevent.code = SDL_USEREVENT_CODE_IDLE_EVENT;
2493         userevent.data1 = NULL;
2494         userevent.data2 = NULL;
2495
2496         event.type = SDL_USEREVENT;
2497         event.user = userevent;
2498
2499         SDL_PushEvent (&event);
2500     }
2501     else        // more than one entry => sort the list
2502         g_ptr_array_sort(idle_tasks, sdl_sort_idle_tasks);
2503
2504     return (struct event_idle *)task;
2505 }
2506
2507 static void
2508 event_sdl_remove_idle(struct event_idle *task)
2509 {
2510     dbg(1,"remove task(%p)\n", task);
2511     g_ptr_array_remove(idle_tasks, (gpointer)task);
2512 }
2513
2514 /* callback */
2515
2516 static void
2517 event_sdl_call_callback(struct callback_list *cbl)
2518 {
2519     dbg(1,"call_callback cbl(%p)\n",cbl);
2520     SDL_Event event;
2521     SDL_UserEvent userevent;
2522
2523     userevent.type = SDL_USEREVENT;
2524     userevent.code = SDL_USEREVENT_CODE_CALL_CALLBACK;
2525     userevent.data1 = cbl;
2526     userevent.data2 = NULL;
2527
2528     event.type = SDL_USEREVENT;
2529     event.user = userevent;
2530
2531     SDL_PushEvent (&event);
2532 }
2533
2534 static struct event_methods event_sdl_methods = {
2535     event_sdl_main_loop_run,
2536     event_sdl_main_loop_quit,
2537     event_sdl_add_watch,
2538     event_sdl_remove_watch,
2539     event_sdl_add_timeout,
2540     event_sdl_remove_timeout,
2541     event_sdl_add_idle,
2542     event_sdl_remove_idle,
2543     event_sdl_call_callback,
2544 };
2545
2546 static struct event_priv *
2547 event_sdl_new(struct event_methods* methods)
2548 {
2549     idle_tasks = g_ptr_array_new();
2550     *methods = event_sdl_methods;
2551     return NULL;
2552 }
2553
2554 /* ---------- SDL Eventhandling ---------- */
2555 #endif
2556
2557 void
2558 plugin_init(void)
2559 {
2560 #ifdef USE_WEBOS
2561     plugin_register_event_type("sdl", event_sdl_new);
2562 #endif
2563     plugin_register_graphics_type("sdl", graphics_sdl_new);
2564 }
2565
2566 // vim: sw=4 ts=8