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