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