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