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