Fix:graphics/sdl:Reverted to r3780 until issues on palm pre are solved
[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 "config.h"
22 #include "debug.h"
23 #include "point.h"
24 #include "graphics.h"
25 #include "color.h"
26 #include "plugin.h"
27 #include "window.h"
28 #include "navit.h"
29 #include "keys.h"
30 #include "item.h"
31 #include "attr.h"
32 #include "callback.h"
33 #include "navit/font/freetype/font_freetype.h"
34
35 #include <SDL/SDL.h>
36 #include <math.h>
37
38 #define RASTER
39 #undef SDL_SGE
40 #undef SDL_GFX
41 #undef ALPHA
42
43 #undef SDL_TTF
44 #define SDL_IMAGE
45 #undef LINUX_TOUCHSCREEN
46
47 #define DISPLAY_W 800
48 #define DISPLAY_H 600
49
50
51 #undef DEBUG
52 #undef PROFILE
53
54 #define OVERLAY_MAX 16
55
56 #ifdef RASTER
57 #include "raster.h"
58 #endif
59
60 #ifdef SDL_SGE
61 #include <SDL/sge.h>
62 #endif
63
64 #ifdef SDL_GFX
65 #include <SDL/SDL_gfxPrimitives.h>
66 #endif
67
68 #ifdef SDL_TTF
69 #include <SDL/SDL_ttf.h>
70 #else
71 #include <fontconfig/fontconfig.h>
72 #include <ft2build.h>
73 #include FT_FREETYPE_H
74 #include <freetype/ftglyph.h>
75 #endif
76 #include <event.h>
77
78 #ifdef SDL_IMAGE
79 #include <SDL/SDL_image.h>
80 #endif
81
82 #ifdef LINUX_TOUCHSCREEN
83 /* we use Linux evdev directly for the touchscreen.  */
84 #include <sys/types.h>
85 #include <sys/stat.h>
86 #include <fcntl.h>
87 #include <linux/input.h>
88 #endif
89
90 #include <alloca.h>
91
92 #ifdef PROFILE
93 #include <sys/time.h>
94 #include <time.h>
95 #endif
96
97
98 /* TODO: union overlay + non-overlay to reduce size */
99 struct graphics_priv;
100 struct graphics_priv {
101     SDL_Surface *screen;
102     int aa;
103     /* video modes */
104     uint32_t video_flags;
105     int video_bpp;
106
107     /* <overlay> */
108     int overlay_mode;
109     int overlay_x;
110     int overlay_y;
111     struct graphics_priv *overlay_parent;
112     int overlay_idx;
113     /* </overlay> */
114
115     /* <main> */
116     struct graphics_priv *overlay_array[OVERLAY_MAX];
117     int overlay_enable;
118     enum draw_mode_num draw_mode;
119
120         int resize_callback_initial;
121
122     struct navit *nav;
123     struct callback_list *cbl;
124
125 #ifdef LINUX_TOUCHSCREEN
126     int ts_fd;
127     int32_t ts_hit;
128     uint32_t ts_x;
129     uint32_t ts_y;
130 #endif
131
132 #ifndef SDL_TTF
133     FT_Library library;
134 #endif
135
136 #ifdef PROFILE
137     struct timeval draw_begin_tv;
138     unsigned long draw_time_peak;
139 #endif
140   struct font_freetype_methods freetype_methods;
141     /* </main> */
142 };
143
144 static int dummy;
145
146
147 struct graphics_font_priv {
148 #ifdef SDL_TTF
149     TTF_Font *font;
150 #else
151     FT_Face face;
152 #endif
153 };
154
155 struct graphics_gc_priv {
156     struct graphics_priv *gr;
157     Uint8 fore_r;
158     Uint8 fore_g;
159     Uint8 fore_b;
160     Uint8 fore_a;
161     Uint8 back_r;
162     Uint8 back_g;
163     Uint8 back_b;
164     Uint8 back_a;
165     int linewidth;
166 };
167
168 struct graphics_image_priv {
169     SDL_Surface *img;
170 };
171
172
173 #ifdef LINUX_TOUCHSCREEN
174 static int input_ts_exit(struct graphics_priv *gr);
175 #endif
176
177 static void
178 graphics_destroy(struct graphics_priv *gr)
179 {
180     dbg(0, "graphics_destroy %p %u\n", gr, gr->overlay_mode);
181
182     if(gr->overlay_mode)
183     {
184         SDL_FreeSurface(gr->screen);
185         gr->overlay_parent->overlay_array[gr->overlay_idx] = NULL;
186     }
187     else
188     {
189 #ifdef SDL_TTF
190         TTF_Quit();
191 #else
192         FT_Done_FreeType(gr->library);
193         FcFini();
194 #endif
195 #ifdef LINUX_TOUCHSCREEN
196         input_ts_exit(gr);
197 #endif
198         SDL_Quit();
199     }
200
201     g_free(gr);
202 }
203
204 /* graphics_font */
205 static char *fontfamilies[]={
206         "Liberation Mono",
207         "Arial",
208         "DejaVu Sans",
209         "NcrBI4nh",
210         "luximbi",
211         "FreeSans",
212         NULL,
213 };
214
215 static void font_destroy(struct graphics_font_priv *gf)
216 {
217 #ifdef SDL_TTF
218 #else
219     FT_Done_Face(gf->face);
220 #endif
221     g_free(gf);
222 }
223
224 static struct graphics_font_methods font_methods = {
225         font_destroy
226 };
227
228 /* graphics_gc */
229
230 static void
231 gc_destroy(struct graphics_gc_priv *gc)
232 {
233     g_free(gc);
234 }
235
236 static void
237 gc_set_linewidth(struct graphics_gc_priv *gc, int w)
238 {
239 #ifdef DEBUG
240     printf("gc_set_linewidth %p %d\n", gc, w);
241 #endif
242     gc->linewidth = w;
243 }
244
245 static void
246 gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
247 {
248     /* TODO */
249 }
250
251 static void
252 gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
253 {
254 #ifdef DEBUG
255     printf("gc_set_foreground: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
256 #endif
257     gc->fore_r = c->r/256;
258     gc->fore_g = c->g/256;
259     gc->fore_b = c->b/256;
260     gc->fore_a = c->a/256;
261 }
262
263 static void
264 gc_set_background(struct graphics_gc_priv *gc, struct color *c)
265 {
266 #ifdef DEBUG
267     printf("gc_set_background: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
268 #endif
269     gc->back_r = c->r/256;
270     gc->back_g = c->g/256;
271     gc->back_b = c->b/256;
272     gc->back_a = c->a/256;
273 }
274
275 static struct graphics_gc_methods gc_methods = {
276         gc_destroy,
277         gc_set_linewidth,
278         gc_set_dashes,  
279         gc_set_foreground,      
280         gc_set_background       
281 };
282
283 static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
284 {
285     struct graphics_gc_priv *gc=g_new0(struct graphics_gc_priv, 1);
286         *meth=gc_methods;
287     gc->gr=gr;
288     gc->linewidth=1; /* upper layer should override anyway? */
289         return gc;
290 }
291
292
293 #if 0 /* unused by core? */
294 static void image_destroy(struct graphics_image_priv *gi)
295 {
296 #ifdef SDL_IMAGE
297     SDL_FreeSurface(gi->img);
298     g_free(gi);
299 #endif
300 }
301
302 static struct graphics_image_methods gi_methods =
303 {
304     image_destroy
305 };
306 #endif
307
308 static struct graphics_image_priv *
309 image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name, int *w, int *h,
310           struct point *hot, int rotation)
311 {
312 #ifdef SDL_IMAGE
313     struct graphics_image_priv *gi;
314
315     /* FIXME: meth is not used yet.. so gi leaks. at least xpm is small */
316
317     gi = g_new0(struct graphics_image_priv, 1);
318     gi->img = IMG_Load(name);
319     if(gi->img)
320     {
321         /* TBD: improves blit performance? */
322 #if !SDL_VERSION_ATLEAST(1,3,0)
323         SDL_SetColorKey(gi->img, SDL_RLEACCEL, gi->img->format->colorkey);
324 #endif
325         *w=gi->img->w;
326         *h=gi->img->h;
327         hot->x=*w/2;
328         hot->y=*h/2;
329     }
330     else
331     {
332         /* TODO: debug "colour parse errors" on xpm */
333         printf("graphics_sdl: image_new on '%s' failed: %s\n", name, IMG_GetError());
334         g_free(gi);
335         gi = NULL;
336     }
337
338     return gi;
339 #else
340     return NULL;
341 #endif
342 }
343
344 static void
345 image_free(struct graphics_priv *gr, struct graphics_image_priv * gi)
346 {
347 #ifdef SDL_IMAGE
348     SDL_FreeSurface(gi->img);
349     g_free(gi);
350 #endif
351 }
352
353 static void
354 get_text_bbox(struct graphics_priv *gr, struct graphics_font_priv *font, char *text, int dx, int dy, struct point *ret, int estimate)
355 {
356         char *p=text;
357         FT_BBox bbox;
358         FT_UInt  glyph_index;
359         FT_GlyphSlot  slot = font->face->glyph;  // a small shortcut
360         FT_Glyph glyph;
361         FT_Matrix matrix;
362         FT_Vector pen;
363         pen.x = 0 * 64;
364         pen.y = 0 * 64;
365         matrix.xx = dx;
366         matrix.xy = dy;
367         matrix.yx = -dy;
368         matrix.yy = dx;
369         int n,len,x=0,y=0;
370
371         bbox.xMin = bbox.yMin = 32000;
372         bbox.xMax = bbox.yMax = -32000; 
373         FT_Set_Transform( font->face, &matrix, &pen );
374         len=g_utf8_strlen(text, -1);
375         for ( n = 0; n < len; n++ ) {
376                 FT_BBox glyph_bbox;
377                 glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p));
378                 p=g_utf8_next_char(p);
379                 FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT );
380                 FT_Get_Glyph(font->face->glyph, &glyph);
381                 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox );
382                 FT_Done_Glyph(glyph);
383                 glyph_bbox.xMin += x >> 6;
384                 glyph_bbox.xMax += x >> 6;
385                 glyph_bbox.yMin += y >> 6;
386                 glyph_bbox.yMax += y >> 6;
387                 x += slot->advance.x;
388                 y -= slot->advance.y;
389                 if ( glyph_bbox.xMin < bbox.xMin )
390                         bbox.xMin = glyph_bbox.xMin;
391                 if ( glyph_bbox.yMin < bbox.yMin )
392                         bbox.yMin = glyph_bbox.yMin;
393                 if ( glyph_bbox.xMax > bbox.xMax )
394                         bbox.xMax = glyph_bbox.xMax;
395                 if ( glyph_bbox.yMax > bbox.yMax )
396                         bbox.yMax = glyph_bbox.yMax;
397         } 
398         if ( bbox.xMin > bbox.xMax ) {
399                 bbox.xMin = 0;
400                 bbox.yMin = 0;
401                 bbox.xMax = 0;
402                 bbox.yMax = 0;
403         }
404         ret[0].x=bbox.xMin;
405         ret[0].y=-bbox.yMin;
406         ret[1].x=bbox.xMin;
407         ret[1].y=-bbox.yMax;
408         ret[2].x=bbox.xMax;
409         ret[2].y=-bbox.yMax;
410         ret[3].x=bbox.xMax;
411         ret[3].y=-bbox.yMin;
412 }
413
414 static void
415 draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
416 {
417   if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
418     {
419       return;
420     }
421
422     Sint16 *vx, *vy;
423     Sint16 x, y;
424     int i;
425
426     vx = alloca(count * sizeof(Sint16));
427     vy = alloca(count * sizeof(Sint16));
428
429     for(i = 0; i < count; i++)
430     {
431         x = (Sint16)p[i].x;
432         y = (Sint16)p[i].y;
433
434 #if 0
435         if(x < 0)
436         {
437             x = 0;
438         }
439         if(y < 0)
440         {
441             y = 0;
442         }
443 #endif
444
445         vx[i] = x;
446         vy[i] = y;
447
448 #ifdef DEBUG
449         printf("draw_polygon: %p %i %d,%d\n", gc, i, p[i].x, p[i].y);
450 #endif
451     }
452
453 #ifdef RASTER
454     if(gr->aa)
455     {
456         raster_aapolygon(gr->screen, count, vx, vy,
457                        SDL_MapRGBA(gr->screen->format,
458                                   gc->fore_r,
459                                   gc->fore_g,
460                                   gc->fore_b,
461                                   gc->fore_a));
462     }
463     else
464     {
465         raster_polygon(gr->screen, count, vx, vy,
466                        SDL_MapRGBA(gr->screen->format,
467                                   gc->fore_r,
468                                   gc->fore_g,
469                                   gc->fore_b,
470                                   gc->fore_a));
471     }
472 #else
473 #ifdef SDL_SGE
474 #ifdef ALPHA
475     sge_FilledPolygonAlpha(gr->screen, count, vx, vy,
476                            SDL_MapRGB(gr->screen->format,
477                                       gc->fore_r,
478                                       gc->fore_g,
479                                       gc->fore_b),
480                            gc->fore_a);
481 #else
482 #ifdef ANTI_ALIAS
483     sge_AAFilledPolygon(gr->screen, count, vx, vy,
484                            SDL_MapRGB(gr->screen->format,
485                                       gc->fore_r,
486                                       gc->fore_g,
487                                       gc->fore_b));
488 #else
489     sge_FilledPolygon(gr->screen, count, vx, vy,
490                            SDL_MapRGB(gr->screen->format,
491                                       gc->fore_r,
492                                       gc->fore_g,
493                                       gc->fore_b));
494 #endif
495 #endif
496 #else
497     filledPolygonRGBA(gr->screen, vx, vy, count,
498                       gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
499 #endif
500 #endif
501 }
502
503
504
505 static void
506 draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
507 {
508   if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
509     {
510       return;
511     }
512
513 #ifdef DEBUG
514         printf("draw_rectangle: %d %d %d %d r=%d g=%d b=%d a=%d\n", p->x, p->y, w, h,
515                gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
516 #endif
517     if(w > gr->screen->w)
518     {
519         w = gr->screen->w;
520     }
521     if(h > gr->screen->h)
522     {
523         h = gr->screen->h;
524     }
525
526 #ifdef RASTER
527     raster_rect(gr->screen, p->x, p->y, w, h,
528                 SDL_MapRGBA(gr->screen->format,
529                            gc->fore_r,
530                            gc->fore_g,
531                            gc->fore_b,
532                            gc->fore_a));
533 #else
534 #ifdef SDL_SGE
535 #ifdef ALPHA
536     sge_FilledRectAlpha(gr->screen, p->x, p->y, p->x + w, p->y + h,
537                         SDL_MapRGB(gr->screen->format,
538                                    gc->fore_r,
539                                    gc->fore_g,
540                                    gc->fore_b),
541                         gc->fore_a);
542 #else
543     /* no AA -- should use poly instead for that */
544     sge_FilledRect(gr->screen, p->x, p->y, p->x + w, p->y + h,
545                         SDL_MapRGB(gr->screen->format,
546                                    gc->fore_r,
547                                    gc->fore_g,
548                                    gc->fore_b));
549 #endif
550 #else
551     boxRGBA(gr->screen, p->x, p->y, p->x + w, p->y + h,
552             gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
553 #endif
554 #endif
555
556 }
557
558 static void
559 draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
560 {
561   if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
562     {
563       return;
564     }
565
566 #if 0
567         if(gc->fore_a != 0xff)
568         {
569         dbg(0, "%d %d %d %u %u:%u:%u:%u\n", p->x, p->y, r, gc->linewidth,
570             gc->fore_a, gc->fore_r, gc->fore_g, gc->fore_b);
571         }
572 #endif
573
574     /* FIXME: does not quite match gtk */
575
576     /* hack for osd compass.. why is this needed!? */
577     if(gr->overlay_mode)
578     {
579         r = r / 2;
580     }
581
582 #ifdef RASTER
583         if(gr->aa)
584         {
585             raster_aacircle(gr->screen, p->x, p->y, r,
586                             SDL_MapRGBA(gr->screen->format,
587                                        gc->fore_r,
588                                        gc->fore_g,
589                                        gc->fore_b,
590                                        gc->fore_a));
591         }
592         else
593         {
594             raster_circle(gr->screen, p->x, p->y, r,
595                           SDL_MapRGBA(gr->screen->format,
596                                      gc->fore_r,
597                                      gc->fore_g,
598                                      gc->fore_b,
599                                      gc->fore_a));
600         }
601 #else
602 #ifdef SDL_SGE
603 #ifdef ALPHA
604         sge_FilledCircleAlpha(gr->screen, p->x, p->y, r,
605                          SDL_MapRGB(gr->screen->format,
606                                     gc->fore_r, gc->fore_g, gc->fore_b),
607                          gc->fore_a);
608 #else
609 #ifdef ANTI_ALIAS
610         sge_AAFilledCircle(gr->screen, p->x, p->y, r,
611                          SDL_MapRGB(gr->screen->format,
612                                     gc->fore_r, gc->fore_g, gc->fore_b));
613 #else
614         sge_FilledCircle(gr->screen, p->x, p->y, r,
615                          SDL_MapRGB(gr->screen->format,
616                                     gc->fore_r, gc->fore_g, gc->fore_b));
617 #endif
618 #endif
619 #else
620 #ifdef ANTI_ALIAS
621         aacircleRGBA(gr->screen, p->x, p->y, r,
622                    gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
623 #else
624         filledCircleRGBA(gr->screen, p->x, p->y, r,
625                          gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
626 #endif
627 #endif
628 #endif
629 }
630
631
632 static void
633 draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
634 {
635   if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
636     {
637       return;
638     }
639
640     /* you might expect lines to be simpler than the other shapes.
641        but, that would be wrong. 1 line can generate 1 polygon + 2 circles
642        and even worse, we have to calculate their parameters!
643        go dust off your trigonometry hat.
644     */
645 #if 0
646     int i, l, x_inc, y_inc, lw;
647
648     lw = gc->linewidth;
649
650     for(i = 0; i < count-1; i++)
651     {
652 #ifdef DEBUG
653         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);
654 #endif
655         for(l = 0; l < lw; l++)
656         {
657             /* FIXME: center? */
658 #if 1
659             if(p[i].x != p[i+1].x)
660             {
661                 x_inc = l - (lw/2);
662             }
663             else
664             {
665                 x_inc = 0;
666             }
667
668             if(p[i].y != p[i+1].y)
669             {
670                 y_inc = l - (lw/2);
671             }
672             else
673             {
674                 y_inc = 0;
675             }
676 #else
677             x_inc = 0;
678             y_inc = 0;
679 #endif
680
681 #ifdef ANTI_ALIAS
682             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,
683                      gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
684 #else
685             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,
686                      gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
687 #endif
688         }
689     }
690 #else
691     /* sort of based on graphics_opengl.c::draw_lines */
692     /* FIXME: should honor ./configure flag for no fp.
693               this could be 100% integer code pretty easily,
694               except that i am lazy
695     */
696     struct point vert[4];
697     int lw = gc->linewidth;
698     //int lw = 1;
699     int i;
700
701     for(i = 0; i < count-1; i++)
702     {
703                 float dx=p[i+1].x-p[i].x;
704                 float dy=p[i+1].y-p[i].y;
705
706 #if 0
707                 float cx=(p[i+1].x+p[i].x)/2;
708                 float cy=(p[i+1].y+p[i].y)/2;
709 #endif
710
711         float angle;
712
713         int x_lw_adj, y_lw_adj;
714
715         if(lw == 1)
716         {
717 #ifdef RASTER
718             if(gr->aa)
719             {
720                 raster_aaline(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
721                          SDL_MapRGBA(gr->screen->format,
722                                     gc->fore_r,
723                                     gc->fore_g,
724                                     gc->fore_b,
725                                     gc->fore_a));
726             }
727             else
728             {
729                 raster_line(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
730                          SDL_MapRGBA(gr->screen->format,
731                                     gc->fore_r,
732                                     gc->fore_g,
733                                     gc->fore_b,
734                                     gc->fore_a));
735             }
736 #else
737 #ifdef SDL_SGE
738 #ifdef ALPHA
739             sge_LineAlpha(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
740                      SDL_MapRGB(gr->screen->format,
741                                 gc->fore_r, gc->fore_g, gc->fore_b),
742                      gc->fore_a);
743 #else
744 #ifdef ANTI_ALIAS
745             sge_AALine(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
746                      SDL_MapRGB(gr->screen->format,
747                                 gc->fore_r, gc->fore_g, gc->fore_b));
748 #else
749             sge_Line(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
750                      SDL_MapRGB(gr->screen->format,
751                                 gc->fore_r, gc->fore_g, gc->fore_b));
752 #endif
753 #endif
754 #else
755 #ifdef ANTI_ALIAS
756             aalineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
757                      gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
758 #else
759             lineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
760                      gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
761 #endif
762 #endif
763 #endif
764         }
765         else
766         {
767             /* there is probably a much simpler way but this works ok */
768
769             /* FIXME: float + double mixture */
770             /* FIXME: lrint(round())? */
771             if(dy == 0.0)
772             {
773                 angle = 0.0;
774                 x_lw_adj = 0;
775                 y_lw_adj = round((float)lw/2.0);
776             }
777             else if(dx == 0.0)
778             {
779                 angle = 0.0;
780                 x_lw_adj = round((float)lw/2.0);
781                 y_lw_adj = 0;
782             }
783             else
784             {
785                 angle = (M_PI/2.0) - atan(abs(dx)/abs(dy));
786                 x_lw_adj = round(sin(angle)*(float)lw/2.0);
787                 y_lw_adj = round(cos(angle)*(float)lw/2.0);
788                 if((x_lw_adj < 0) || (y_lw_adj < 0))
789                 {
790                     printf("i=%d\n", i);
791                     printf("   %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y);
792                     printf("   lw=%d angle=%f\n", lw, 180.0 * angle / M_PI);
793                     printf("   x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj);
794                 }
795             }
796
797             if(p[i+1].x > p[i].x)
798             {
799                 x_lw_adj = -x_lw_adj;
800             }
801             if(p[i+1].y > p[i].y)
802             {
803                 y_lw_adj = -y_lw_adj;
804             }
805
806 #if 0
807             if(((y_lw_adj*y_lw_adj)+(x_lw_adj*x_lw_adj)) != (lw/2)*(lw/2))
808             {
809                 printf("i=%d\n", i);
810                 printf("   %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y);
811                 printf("   lw=%d angle=%f\n", lw, 180.0 * angle / M_PI);
812                 printf("   x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj);
813             }
814 #endif
815
816             /* FIXME: draw a circle/square if p[i]==p[i+1]? */
817             /* FIXME: clipping, check for neg values. hoping sdl-gfx does this */
818             vert[0].x = p[i].x + x_lw_adj;
819             vert[0].y = p[i].y - y_lw_adj;
820             vert[1].x = p[i].x - x_lw_adj;
821             vert[1].y = p[i].y + y_lw_adj;
822             vert[2].x = p[i+1].x - x_lw_adj;
823             vert[2].y = p[i+1].y + y_lw_adj;
824             vert[3].x = p[i+1].x + x_lw_adj;
825             vert[3].y = p[i+1].y - y_lw_adj;
826
827             draw_polygon(gr, gc, vert, 4);
828
829             /* draw small circles at the ends. this looks better than nothing, and slightly
830              * better than the triangle used by graphics_opengl, but is more expensive.
831              * should have an ifdef/xml attr?
832             */
833
834             /* FIXME: should just draw a half circle */
835
836             /* now some circular endcaps, if the width is over 2 */ 
837             if(lw > 2)
838             {
839                 if(i == 0)
840                 {
841                     draw_circle(gr, gc, &p[i], lw/2);
842                 }
843                 /* we truncate on the divide on purpose, so we don't go outside the line */
844                 draw_circle(gr, gc, &p[i+1], lw/2);
845             }
846         }
847     }
848 #endif
849 }
850 static void
851 display_text_draw(struct font_freetype_text *text,
852                   struct graphics_priv *gr, struct graphics_gc_priv *fg,
853                   struct graphics_gc_priv *bg, int color, struct point *p)
854 {
855     int i, x, y, stride;
856     struct font_freetype_glyph *g, **gp;
857     unsigned char *shadow, *glyph;
858     struct color transparent = { 0x0000, 0x0000, 0x0000, 0x0000 };
859     struct color black =
860         { fg->fore_r * 255, fg->fore_g * 255, fg->fore_b * 255, fg->fore_a * 255
861     };
862     struct color white = { 0xffff, 0xffff, 0xffff, 0xffff };
863
864     if (bg) {
865         if (COLOR_IS_WHITE(black) && COLOR_IS_BLACK(white)) {
866             black.r = 65535;
867             black.g = 65535;
868             black.b = 65535;
869             black.a = 65535;
870
871             white.r = 0;
872             white.g = 0;
873             white.b = 0;
874             white.a = 65535;
875         } else if (COLOR_IS_BLACK(black) && COLOR_IS_WHITE(white)) {
876             white.r = 65535;
877             white.g = 65535;
878             white.b = 65535;
879             white.a = 65535;
880
881             black.r = 0;
882             black.g = 0;
883             black.b = 0;
884             black.a = 65535;
885         } else {
886             white.r = bg->fore_r * 255;
887             white.g = bg->fore_g * 255;
888             white.b = bg->fore_b * 255;
889             white.a = bg->fore_a * 255;
890         }
891     } else {
892         white.r = 0;
893         white.g = 0;
894         white.b = 0;
895         white.a = 0;
896     }
897
898
899     gp = text->glyph;
900     i = text->glyph_count;
901     x = p->x << 6;
902     y = p->y << 6;
903     while (i-- > 0) {
904         g = *gp++;
905         if (g->w && g->h && bg) {
906             stride = (g->w + 2) * 4;
907             if (color) {
908                 shadow = g_malloc(stride * (g->h + 2));
909                 gr->freetype_methods.get_shadow(g, shadow, 32, stride, &white, &transparent);
910
911                 SDL_Surface *glyph_surface =
912                     SDL_CreateRGBSurfaceFrom(shadow, g->w + 2, g->h + 2,
913                                              32,
914                                              stride, 
915                                              0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
916                 if (glyph_surface) {
917                     SDL_Rect r;
918                     r.x = (x + g->x) >> 6;
919                     r.y = (y + g->y) >> 6;
920                     r.w = g->w + 2;
921                     r.h = g->h + 2;
922
923                     SDL_BlitSurface(glyph_surface, NULL, gr->screen, &r);
924                     SDL_FreeSurface(glyph_surface);
925                 }
926                 g_free(shadow);
927             }
928         }
929         x += g->dx;
930         y += g->dy;
931     }
932
933     x = p->x << 6;
934     y = p->y << 6;
935     gp = text->glyph;
936     i = text->glyph_count;
937     while (i-- > 0) {
938         g = *gp++;
939         if (g->w && g->h) {
940             if (color) {
941                 stride = g->w;
942                 if (bg) {
943                     glyph = g_malloc(stride * g->h * 4);
944                     gr->freetype_methods.get_glyph(g, glyph, 32,
945                                                    stride * 4, &black,
946                                                    &white, &transparent);
947                     SDL_Surface *glyph_surface =
948                         SDL_CreateRGBSurfaceFrom(glyph, g->w, g->h, 32,
949                                                  stride * 4, 
950                                                  0x000000ff,0x0000ff00, 0x00ff0000,0xff000000);
951                     if (glyph_surface) {
952                         SDL_Rect r;
953                         r.x = (x + g->x) >> 6;
954                         r.y = (y + g->y) >> 6;
955                         r.w = g->w;
956                         r.h = g->h;
957
958                         SDL_BlitSurface(glyph_surface, NULL, gr->screen,&r);
959                         SDL_FreeSurface(glyph_surface);
960                     }
961                     g_free(glyph);
962                 }
963                 stride *= 4;
964                 glyph = g_malloc(stride * g->h);
965                 gr->freetype_methods.get_glyph(g, glyph, 32, stride,
966                                                &black, &white,
967                                                &transparent);
968                 //convert ABGR to RGBA
969                 int j;
970                 unsigned char *pGlyph = glyph;
971                 for (j = 0; j < g->w * g->h; ++j) {
972                     unsigned char tmp;
973                     tmp = *(pGlyph + 0);
974                     *(pGlyph + 0) = *(pGlyph + 2);
975                     *(pGlyph + 2) = tmp;
976                     pGlyph += 4;
977                 }
978                 SDL_Surface *glyph_surface =
979                     SDL_CreateRGBSurfaceFrom(glyph, g->w, g->h, 32, 
980                                                 stride,
981                                                 0x000000ff,0x0000ff00,0x00ff0000,0xff000000);
982                 if (glyph_surface) {
983                     SDL_Rect r;
984                     r.x = (x + g->x) >> 6;
985                     r.y = (y + g->y) >> 6;
986                     r.w = g->w;
987                     r.h = g->h;
988
989                     SDL_BlitSurface(glyph_surface, NULL, gr->screen, &r);
990                     SDL_FreeSurface(glyph_surface);
991                 }
992
993                 int ii, jj;
994                 for (jj = 0; jj < g->h; ++jj) {
995                     for (ii = 0; ii < g->w; ++ii) {
996                         int sx = (x + g->x) >> 6;
997                         int sy = (y + g->y) >> 6;
998                         sx = sx < 0 ? 0 : sx;
999                         sy = sy < 0 ? 0 : sy;
1000                         int poff =
1001                             gr->screen->w * ((jj) + sy) + ((ii) + sx);
1002                         poff *= gr->screen->format->BytesPerPixel;
1003                     }
1004                 }
1005                 g_free(glyph);
1006             }
1007         }
1008         x += g->dx;
1009         y += g->dy;
1010     }
1011 }
1012
1013 static void
1014 draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1015           struct graphics_gc_priv *bg, struct graphics_font_priv *font,
1016           char *text, struct point *p, int dx, int dy)
1017 {
1018     if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable)
1019         || (gr->overlay_parent && gr->overlay_parent->overlay_enable
1020             && !gr->overlay_enable)) {
1021         return;
1022     }
1023
1024     struct font_freetype_text *t;
1025     int color = 1;
1026
1027     if (!font) {
1028         dbg(0, "no font, returning\n");
1029         return;
1030     }
1031     t = gr->freetype_methods.text_new(text,
1032                                       (struct font_freetype_font *) font,
1033                                       dx, dy);
1034
1035     struct point p_eff;
1036     p_eff.x = p->x;
1037     p_eff.y = p->y;
1038
1039     display_text_draw(t, gr, fg, bg, color, &p_eff);
1040     gr->freetype_methods.text_destroy(t);
1041 }
1042
1043 static void
1044 draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
1045 {
1046   if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
1047     {
1048       return;
1049     }
1050
1051 #ifdef SDL_IMAGE
1052     SDL_Rect r;
1053
1054     r.x = p->x;
1055     r.y = p->y;
1056     r.w = img->img->w;
1057     r.h = img->img->h;
1058
1059     SDL_BlitSurface(img->img, NULL, gr->screen, &r);
1060 #endif
1061 }
1062
1063 static void
1064 draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
1065 {
1066     /* TODO */
1067 }
1068
1069 static void
1070 draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
1071 {
1072 #ifdef DEBUG
1073     printf("draw_restore\n");
1074 #endif
1075 }
1076
1077 static void
1078 background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
1079 {
1080 #ifdef DEBUG
1081     printf("background_gc\n");
1082 #endif
1083 }
1084
1085
1086 static void
1087 draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
1088 {
1089 #ifdef PROFILE
1090     struct timeval now;
1091     unsigned long elapsed;
1092 #endif
1093     struct graphics_priv *ov;
1094     SDL_Rect rect;
1095     int i;
1096
1097     if(gr->overlay_mode)
1098     {
1099         /* will be drawn below */
1100     }
1101     else
1102     {
1103 #ifdef DEBUG
1104         printf("draw_mode: %d\n", mode);
1105 #endif
1106
1107 #ifdef PROFILE
1108         if(mode == draw_mode_begin)
1109         {
1110             gettimeofday(&gr->draw_begin_tv, NULL);
1111         }
1112 #endif
1113
1114         if(mode == draw_mode_end)
1115         {
1116             if((gr->draw_mode == draw_mode_begin) && gr->overlay_enable)
1117             {
1118                 for(i = 0; i < OVERLAY_MAX; i++)
1119                 {
1120                     ov = gr->overlay_array[i];
1121                     if(ov && ov->overlay_enable)
1122                     {
1123                         rect.x = ov->overlay_x;
1124                         if(rect.x<0) rect.x += gr->screen->w;
1125                         rect.y = ov->overlay_y;
1126                         if(rect.y<0) rect.y += gr->screen->h;
1127                         rect.w = ov->screen->w;
1128                         rect.h = ov->screen->h;
1129                         SDL_BlitSurface(ov->screen, NULL,
1130                                         gr->screen, &rect);
1131                     }
1132                 }
1133             }
1134
1135             SDL_Flip(gr->screen);
1136
1137 #ifdef PROFILE
1138             gettimeofday(&now, NULL);
1139             elapsed = 1000000 * (now.tv_sec - gr->draw_begin_tv.tv_sec);
1140             elapsed += (now.tv_usec - gr->draw_begin_tv.tv_usec);
1141             if(elapsed >= gr->draw_time_peak)
1142             {
1143                dbg(0, "draw elapsed %u usec\n", elapsed);
1144                gr->draw_time_peak = elapsed;
1145             }
1146 #endif
1147         }
1148
1149         gr->draw_mode = mode;
1150     }
1151 }
1152
1153 static void overlay_disable(struct graphics_priv *gr, int disable)
1154 {
1155     gr->overlay_enable = !disable;
1156     struct graphics_priv *curr_gr = gr;
1157     if(gr->overlay_parent) {
1158       curr_gr = gr->overlay_parent;
1159     }
1160     draw_mode(curr_gr,draw_mode_end);
1161 }
1162
1163 static struct graphics_priv *
1164 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h, int alpha, int wraparound);
1165
1166 static int window_fullscreen(struct window *win, int on)
1167 {
1168         struct graphics_priv *gr=(struct graphics_priv *)win->priv;
1169
1170         /* Update video flags */
1171         if(on) {
1172                 gr->video_flags |= SDL_FULLSCREEN;
1173         } else {
1174                 gr->video_flags &= ~SDL_FULLSCREEN;
1175         }
1176
1177         /* Update video mode */
1178         gr->screen = SDL_SetVideoMode(gr->screen->w, gr->screen->h, gr->video_bpp, gr->video_flags);
1179         if(gr->screen == NULL) {
1180                 navit_destroy(gr->nav);
1181         } 
1182         else {
1183                 callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
1184         }
1185         return 1;
1186 }
1187
1188 static void *
1189 get_data(struct graphics_priv *this, char *type)
1190 {
1191         if(strcmp(type, "window") == 0) {
1192                 struct window *win;
1193                 win=g_new(struct window, 1);
1194                 win->priv=this;
1195                 win->fullscreen=window_fullscreen;
1196                 win->disable_suspend=NULL;
1197                 return win;
1198         } else {
1199                 return &dummy;
1200         }
1201 }
1202
1203 static void draw_drag(struct graphics_priv *gr, struct point *p)
1204 {
1205         if(p) {
1206             gr->overlay_x = p->x;
1207             gr->overlay_y = p->y;
1208         }
1209 }
1210
1211 static struct graphics_methods graphics_methods = {
1212         graphics_destroy,
1213         draw_mode,
1214         draw_lines,
1215         draw_polygon,
1216         draw_rectangle,
1217         draw_circle,
1218         draw_text,
1219         draw_image,
1220         draw_image_warp,
1221         draw_restore,
1222         draw_drag,
1223         NULL,
1224         gc_new,
1225         background_gc,
1226         overlay_new,
1227         image_new,
1228         get_data,
1229 //      register_resize_callback,
1230 //      register_button_callback,
1231 //      register_motion_callback,
1232         image_free,
1233         get_text_bbox,
1234         overlay_disable,
1235 //      register_keypress_callback
1236 };
1237
1238 static struct graphics_priv *
1239 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h,int alpha, int wraparound)
1240 {
1241         struct graphics_priv *ov;
1242         Uint32 rmask, gmask, bmask, amask;
1243         int i;
1244
1245         for(i = 0; i < OVERLAY_MAX; i++)
1246         {
1247                 if(gr->overlay_array[i] == NULL)
1248                 {
1249                         break;
1250                 }
1251         }
1252         if(i == OVERLAY_MAX)
1253         {
1254                 dbg(0, "too many overlays! increase OVERLAY_MAX\n");
1255                 return NULL;
1256         }
1257
1258         dbg(1, "overlay_new %d %d %d %u %u (%x, %x, %x ,%x, %d)\n", i,
1259                         p->x,
1260                         p->y,
1261                         w,
1262                         h,
1263                         gr->screen->format->Rmask,
1264                         gr->screen->format->Gmask,
1265                         gr->screen->format->Bmask,
1266                         gr->screen->format->Amask,
1267                         gr->screen->format->BitsPerPixel
1268            );
1269
1270         ov = g_new0(struct graphics_priv, 1);
1271
1272         switch(gr->screen->format->BitsPerPixel) {
1273         case 8:
1274                 rmask = 0xc0;
1275                 gmask = 0x30;
1276                 bmask = 0x0c;
1277                 amask = 0x03;
1278                 break;
1279         case 16:
1280                 rmask = 0xf000;
1281                 gmask = 0x0f00;
1282                 bmask = 0x00f0;
1283                 amask = 0x000f;
1284                 break;
1285         case 32:
1286                 rmask = 0xff000000;
1287                 gmask = 0x00ff0000;
1288                 bmask = 0x0000ff00;
1289                 amask = 0x000000ff;
1290                 break;
1291         default:
1292                 rmask = gr->screen->format->Rmask;
1293                 gmask = gr->screen->format->Gmask;
1294                 bmask = gr->screen->format->Bmask;
1295                 amask = gr->screen->format->Amask;
1296         }
1297
1298         ov->screen = SDL_CreateRGBSurface(SDL_SWSURFACE, 
1299                         w, h,
1300                         gr->screen->format->BitsPerPixel,
1301                         rmask, gmask, bmask, amask);
1302
1303         ov->overlay_mode = 1;
1304         ov->overlay_enable = 1;
1305         ov->overlay_x = p->x;
1306         ov->overlay_y = p->y;
1307         ov->overlay_parent = gr;
1308         ov->overlay_idx = i;
1309         gr->overlay_array[i] = ov;
1310
1311
1312   struct font_priv *(*font_freetype_new) (void *meth);
1313   font_freetype_new = plugin_get_font_type ("freetype");
1314
1315   if (!font_freetype_new)
1316     {
1317       return NULL;
1318     }
1319
1320
1321   font_freetype_new (&ov->freetype_methods);
1322
1323         *meth=graphics_methods;
1324
1325   meth->font_new =
1326     (struct graphics_font_priv *
1327      (*)(struct graphics_priv *, struct graphics_font_methods *, char *, int,
1328          int)) ov->freetype_methods.font_new;
1329   meth->get_text_bbox = ov->freetype_methods.get_text_bbox;
1330
1331
1332
1333
1334         return ov;
1335 }
1336
1337
1338 #ifdef LINUX_TOUCHSCREEN
1339
1340 #define EVFN "/dev/input/eventX"
1341
1342 static int input_ts_init(struct graphics_priv *gr)
1343 {
1344     struct input_id ii;
1345     char fn[32];
1346 #if 0
1347     char name[64];
1348 #endif
1349     int n, fd, ret;
1350
1351     gr->ts_fd = -1;
1352     gr->ts_hit = -1;
1353     gr->ts_x = 0;
1354     gr->ts_y = 0;
1355
1356     strcpy(fn, EVFN);
1357     n = 0;
1358     while(1)
1359     {
1360         fn[sizeof(EVFN)-2] = '0' + n;
1361
1362         fd = open(fn, O_RDONLY);
1363         if(fd >= 0)
1364         {
1365 #if 0
1366             ret = ioctl(fd, EVIOCGNAME(64), (void *)name);
1367             if(ret > 0)
1368             {
1369                 printf("input_ts: %s\n", name);
1370             }
1371 #endif
1372
1373             ret = ioctl(fd, EVIOCGID, (void *)&ii);
1374             if(ret == 0)
1375             {
1376 #if 1
1377                 printf("bustype %04x vendor %04x product %04x version %04x\n",
1378                        ii.bustype,
1379                        ii.vendor,
1380                        ii.product,
1381                        ii.version);
1382 #endif
1383
1384                 if((ii.bustype == BUS_USB) &&
1385                    (ii.vendor == 0x0eef) &&
1386                    (ii.product == 0x0001))
1387                 {
1388                     ret = fcntl(fd, F_SETFL, O_NONBLOCK);
1389                     if(ret == 0)
1390                     {
1391                         gr->ts_fd = fd;
1392                     }
1393                     else
1394                     {
1395                         close(fd);
1396                     }
1397
1398                     break;
1399                 }
1400             }
1401
1402             close(fd);
1403         }
1404
1405         n = n + 1;
1406
1407         /* FIXME: should check all 32 minors */
1408         if(n == 10)
1409         {
1410             /* not found */
1411             ret = -1;
1412             break;
1413         }
1414     }
1415
1416     return ret;
1417 }
1418
1419
1420 /* returns 0-based display coordinate for the given ts coord */
1421 static void input_ts_map(int *disp_x, int *disp_y,
1422                          uint32_t ts_x, uint32_t ts_y)
1423 {
1424     /* Dynamix 7" (eGalax TS)
1425        top left  = 1986,103
1426        top right =   61,114
1427        bot left  = 1986,1897
1428        bot right =   63,1872
1429
1430        calibrate your TS using input_event_dump
1431        and touching all four corners. use the most extreme values. 
1432     */
1433
1434 #define INPUT_TS_LEFT 1978
1435 #define INPUT_TS_RIGHT  48
1436 #define INPUT_TS_TOP   115
1437 #define INPUT_TS_BOT  1870
1438
1439     /* clamp first */
1440     if(ts_x > INPUT_TS_LEFT)
1441     {
1442         ts_x = INPUT_TS_LEFT;
1443     }
1444     if(ts_x < INPUT_TS_RIGHT)
1445     {
1446         ts_x = INPUT_TS_RIGHT;
1447     }
1448
1449     ts_x = ts_x - INPUT_TS_RIGHT;
1450
1451     *disp_x = ((DISPLAY_W-1) * ts_x) / (INPUT_TS_LEFT - INPUT_TS_RIGHT);
1452     *disp_x = (DISPLAY_W-1) - *disp_x;
1453
1454
1455     if(ts_y > INPUT_TS_BOT)
1456     {
1457         ts_y = INPUT_TS_BOT;
1458     }
1459     if(ts_y < INPUT_TS_TOP)
1460     {
1461         ts_y = INPUT_TS_TOP;
1462     }
1463
1464     ts_y = ts_y - INPUT_TS_TOP;
1465
1466     *disp_y = ((DISPLAY_H-1) * ts_y) / (INPUT_TS_BOT - INPUT_TS_TOP);
1467 /*  *disp_y = (DISPLAY_H-1) - *disp_y; */
1468 }
1469
1470 #if 0
1471 static void input_event_dump(struct input_event *ie)
1472 {
1473     printf("input_event:\n"
1474            "\ttv_sec\t%u\n"
1475            "\ttv_usec\t%lu\n"
1476            "\ttype\t%u\n"
1477            "\tcode\t%u\n"
1478            "\tvalue\t%d\n",
1479            (unsigned int)ie->time.tv_sec,
1480            ie->time.tv_usec,
1481            ie->type,
1482            ie->code,
1483            ie->value);
1484 }
1485 #endif
1486
1487 static int input_ts_exit(struct graphics_priv *gr)
1488 {
1489     close(gr->ts_fd);
1490     gr->ts_fd = -1;
1491
1492     return 0;
1493 }
1494 #endif
1495
1496
1497 static gboolean graphics_sdl_idle(void *data)
1498 {
1499     struct graphics_priv *gr = (struct graphics_priv *)data;
1500     struct point p;
1501     SDL_Event ev;
1502 #ifdef LINUX_TOUCHSCREEN
1503     struct input_event ie;
1504     ssize_t ss;
1505 #endif
1506     int ret, key;
1507     char keybuf[2];
1508
1509     /* generate the initial resize callback, so the gui knows W/H
1510
1511        its unsafe to do this directly inside register_resize_callback;
1512        graphics_gtk does it during Configure, but SDL does not have
1513        an equivalent event, so we use our own flag
1514     */
1515     if(gr->resize_callback_initial != 0)
1516     {
1517         callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
1518         gr->resize_callback_initial = 0;
1519     }
1520
1521 #ifdef LINUX_TOUCHSCREEN
1522     if(gr->ts_fd >= 0)
1523     {
1524         ss = read(gr->ts_fd, (void *)&ie, sizeof(ie));
1525         if(ss == sizeof(ie))
1526         {
1527             /* we (usually) get three events on a touchscreen hit:
1528               1: type =EV_KEY
1529                  code =330 [BTN_TOUCH]
1530                  value=1
1531
1532               2: type =EV_ABS
1533                  code =0 [X]
1534                  value=X pos
1535
1536               3: type =EV_ABS
1537                  code =1 [Y]
1538                  value=Y pos
1539
1540               4: type =EV_SYN
1541
1542               once hit, if the contact point changes, we'll get more 
1543               EV_ABS (for 1 or both axes), followed by an EV_SYN.
1544
1545               and, on a lift:
1546
1547               5: type =EV_KEY
1548                  code =330 [BTN_TOUCH]
1549                  value=0
1550
1551               6: type =EV_SYN
1552             */
1553             switch(ie.type)
1554             {
1555                 case EV_KEY:
1556                 {
1557                     if(ie.code == BTN_TOUCH)
1558                     {
1559                         gr->ts_hit = ie.value;
1560                     }
1561
1562                     break;
1563                 }
1564
1565                 case EV_ABS:
1566                 {
1567                     if(ie.code == 0)
1568                     {
1569                         gr->ts_x = ie.value;
1570                     }
1571                     else if(ie.code == 1)
1572                     {
1573                         gr->ts_y = ie.value;
1574                     }
1575
1576                     break;
1577                 }
1578
1579                 case EV_SYN:
1580                 {
1581                     input_ts_map(&p.x, &p.y, gr->ts_x, gr->ts_y);
1582
1583                     /* always send MOUSE_MOTION (first) */
1584                     callback_list_call_attr_1(gr->cbl, attr_motion, (void *)&p); 
1585                     if(gr->ts_hit > 0)
1586                     {
1587                         callback_list_call_attr_3(gr->cbl, attr_button, (void *)1, (void *)SDL_BUTTON_LEFT, (void *)&p); 
1588                     }
1589                     else if(gr->ts_hit == 0)
1590                     {
1591                         callback_list_call_attr_3(gr->cbl, attr_button, (void *)0, (void *)SDL_BUTTON_LEFT, (void *)&p); 
1592                     }
1593
1594                     /* reset ts_hit */
1595                     gr->ts_hit = -1;
1596
1597                     break;
1598                 }
1599
1600                 default:
1601                 {
1602                     break;
1603                 }
1604             }
1605         }
1606     }
1607 #endif
1608
1609     while(1)
1610     {
1611         ret = SDL_PollEvent(&ev);
1612         if(ret == 0)
1613         {
1614             break;
1615         }
1616
1617         switch(ev.type)
1618         {
1619             case SDL_MOUSEMOTION:
1620             {
1621                 p.x = ev.motion.x;
1622                 p.y = ev.motion.y;
1623                 callback_list_call_attr_1(gr->cbl, attr_motion, (void *)&p); 
1624                 break;
1625             }
1626
1627             case SDL_KEYDOWN:
1628             {
1629                 switch(ev.key.keysym.sym)
1630                 {
1631                     case SDLK_LEFT:
1632                     {
1633                         key = NAVIT_KEY_LEFT;
1634                         break;
1635                     }
1636                     case SDLK_RIGHT:
1637                     {
1638                         key = NAVIT_KEY_RIGHT;
1639                         break;
1640                     }
1641                     case SDLK_BACKSPACE:
1642                     {
1643                         key = NAVIT_KEY_BACKSPACE;
1644                         break;
1645                     }
1646                     case SDLK_RETURN:
1647                     {
1648                         key = NAVIT_KEY_RETURN;
1649                         break;
1650                     }
1651                     case SDLK_DOWN:
1652                     {
1653                         key = NAVIT_KEY_DOWN;
1654                         break;
1655                     }
1656                     case SDLK_PAGEUP:
1657                     {
1658                         key = NAVIT_KEY_ZOOM_OUT;
1659                         break;
1660                     }
1661                     case SDLK_UP:
1662                     {
1663                         key = NAVIT_KEY_UP;
1664                         break;
1665                     }
1666                     case SDLK_PAGEDOWN:
1667                     {
1668                         key = NAVIT_KEY_ZOOM_IN;
1669                         break;
1670                     }
1671                     default:
1672                     {
1673                         /* return unicode chars when they can be converted to ascii */
1674                         key = ev.key.keysym.unicode<=127 ? ev.key.keysym.unicode : 0;
1675                         break;
1676                     }
1677                 }
1678
1679                 keybuf[0] = key;
1680                 keybuf[1] = '\0';
1681                 callback_list_call_attr_1(gr->cbl, attr_keypress, (void *)keybuf);
1682
1683                 break;
1684             }
1685
1686             case SDL_KEYUP:
1687             {
1688                 break;
1689             }
1690
1691             case SDL_MOUSEBUTTONDOWN:
1692             {
1693 #ifdef DEBUG
1694                 printf("SDL_MOUSEBUTTONDOWN %d %d %d %d %d\n",
1695                        ev.button.which,
1696                        ev.button.button,
1697                        ev.button.state,
1698                        ev.button.x,
1699                        ev.button.y);
1700 #endif
1701
1702                 p.x = ev.button.x;
1703                 p.y = ev.button.y;
1704                 callback_list_call_attr_3(gr->cbl, attr_button, (void *)1, (void *)(int)ev.button.button, (void *)&p); 
1705                 break;
1706             }
1707
1708             case SDL_MOUSEBUTTONUP:
1709             {
1710 #ifdef DEBUG
1711                 printf("SDL_MOUSEBUTTONUP %d %d %d %d %d\n",
1712                        ev.button.which,
1713                        ev.button.button,
1714                        ev.button.state,
1715                        ev.button.x,
1716                        ev.button.y);
1717 #endif
1718
1719                 p.x = ev.button.x;
1720                 p.y = ev.button.y;
1721                 callback_list_call_attr_3(gr->cbl, attr_button, (void *)0, (void *)(int)ev.button.button, (void *)&p); 
1722                 break;
1723             }
1724
1725             case SDL_QUIT:
1726             {
1727                 navit_destroy(gr->nav);
1728                 break;
1729             }
1730
1731             case SDL_VIDEORESIZE:
1732             {
1733
1734                 gr->screen = SDL_SetVideoMode(ev.resize.w, ev.resize.h, gr->video_bpp, gr->video_flags);
1735                 if(gr->screen == NULL)
1736                 {
1737                     navit_destroy(gr->nav);
1738                 }
1739                 else
1740                 {
1741                     callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
1742                 }
1743
1744                 break;
1745             }
1746
1747             default:
1748             {
1749 #ifdef DEBUG
1750                 printf("SDL_Event %d\n", ev.type);
1751 #endif
1752                 break;
1753             }
1754         }
1755     }
1756
1757     return TRUE;
1758 }
1759
1760
1761 static struct graphics_priv *
1762 graphics_sdl_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
1763 {
1764     struct graphics_priv *this=g_new0(struct graphics_priv, 1);
1765     struct attr *attr;
1766     int ret;
1767     int w=DISPLAY_W,h=DISPLAY_H;
1768
1769     struct font_priv *(*font_freetype_new) (void *meth);
1770     font_freetype_new = plugin_get_font_type ("freetype");
1771
1772     if (!font_freetype_new)
1773       {
1774         return NULL;
1775       }
1776
1777     font_freetype_new (&this->freetype_methods);
1778
1779     this->nav = nav;
1780     this->cbl = cbl;
1781
1782     ret = SDL_Init(SDL_INIT_VIDEO);
1783     if(ret < 0)
1784     {
1785         g_free(this);
1786         return NULL;
1787     }
1788
1789     if (! event_request_system("glib","graphics_sdl_new"))
1790         return NULL;
1791
1792     this->video_bpp = 16;
1793     this->video_flags = SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE;
1794
1795     if ((attr=attr_search(attrs, NULL, attr_w)))
1796         w=attr->u.num;
1797     if ((attr=attr_search(attrs, NULL, attr_h)))
1798         h=attr->u.num;
1799     if ((attr=attr_search(attrs, NULL, attr_bpp)))
1800         this->video_bpp=attr->u.num;
1801     if ((attr=attr_search(attrs, NULL, attr_flags))) {
1802         if (attr->u.num & 1) 
1803             this->video_flags = SDL_SWSURFACE;
1804     }
1805     if ((attr=attr_search(attrs, NULL, attr_frame))) {
1806         if(!attr->u.num)
1807             this->video_flags |= SDL_NOFRAME;
1808     }
1809
1810     this->screen = SDL_SetVideoMode(w, h, this->video_bpp, this->video_flags);
1811
1812     /* Use screen size instead of requested */
1813     w = this->screen->w;
1814     h = this->screen->h;
1815
1816     if(this->screen == NULL)
1817     {
1818         g_free(this);
1819         SDL_Quit();
1820         return NULL;
1821     }
1822
1823     SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
1824
1825     SDL_EnableUNICODE(1);
1826     SDL_WM_SetCaption("navit", NULL);
1827
1828 #ifdef LINUX_TOUCHSCREEN
1829     input_ts_init(this);
1830     if(this->ts_fd >= 0)
1831     {
1832         /* mouse cursor does not always display correctly in Linux FB.
1833            anyway, it is unnecessary w/ a touch screen
1834         */
1835         SDL_ShowCursor(0);
1836     }
1837 #endif
1838
1839 #ifdef SDL_SGE
1840     sge_Update_OFF();
1841     sge_Lock_ON();
1842 #endif
1843
1844     *meth=graphics_methods;
1845
1846
1847     meth->font_new =
1848        (struct graphics_font_priv *
1849        (*)(struct graphics_priv *, struct graphics_font_methods *, char *, int,
1850         int)) this->freetype_methods.font_new;
1851     meth->get_text_bbox = this->freetype_methods.get_text_bbox;
1852
1853
1854
1855     g_timeout_add(G_PRIORITY_DEFAULT+10, graphics_sdl_idle, this);
1856
1857     this->overlay_enable = 1;
1858
1859     this->aa = 1;
1860     if((attr=attr_search(attrs, NULL, attr_antialias)))
1861         this->aa = attr->u.num;
1862
1863     this->resize_callback_initial=1;
1864     return this;
1865 }
1866
1867 void
1868 plugin_init(void)
1869 {
1870         plugin_register_graphics_type("sdl", graphics_sdl_new);
1871 }
1872