Fix:graphics_gtk_drawing_area:Handle overlay disable/enable correctly
[profile/ivi/navit.git] / navit / navit / graphics / gtk_drawing_area / graphics_gtk_drawing_area.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #define GDK_ENABLE_BROKEN
21 #include "config.h"
22 #include <stdlib.h>
23 #include <signal.h>
24 #include <sys/time.h>
25 #include <gtk/gtk.h>
26 #include <gdk/gdkkeysyms.h>
27 #include <locale.h> /* For WIN32 */
28 #if !defined(GDK_Book) || !defined(GDK_Calendar)
29 #include <X11/XF86keysym.h>
30 #endif
31 #ifdef HAVE_IMLIB2
32 #include <Imlib2.h>
33 #endif
34
35 #ifndef _WIN32
36 #include <gdk/gdkx.h>
37 #endif
38 #include "event.h"
39 #include "debug.h"
40 #include "point.h"
41 #include "graphics.h"
42 #include "color.h"
43 #include "item.h"
44 #include "window.h"
45 #include "callback.h"
46 #include "keys.h"
47 #include "plugin.h"
48 #include "navit/font/freetype/font_freetype.h"
49 #include "navit.h"
50
51 #ifndef GDK_Book
52 #define GDK_Book XF86XK_Book
53 #endif
54 #ifndef GDK_Calendar
55 #define GDK_Calendar XF86XK_Calendar
56 #endif
57
58
59 struct graphics_priv {
60         GdkEventButton button_event;
61         int button_timeout;
62         GtkWidget *widget;
63         GtkWidget *win;
64         struct window window;
65         GdkDrawable *drawable;
66         GdkDrawable *background;
67         int background_ready;
68         GdkColormap *colormap;
69         struct point p;
70         struct point pclean;
71         int cleanup;
72         int width;
73         int height;
74         int win_w;
75         int win_h;
76         int visible;
77         int overlay_disabled;
78         int overlay_autodisabled;
79         int a;
80         int wraparound;
81         struct graphics_priv *parent;
82         struct graphics_priv *overlays;
83         struct graphics_priv *next;
84         struct graphics_gc_priv *background_gc;
85         enum draw_mode_num mode;
86         struct callback_list *cbl;
87         struct font_freetype_methods freetype_methods;
88         struct navit *nav;
89         int pid;
90         struct timeval button_press[8];
91         struct timeval button_release[8];
92         int timeout;
93         int delay;
94         char *window_title;
95 };
96
97
98 struct graphics_gc_priv {
99         GdkGC *gc;
100         GdkPixmap *pixmap;
101         struct graphics_priv *gr;
102         struct color c;
103 };
104
105 struct graphics_image_priv {
106         GdkPixbuf *pixbuf;
107         int w;
108         int h;
109 };
110
111 static GHashTable *hImageData;   /*hastable for uncompressed image data*/
112 static int hImageDataCount;
113 static struct graphics_image_priv image_error;
114
115 static void
116 graphics_destroy_image(gpointer data)
117 {
118         struct graphics_image_priv *priv = (struct graphics_image_priv*)data;
119
120         if (priv == &image_error)
121                 return;
122
123         if (priv->pixbuf)
124                 g_object_unref(priv->pixbuf);
125         g_free(priv);
126 }
127
128 static void
129 graphics_destroy(struct graphics_priv *gr)
130 {
131         dbg(0,"enter parent %p\n",gr->parent);
132         if (!gr->parent) {
133                 dbg(0,"enter win %p\n",gr->win);
134                 if (gr->win)
135                         gtk_widget_destroy(gr->win);
136                 dbg(0,"widget %p\n",gr->widget);
137                 if (gr->widget)
138                         gtk_widget_destroy(gr->widget);
139                 g_free(gr->window_title);
140         }
141         dbg(0,"hImageDataCount %d\n",hImageDataCount);
142         if (!--hImageDataCount)
143                 g_hash_table_destroy(hImageData);
144         g_free(gr);
145 }
146
147 static void
148 gc_destroy(struct graphics_gc_priv *gc)
149 {
150         g_object_unref(gc->gc);
151         g_free(gc);
152 }
153
154 static void
155 gc_set_linewidth(struct graphics_gc_priv *gc, int w)
156 {
157         gdk_gc_set_line_attributes(gc->gc, w, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
158 }
159
160 static void
161 gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
162 {
163         gdk_gc_set_dashes(gc->gc, offset, (gint8 *)dash_list, n);
164         gdk_gc_set_line_attributes(gc->gc, w, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND);
165 }
166
167 static void
168 gc_set_color(struct graphics_gc_priv *gc, struct color *c, int fg)
169 {
170         GdkColor gdkc;
171         gdkc.pixel=0;
172         gdkc.red=c->r;
173         gdkc.green=c->g;
174         gdkc.blue=c->b;
175         gdk_colormap_alloc_color(gc->gr->colormap, &gdkc, FALSE, TRUE);
176         gdk_colormap_query_color(gc->gr->colormap, gdkc.pixel, &gdkc);
177         gc->c=*c;
178         if (fg) {
179                 gdk_gc_set_foreground(gc->gc, &gdkc);
180         } else
181                 gdk_gc_set_background(gc->gc, &gdkc);
182 }
183
184 static void
185 gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
186 {
187         gc_set_color(gc, c, 1);
188 }
189
190 static void
191 gc_set_background(struct graphics_gc_priv *gc, struct color *c)
192 {
193         gc_set_color(gc, c, 0);
194 }
195
196 static void
197 gc_set_stipple(struct graphics_gc_priv *gc, struct graphics_image_priv *img)
198 {
199         char data[2]={0x2,0x1};
200         gdk_gc_set_fill(gc->gc, GDK_STIPPLED);
201         gc->pixmap=gdk_bitmap_create_from_data(gc->gr->widget->window, data, 2, 2);
202         gdk_gc_set_stipple(gc->gc, gc->pixmap);
203 }
204
205 static struct graphics_gc_methods gc_methods = {
206         gc_destroy,
207         gc_set_linewidth,
208         gc_set_dashes,
209         gc_set_foreground,
210         gc_set_background,
211         gc_set_stipple,
212 };
213
214 static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
215 {
216         struct graphics_gc_priv *gc=g_new(struct graphics_gc_priv, 1);
217
218         *meth=gc_methods;
219         gc->gc=gdk_gc_new(gr->widget->window);
220         gc->gr=gr;
221         return gc;
222 }
223
224
225 static struct graphics_image_priv *
226 image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name, int *w, int *h, struct point *hot, int rotation)
227 {
228         GdkPixbuf *pixbuf;
229         struct graphics_image_priv *ret;
230         const char *option;
231
232         char* hash_key = g_strdup_printf("%s_%d_%d_%d",name,*w,*h,rotation);
233
234         //check if image already exists in hashmap
235         struct graphics_image_priv *curr_elem = g_hash_table_lookup(hImageData, hash_key);
236         if(curr_elem == &image_error) {
237                 //found but couldn't be loaded
238                 g_free(hash_key);
239                 return NULL;
240         }
241         else if(curr_elem) {
242                 //found and OK -> use hashtable entry
243                 g_free(hash_key);
244                 *w = curr_elem->w;
245                 *h = curr_elem->h;
246                 hot->x = curr_elem->w / 2 - 1;
247                 hot->y = curr_elem->h / 2 - 1;
248                 ret=g_new0(struct graphics_image_priv, 1);
249                 *ret = *curr_elem;
250                 g_object_ref(ret->pixbuf);
251                 return ret;
252         }
253         else {
254                 if (*w == -1 && *h == -1)
255                         pixbuf=gdk_pixbuf_new_from_file(name, NULL);
256                 else
257                         pixbuf=gdk_pixbuf_new_from_file_at_size(name, *w, *h, NULL);
258
259                 if (!pixbuf) {
260                         g_hash_table_insert(hImageData, g_strdup(hash_key), &image_error);
261                         g_free(hash_key);
262                         return NULL;
263                 }
264
265                 if (rotation) {
266                         GdkPixbuf *tmp;
267                         switch (rotation) {
268                                 case 90:
269                                         rotation=270;
270                                         break;
271                                 case 180:
272                                         break;
273                                 case 270:
274                                         rotation=90;
275                                         break;
276                                 default:
277                                         g_hash_table_insert(hImageData, g_strdup(hash_key), &image_error);
278                                         g_free(hash_key);
279                                         return NULL;
280                         }
281
282                         tmp=gdk_pixbuf_rotate_simple(pixbuf, rotation);
283
284                         if (!tmp) {
285                                 g_hash_table_insert(hImageData, g_strdup(hash_key), &image_error);
286                                 g_free(hash_key);
287                                 g_object_unref(pixbuf);
288                                 return NULL;
289                         }
290
291                         g_object_unref(pixbuf);
292                         pixbuf=tmp;
293                 }
294
295                 ret=g_new0(struct graphics_image_priv, 1);
296                 ret->pixbuf=pixbuf;
297                 ret->w=gdk_pixbuf_get_width(pixbuf);
298                 ret->h=gdk_pixbuf_get_height(pixbuf);
299                 *w=ret->w;
300                 *h=ret->h;
301                 if (hot) {
302                         option=gdk_pixbuf_get_option(pixbuf, "x_hot");
303                         if (option)
304                                 hot->x=atoi(option);
305                         else
306                                 hot->x=ret->w/2-1;
307                         option=gdk_pixbuf_get_option(pixbuf, "y_hot");
308                         if (option)
309                                 hot->y=atoi(option);
310                         else
311                                 hot->y=ret->h/2-1;
312                 }
313                 struct graphics_image_priv *cached = g_new0(struct graphics_image_priv, 1);
314                 *cached = *ret;
315                 g_hash_table_insert(hImageData, g_strdup(hash_key), cached);
316                 g_object_ref(pixbuf);
317                 g_free(hash_key);
318                 return ret;
319         }
320 }
321
322 static void 
323 image_free(struct graphics_priv *gr, struct graphics_image_priv *priv)
324 {
325         g_object_unref(priv->pixbuf);
326         g_free(priv);
327 }
328
329 static void
330 draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
331 {
332         if (gr->mode == draw_mode_begin || gr->mode == draw_mode_end)
333                 gdk_draw_lines(gr->drawable, gc->gc, (GdkPoint *)p, count);
334         if (gr->mode == draw_mode_end || gr->mode == draw_mode_cursor)
335                 gdk_draw_lines(gr->widget->window, gc->gc, (GdkPoint *)p, count);
336 }
337
338 static void
339 draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
340 {
341         if (gr->mode == draw_mode_begin || gr->mode == draw_mode_end)
342                 gdk_draw_polygon(gr->drawable, gc->gc, TRUE, (GdkPoint *)p, count);
343         if (gr->mode == draw_mode_end || gr->mode == draw_mode_cursor)
344                 gdk_draw_polygon(gr->widget->window, gc->gc, TRUE, (GdkPoint *)p, count);
345 }
346
347 static void
348 draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
349 {
350         gdk_draw_rectangle(gr->drawable, gc->gc, TRUE, p->x, p->y, w, h);
351 }
352
353 static void
354 draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
355 {
356         if (gr->mode == draw_mode_begin || gr->mode == draw_mode_end)
357                 gdk_draw_arc(gr->drawable, gc->gc, FALSE, p->x-r/2, p->y-r/2, r, r, 0, 64*360);
358         if (gr->mode == draw_mode_end || gr->mode == draw_mode_cursor)
359                 gdk_draw_arc(gr->widget->window, gc->gc, FALSE, p->x-r/2, p->y-r/2, r, r, 0, 64*360);
360 }
361
362 static void
363 display_text_draw(struct font_freetype_text *text, struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg, int color, struct point *p)
364 {
365         int i,x,y,stride;
366         struct font_freetype_glyph *g, **gp;
367         unsigned char *shadow,*glyph;
368         struct color transparent={0x0,0x0,0x0,0x0};
369         struct color white={0xffff,0xffff,0xffff,0xffff};
370
371         gp=text->glyph;
372         i=text->glyph_count;
373         x=p->x << 6;
374         y=p->y << 6;
375         while (i-- > 0)
376         {
377                 g=*gp++;
378                 if (g->w && g->h && bg ) {
379 #if 1
380                         stride=g->w+2;
381                         shadow=g_malloc(stride*(g->h+2));
382                         if (gr->freetype_methods.get_shadow(g, shadow, 8, stride, &white, &transparent))
383                                 gdk_draw_gray_image(gr->drawable, bg->gc, ((x+g->x)>>6)-1, ((y+g->y)>>6)-1, g->w+2, g->h+2, GDK_RGB_DITHER_NONE, shadow, stride);
384                         g_free(shadow);
385                         if (color) {
386                                 stride*=3;
387                                 shadow=g_malloc(stride*(g->h+2));
388                                 gr->freetype_methods.get_shadow(g, shadow, 24, stride, &bg->c, &transparent);
389                                 gdk_draw_rgb_image(gr->drawable, fg->gc, ((x+g->x)>>6)-1, ((y+g->y)>>6)-1, g->w+2, g->h+2, GDK_RGB_DITHER_NONE, shadow, stride);
390                                 g_free(shadow);
391                         } 
392 #else
393                         GdkImage *image;
394                         stride=(g->w+9)/8;
395                         shadow=malloc(stride*(g->h+2));
396                         
397                         gr->freetype_methods.get_shadow(g, shadow, 1, stride);
398                         image=gdk_image_new_bitmap(gdk_visual_get_system(),shadow,g->w+2, g->h+2);
399                         gdk_draw_image(gr->drawable, bg->gc, image, 0, 0, ((x+g->x)>>6)-1, ((y+g->y)>>6)-1, g->w+2, g->h+2);
400                         g_object_unref(image);
401 #endif
402                         
403                 }
404                 x+=g->dx;
405                 y+=g->dy;
406         }
407         x=p->x << 6;
408         y=p->y << 6;
409         gp=text->glyph;
410         i=text->glyph_count;
411         while (i-- > 0)
412         {
413                 g=*gp++;
414                 if (g->w && g->h) {
415                         if (color) {
416                                 stride=g->w;
417                                 if (bg) {
418                                         glyph=g_malloc(stride*g->h);
419                                         gr->freetype_methods.get_glyph(g, glyph, 8, stride, &fg->c, &bg->c, &transparent);
420                                         gdk_draw_gray_image(gr->drawable, bg->gc, (x+g->x)>>6, (y+g->y)>>6, g->w, g->h, GDK_RGB_DITHER_NONE, glyph, g->w);
421                                         g_free(glyph);
422                                 }
423                                 stride*=3;
424                                 glyph=g_malloc(stride*g->h);
425                                 gr->freetype_methods.get_glyph(g, glyph, 24, stride, &fg->c, bg?&bg->c:&transparent, &transparent);
426                                 gdk_draw_rgb_image(gr->drawable, fg->gc, (x+g->x)>>6, (y+g->y)>>6, g->w, g->h, GDK_RGB_DITHER_NONE, glyph, stride);
427                                 g_free(glyph);
428                         } else
429                                 gdk_draw_gray_image(gr->drawable, fg->gc, (x+g->x)>>6, (y+g->y)>>6, g->w, g->h, GDK_RGB_DITHER_NONE, g->pixmap, g->w);
430                 }
431                 x+=g->dx;
432                 y+=g->dy;
433         }
434 }
435
436 static void
437 draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg, struct graphics_font_priv *font, char *text, struct point *p, int dx, int dy)
438 {
439         struct font_freetype_text *t;
440         int color=0;
441
442         if (! font)
443         {
444                 dbg(0,"no font, returning\n");
445                 return;
446         }
447 #if 0 /* Temporarily disabled because it destroys text rendering of overlays and in gui internal in some places */
448         /* 
449          This needs an improvement, no one checks if the strings are visible
450         */
451         if (p->x > gr->width-50 || p->y > gr->height-50) {
452                 return;
453         }
454         if (p->x < -50 || p->y < -50) {
455                 return;
456         }
457 #endif
458
459         if (bg) {
460                 if (COLOR_IS_BLACK(fg->c) && COLOR_IS_WHITE(bg->c)) {
461                         gdk_gc_set_function(fg->gc, GDK_AND_INVERT);
462                         gdk_gc_set_function(bg->gc, GDK_OR);
463                 } else if (COLOR_IS_WHITE(fg->c) && COLOR_IS_BLACK(bg->c)) {
464                         gdk_gc_set_function(fg->gc, GDK_OR);
465                         gdk_gc_set_function(bg->gc, GDK_AND_INVERT);
466                 } else  {
467                         gdk_gc_set_function(fg->gc, GDK_OR);
468                         gdk_gc_set_function(bg->gc, GDK_AND_INVERT);
469                         color=1;
470                 }
471         } else {
472                 gdk_gc_set_function(fg->gc, GDK_OR);
473                 color=1;
474         }
475         t=gr->freetype_methods.text_new(text, (struct font_freetype_font *)font, dx, dy);
476         display_text_draw(t, gr, fg, bg, color, p);
477         gr->freetype_methods.text_destroy(t);
478         gdk_gc_set_function(fg->gc, GDK_COPY);
479         if (bg)
480                 gdk_gc_set_function(bg->gc, GDK_COPY);
481 #if 0
482         {
483                 struct point pnt[5];
484                 int i;
485                 gr->freetype_methods.get_text_bbox(gr, font, text, dx, dy, pnt, 1);
486                 for (i = 0 ; i < 4 ; i++) {
487                         pnt[i].x+=p->x;
488                         pnt[i].y+=p->y;
489                 }
490                 pnt[4]=pnt[0];
491                 gdk_draw_lines(gr->drawable, fg->gc, (GdkPoint *)pnt, 5);
492         }
493 #endif
494 }
495
496 static void
497 draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
498 {
499         gdk_draw_pixbuf(gr->drawable, fg->gc, img->pixbuf, 0, 0, p->x, p->y,
500                     img->w, img->h, GDK_RGB_DITHER_NONE, 0, 0);
501 }
502
503 #ifdef HAVE_IMLIB2
504 static void
505 draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
506 {
507         void *image;
508         int w,h;
509         dbg(1,"draw_image_warp data=%s\n", data);
510         image = imlib_load_image(data);
511         imlib_context_set_display(gdk_x11_drawable_get_xdisplay(gr->widget->window));
512         imlib_context_set_colormap(gdk_x11_colormap_get_xcolormap(gtk_widget_get_colormap(gr->widget)));
513         imlib_context_set_visual(gdk_x11_visual_get_xvisual(gtk_widget_get_visual(gr->widget)));
514         imlib_context_set_drawable(gdk_x11_drawable_get_xid(gr->drawable));
515         imlib_context_set_image(image);
516         w = imlib_image_get_width();
517         h = imlib_image_get_height();
518         if (count == 3) {
519                 /* 0 1
520                    2   */
521                 imlib_render_image_on_drawable_skewed(0, 0, w, h, p[0].x, p[0].y, p[1].x-p[0].x, p[1].y-p[0].y, p[2].x-p[0].x, p[2].y-p[0].y);
522         }
523         if (count == 2) {
524                 /* 0 
525                      1 */
526                 imlib_render_image_on_drawable_skewed(0, 0, w, h, p[0].x, p[0].y, p[1].x-p[0].x, 0, 0, p[1].y-p[0].y);
527         }
528         if (count == 1) {
529                 /* 
530                    0 
531                      */
532                 imlib_render_image_on_drawable_skewed(0, 0, w, h, p[0].x-w/2, p[0].y-h/2, w, 0, 0, h);
533         }
534         imlib_free_image();
535 }
536 #endif
537
538 static void
539 overlay_rect(struct graphics_priv *parent, struct graphics_priv *overlay, int clean, GdkRectangle *r)
540 {
541         if (clean) {
542                 r->x=overlay->pclean.x;
543                 r->y=overlay->pclean.y;
544         } else {
545                 r->x=overlay->p.x;
546                 r->y=overlay->p.y;
547         }
548         r->width=overlay->width;
549         r->height=overlay->height;
550         if (!overlay->wraparound)
551                 return;
552         if (r->x < 0)
553                 r->x += parent->width;
554         if (r->y < 0)
555                 r->y += parent->height;
556         if (r->width < 0)
557                 r->width += parent->width;
558         if (r->height < 0)
559                 r->height += parent->height;
560 }
561
562 static void
563 overlay_draw(struct graphics_priv *parent, struct graphics_priv *overlay, GdkRectangle *re, GdkPixmap *pixmap, GdkGC *gc)
564 {
565         GdkPixbuf *pixbuf,*pixbuf2;
566         guchar *pixels1, *pixels2, *p1, *p2, r=0, g=0, b=0, a=0;
567         int x,y;
568         int rowstride1,rowstride2;
569         int n_channels1,n_channels2;
570         GdkRectangle or,ir;
571         struct graphics_gc_priv *bg=overlay->background_gc;
572         if (bg) {
573                 r=bg->c.r>>8;
574                 g=bg->c.g>>8;
575                 b=bg->c.b>>8;
576                 a=bg->c.a>>8;
577         }
578
579         if (parent->overlay_disabled || overlay->overlay_disabled || overlay->overlay_autodisabled)
580                 return;
581         dbg(1,"r->x=%d r->y=%d r->width=%d r->height=%d\n", re->x, re->y, re->width, re->height);
582         overlay_rect(parent, overlay, 0, &or);
583         dbg(1,"or.x=%d or.y=%d or.width=%d or.height=%d\n", or.x, or.y, or.width, or.height);
584         if (! gdk_rectangle_intersect(re, &or, &ir))
585                 return;
586         or.x-=re->x;
587         or.y-=re->y;
588         pixbuf=gdk_pixbuf_get_from_drawable(NULL, overlay->drawable, NULL, 0, 0, 0, 0, or.width, or.height);
589         pixbuf2=gdk_pixbuf_new(gdk_pixbuf_get_colorspace(pixbuf), TRUE, gdk_pixbuf_get_bits_per_sample(pixbuf),
590                                 or.width, or.height);
591         rowstride1 = gdk_pixbuf_get_rowstride (pixbuf);
592         rowstride2 = gdk_pixbuf_get_rowstride (pixbuf2);
593         pixels1=gdk_pixbuf_get_pixels (pixbuf);
594         pixels2=gdk_pixbuf_get_pixels (pixbuf2);
595         n_channels1 = gdk_pixbuf_get_n_channels (pixbuf);
596         n_channels2 = gdk_pixbuf_get_n_channels (pixbuf2);
597         for (y = 0 ; y < or.height ; y++) {
598                 for (x = 0 ; x < or.width ; x++) {
599                         p1 = pixels1 + y * rowstride1 + x * n_channels1;
600                         p2 = pixels2 + y * rowstride2 + x * n_channels2;
601                         p2[0]=p1[0];
602                         p2[1]=p1[1];
603                         p2[2]=p1[2];
604                         if (bg && p1[0] == r && p1[1] == g && p1[2] == b) 
605                                 p2[3]=a;
606                         else 
607                                 p2[3]=overlay->a;
608                 }
609         }
610         gdk_draw_pixbuf(pixmap, gc, pixbuf2, 0, 0, or.x, or.y, or.width, or.height, GDK_RGB_DITHER_NONE, 0, 0);
611         g_object_unref(pixbuf);
612         g_object_unref(pixbuf2);
613 }
614
615 static void
616 draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
617 {
618         GtkWidget *widget=gr->widget;
619         gdk_draw_drawable(widget->window,
620                         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
621                         gr->drawable,
622                         p->x, p->y, p->x, p->y, w, h);
623
624 }
625
626 static void
627 draw_drag(struct graphics_priv *gr, struct point *p)
628 {
629         if (!gr->cleanup) {
630                 gr->pclean=gr->p;
631                 gr->cleanup=1;
632         }
633         if (p)
634                 gr->p=*p;
635         else {
636                 gr->p.x=0;
637                 gr->p.y=0;
638         }
639 }
640
641
642 static void
643 background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
644 {
645         gr->background_gc=gc;
646 }
647
648 static void
649 gtk_drawing_area_draw(struct graphics_priv *gr, GdkRectangle *r)
650 {
651         GdkPixmap *pixmap;
652         GtkWidget *widget=gr->widget;
653         GdkGC *gc=widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
654         struct graphics_priv *overlay;
655
656         if (! gr->drawable)
657                 return;
658         pixmap = gdk_pixmap_new(widget->window, r->width, r->height, -1);
659         if ((gr->p.x || gr->p.y) && gr->background_gc) 
660                 gdk_draw_rectangle(pixmap, gr->background_gc->gc, TRUE, 0, 0, r->width, r->height);
661         gdk_draw_drawable(pixmap, gc, gr->drawable, r->x, r->y, gr->p.x, gr->p.y, r->width, r->height);
662         overlay=gr->overlays;
663         while (overlay) {
664                 overlay_draw(gr,overlay,r,pixmap,gc);
665                 overlay=overlay->next;
666         }
667         gdk_draw_drawable(widget->window, gc, pixmap, 0, 0, r->x, r->y, r->width, r->height);
668         g_object_unref(pixmap);
669 }
670
671 static void
672 draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
673 {
674         GdkRectangle r;
675         struct graphics_priv *overlay;
676 #if 0
677         if (mode == draw_mode_begin) {
678                 if (! gr->parent && gr->background_gc)
679                         gdk_draw_rectangle(gr->drawable, gr->background_gc->gc, TRUE, 0, 0, gr->width, gr->height);
680         }
681 #endif
682         if (mode == draw_mode_end && gr->mode != draw_mode_cursor) {
683                 if (gr->parent) {
684                         if (gr->cleanup) {
685                                 overlay_rect(gr->parent, gr, 1, &r);
686                                 gtk_drawing_area_draw(gr->parent, &r);
687                                 gr->cleanup=0;
688                         }
689                         overlay_rect(gr->parent, gr, 0, &r);
690                         gtk_drawing_area_draw(gr->parent, &r);
691                 } else {
692                         r.x=0;
693                         r.y=0;
694                         r.width=gr->width;
695                         r.height=gr->height;
696                         gtk_drawing_area_draw(gr, &r);
697                         overlay=gr->overlays;
698                         while (overlay) {
699                                 overlay->cleanup=0;
700                                 overlay=overlay->next;
701                         }
702                 }
703         }
704         gr->mode=mode;
705 }
706
707 /* Events */
708
709 static gint
710 configure(GtkWidget * widget, GdkEventConfigure * event, gpointer user_data)
711 {
712         struct graphics_priv *gra=user_data;
713         if (! gra->visible)
714                 return TRUE;
715         if (gra->drawable != NULL) {
716                 g_object_unref(gra->drawable);
717         }
718         if(gra->background_ready && gra->background != NULL) {
719                g_object_unref(gra->background);
720                gra->background_ready = 0;
721         }
722 #ifndef _WIN32
723         dbg(1,"window=%d\n", GDK_WINDOW_XID(widget->window));
724 #endif
725         gra->width=widget->allocation.width;
726         gra->height=widget->allocation.height;
727         gra->drawable = gdk_pixmap_new(widget->window, gra->width, gra->height, -1);
728         callback_list_call_attr_2(gra->cbl, attr_resize, GINT_TO_POINTER(gra->width), GINT_TO_POINTER(gra->height));
729         return TRUE;
730 }
731
732 static gint
733 expose(GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
734 {
735         struct graphics_priv *gra=user_data;
736
737         gra->visible=1;
738         if (! gra->drawable)
739                 configure(widget, NULL, user_data);
740         gtk_drawing_area_draw(gra, &event->area);
741 #if 0
742         gdk_draw_drawable(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
743                         gra->drawable, event->area.x, event->area.y,
744                         event->area.x, event->area.y,
745                         event->area.width, event->area.height);
746 #endif
747
748         return FALSE;
749 }
750
751 #if 0
752 static gint
753 button_timeout(gpointer user_data)
754 {
755 #if 0
756         struct container *co=user_data;
757         int x=co->gra->gra->button_event.x;
758         int y=co->gra->gra->button_event.y;
759         int button=co->gra->gra->button_event.button;
760
761         co->gra->gra->button_timeout=0;
762         popup(co, x, y, button);
763
764         return FALSE;
765 #endif
766 }
767 #endif
768
769 static int
770 tv_delta(struct timeval *old, struct timeval *new)
771 {
772         if (new->tv_sec-old->tv_sec >= INT_MAX/1000)
773                 return INT_MAX;
774         return (new->tv_sec-old->tv_sec)*1000+(new->tv_usec-old->tv_usec)/1000;
775 }
776
777 static gint
778 button_press(GtkWidget * widget, GdkEventButton * event, gpointer user_data)
779 {
780         struct graphics_priv *this=user_data;
781         struct point p;
782         struct timeval tv;
783         struct timezone tz;
784
785         gettimeofday(&tv, &tz);
786
787         if (event->button < 8) {
788                 if (tv_delta(&this->button_press[event->button], &tv) < this->timeout)
789                         return FALSE;
790                 this->button_press[event->button]= tv;
791                 this->button_release[event->button].tv_sec=0;
792                 this->button_release[event->button].tv_usec=0;
793         }
794         p.x=event->x;
795         p.y=event->y;
796         callback_list_call_attr_3(this->cbl, attr_button, GINT_TO_POINTER(1), GINT_TO_POINTER(event->button), (void *)&p);
797         return FALSE;
798 }
799
800 static gint
801 button_release(GtkWidget * widget, GdkEventButton * event, gpointer user_data)
802 {
803         struct graphics_priv *this=user_data;
804         struct point p;
805         struct timeval tv;
806         struct timezone tz;
807
808         gettimeofday(&tv, &tz);
809
810         if (event->button < 8) {
811                 if (tv_delta(&this->button_release[event->button], &tv) < this->timeout)
812                         return FALSE;
813                 this->button_release[event->button]= tv;
814                 this->button_press[event->button].tv_sec=0;
815                 this->button_press[event->button].tv_usec=0;
816         }
817         p.x=event->x;
818         p.y=event->y;
819         callback_list_call_attr_3(this->cbl, attr_button, GINT_TO_POINTER(0), GINT_TO_POINTER(event->button), (void *)&p);
820         return FALSE;
821 }
822
823
824
825 static gint
826 scroll(GtkWidget * widget, GdkEventScroll * event, gpointer user_data)
827 {
828         struct graphics_priv *this=user_data;
829         struct point p;
830         int button;
831
832         p.x=event->x;
833         p.y=event->y;
834         switch (event->direction) {
835         case GDK_SCROLL_UP:
836                 button=4;
837                 break;
838         case GDK_SCROLL_DOWN:
839                 button=5;
840                 break;
841         default:
842                 button=-1;
843                 break;
844         }
845         if (button != -1) {
846                 callback_list_call_attr_3(this->cbl, attr_button, GINT_TO_POINTER(1), GINT_TO_POINTER(button), (void *)&p);
847                 callback_list_call_attr_3(this->cbl, attr_button, GINT_TO_POINTER(0), GINT_TO_POINTER(button), (void *)&p);
848         }
849         return FALSE;
850 }
851
852 static gint
853 motion_notify(GtkWidget * widget, GdkEventMotion * event, gpointer user_data)
854 {
855         struct graphics_priv *this=user_data;
856         struct point p;
857
858         p.x=event->x;
859         p.y=event->y;
860         callback_list_call_attr_1(this->cbl, attr_motion, (void *)&p);
861         return FALSE;
862 }
863
864 /* *
865  * * Exit navit (X pressed)
866  * * @param widget active widget
867  * * @param event the event (delete_event)
868  * * @param user_data Pointer to private data structure
869  * * @returns TRUE
870  * */
871 static gint
872 delete(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
873 {
874         struct graphics_priv *this=user_data;
875         dbg(0,"enter this->win=%p\n",this->win);
876         if (this->delay & 2) {
877                 if (this->win) 
878                         this->win=NULL;
879         } else {
880                 callback_list_call_attr_0(this->cbl, attr_window_closed);
881         }
882         return TRUE;
883 }
884
885 static gint
886 keypress(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
887 {
888         struct graphics_priv *this=user_data;
889         int len,ucode;
890         char key[8];
891         ucode=gdk_keyval_to_unicode(event->keyval);
892         len=g_unichar_to_utf8(ucode, key);
893         key[len]='\0';
894         
895         switch (event->keyval) {
896         case GDK_Up:
897                 key[0]=NAVIT_KEY_UP;
898                 key[1]='\0';
899                 break;
900         case GDK_Down:
901                 key[0]=NAVIT_KEY_DOWN;
902                 key[1]='\0';
903                 break;
904         case GDK_Left:
905                 key[0]=NAVIT_KEY_LEFT;
906                 key[1]='\0';
907                 break;
908         case GDK_Right:
909                 key[0]=NAVIT_KEY_RIGHT;
910                 key[1]='\0';
911                 break;
912         case GDK_BackSpace:
913                 key[0]=NAVIT_KEY_BACKSPACE;
914                 key[1]='\0';
915                 break;
916         case GDK_Tab:
917                 key[0]='\t';
918                 key[1]='\0';
919                 break;
920         case GDK_Delete:
921                 key[0]=NAVIT_KEY_DELETE;
922                 key[1]='\0';
923                 break;
924         case GDK_Escape:
925                 key[0]=NAVIT_KEY_BACK;
926                 key[1]='\0';
927                 break;
928         case GDK_Return:
929         case GDK_KP_Enter:
930                 key[0]=NAVIT_KEY_RETURN;
931                 key[1]='\0';
932                 break;
933         case GDK_Book:
934 #ifdef USE_HILDON
935         case GDK_F7:
936 #endif
937                 key[0]=NAVIT_KEY_ZOOM_IN;
938                 key[1]='\0';
939                 break;
940         case GDK_Calendar:
941 #ifdef USE_HILDON
942         case GDK_F8:
943 #endif
944                 key[0]=NAVIT_KEY_ZOOM_OUT;
945                 key[1]='\0';
946                 break;
947         }
948         if (key[0])
949                 callback_list_call_attr_1(this->cbl, attr_keypress, (void *)key);
950         else
951                 dbg(0,"keyval 0x%x\n", event->keyval);
952         
953         return FALSE;
954 }
955
956 static struct graphics_priv *graphics_gtk_drawing_area_new_helper(struct graphics_methods *meth);
957
958 static void
959 overlay_disable(struct graphics_priv *gr, int disabled)
960 {
961         if (!gr->overlay_disabled != !disabled) {
962                 gr->overlay_disabled=disabled;
963                 if (gr->parent) {
964                         GdkRectangle r;
965                         overlay_rect(gr->parent, gr, 0, &r);
966                         gtk_drawing_area_draw(gr->parent, &r);
967                 }
968         }
969 }
970
971 static void
972 overlay_resize(struct graphics_priv *this, struct point *p, int w, int h, int alpha, int wraparound)
973 {
974         //do not dereference parent for non overlay osds
975         if(!this->parent) {
976                 return;
977         }
978
979         int changed = 0;
980         int w2,h2;
981
982         if (w == 0) {
983                 w2 = 1;
984         } else {
985                 w2 = w;
986         }
987
988         if (h == 0) {
989                 h2 = 1;
990         } else {
991                 h2 = h;
992         }
993
994         this->p = *p;
995         if (this->width != w2) {
996                 this->width = w2;
997                 changed = 1;
998         }
999
1000         if (this->height != h2) {
1001                 this->height = h2;
1002                 changed = 1;
1003         }
1004
1005         this->a = alpha >> 8;
1006         this->wraparound = wraparound;
1007
1008         if (changed) {
1009                 // Set the drawables to the right sizes
1010                 g_object_unref(this->drawable);
1011                 g_object_unref(this->background);
1012
1013                 this->drawable=gdk_pixmap_new(this->parent->widget->window, w2, h2, -1);
1014                 this->background=gdk_pixmap_new(this->parent->widget->window, w2, h2, -1);
1015
1016                 if ((w == 0) || (h == 0)) {
1017                         this->overlay_autodisabled = 1;
1018                 } else {
1019                         this->overlay_autodisabled = 0;
1020                 }
1021
1022                 callback_list_call_attr_2(this->cbl, attr_resize, GINT_TO_POINTER(this->width), GINT_TO_POINTER(this->height));
1023         }
1024 }
1025
1026 static void
1027 get_data_window(struct graphics_priv *this, unsigned int xid)
1028 {
1029         if (!xid)
1030                 this->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1031         else
1032                 this->win = gtk_plug_new(xid);
1033         if (!gtk_widget_get_parent(this->widget)) 
1034                 gtk_widget_ref(this->widget);
1035         gtk_window_set_default_size(GTK_WINDOW(this->win), this->win_w, this->win_h);
1036         dbg(1,"h= %i, w= %i\n",this->win_h, this->win_w);
1037         gtk_window_set_title(GTK_WINDOW(this->win), this->window_title);
1038         gtk_window_set_wmclass (GTK_WINDOW (this->win), "navit", this->window_title);
1039         gtk_widget_realize(this->win);
1040         if (gtk_widget_get_parent(this->widget)) 
1041                 gtk_widget_reparent(this->widget, this->win);
1042         else
1043                 gtk_container_add(GTK_CONTAINER(this->win), this->widget);
1044         gtk_widget_show_all(this->win);
1045         GTK_WIDGET_SET_FLAGS (this->widget, GTK_CAN_FOCUS);
1046         gtk_widget_set_sensitive(this->widget, TRUE);
1047         gtk_widget_grab_focus(this->widget);
1048         g_signal_connect(G_OBJECT(this->widget), "key-press-event", G_CALLBACK(keypress), this);
1049         g_signal_connect(G_OBJECT(this->win), "delete_event", G_CALLBACK(delete), this);
1050 }
1051
1052 static int
1053 set_attr(struct graphics_priv *gr, struct attr *attr)
1054 {
1055         dbg(0,"enter\n");
1056         switch (attr->type) {
1057         case attr_windowid:
1058                 get_data_window(gr, attr->u.num);
1059                 return 1;
1060         default:
1061                 return 0;
1062         }
1063 }
1064
1065 static struct graphics_priv *
1066 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h, int alpha, int wraparound)
1067 {
1068         int w2,h2;
1069         struct graphics_priv *this=graphics_gtk_drawing_area_new_helper(meth);
1070         this->colormap=gr->colormap;
1071         this->widget=gr->widget;
1072         this->p=*p;
1073         this->width=w;
1074         this->height=h;
1075         this->parent=gr;
1076
1077         /* If either height or width is 0, we set it to 1 to avoid warnings, and
1078          * disable the overlay. */
1079         if (h == 0) {
1080                 h2 = 1;
1081         } else {
1082                 h2 = h;
1083         }
1084
1085         if (w == 0) {
1086                 w2 = 1;
1087         } else {
1088                 w2 = w;
1089         }
1090
1091         this->background=gdk_pixmap_new(gr->widget->window, w2, h2, -1);
1092         this->drawable=gdk_pixmap_new(gr->widget->window, w2, h2, -1);
1093
1094         if ((w == 0) || (h == 0)) {
1095                 this->overlay_autodisabled = 1;
1096         } else {
1097                 this->overlay_autodisabled = 0;
1098         }
1099
1100         this->next=gr->overlays;
1101         this->a=alpha >> 8;
1102         this->wraparound=wraparound;
1103         gr->overlays=this;
1104         return this;
1105 }
1106
1107 static int gtk_argc;
1108 static char **gtk_argv={NULL};
1109
1110
1111 static int
1112 graphics_gtk_drawing_area_fullscreen(struct window *w, int on)
1113 {
1114         struct graphics_priv *gr=w->priv;
1115         if (on)
1116                 gtk_window_fullscreen(GTK_WINDOW(gr->win));
1117         else
1118                 gtk_window_unfullscreen(GTK_WINDOW(gr->win));
1119         return 1;
1120 }               
1121
1122 static void
1123 graphics_gtk_drawing_area_disable_suspend(struct window *w)
1124 {
1125         struct graphics_priv *gr=w->priv;
1126
1127 #ifndef _WIN32
1128         if (gr->pid)
1129                 kill(gr->pid, SIGWINCH);
1130 #else
1131     dbg(1, "failed to kill() under Windows\n");
1132 #endif
1133 }
1134
1135
1136 static void *
1137 get_data(struct graphics_priv *this, char const *type)
1138 {
1139         FILE *f;
1140         if (!strcmp(type,"gtk_widget"))
1141                 return this->widget;
1142 #ifndef _WIN32
1143         if (!strcmp(type,"xwindow_id"))
1144                 return (void *)GDK_WINDOW_XID(this->win ? this->win->window : this->widget->window);
1145 #endif
1146         if (!strcmp(type,"window")) {
1147                 char *cp = getenv("NAVIT_XID");
1148                 unsigned xid = 0;
1149                 if (cp) 
1150                         xid = strtol(cp, NULL, 0);
1151                 if (!(this->delay & 1))
1152                         get_data_window(this, xid);
1153                 this->window.fullscreen=graphics_gtk_drawing_area_fullscreen;
1154                 this->window.disable_suspend=graphics_gtk_drawing_area_disable_suspend;
1155                 this->window.priv=this;
1156 #if !defined(_WIN32) && !defined(__CEGCC__)
1157                 f=popen("pidof /usr/bin/ipaq-sleep","r");
1158                 if (f) {
1159                         fscanf(f,"%d",&this->pid);
1160                         dbg(1,"ipaq_sleep pid=%d\n", this->pid);
1161                         pclose(f);
1162                 }
1163 #endif
1164                 return &this->window;
1165         }
1166         return NULL;
1167 }
1168
1169 static struct graphics_methods graphics_methods = {
1170         graphics_destroy,
1171         draw_mode,
1172         draw_lines,
1173         draw_polygon,
1174         draw_rectangle,
1175         draw_circle,
1176         draw_text,
1177         draw_image,
1178 #ifdef HAVE_IMLIB2
1179         draw_image_warp,
1180 #else
1181         NULL,
1182 #endif
1183         draw_restore,
1184         draw_drag,
1185         NULL, /* font_new */
1186         gc_new,
1187         background_gc,
1188         overlay_new,
1189         image_new,
1190         get_data,
1191         image_free,
1192         NULL, /* get_text_bbox */
1193         overlay_disable,
1194         overlay_resize,
1195         set_attr,
1196 };
1197
1198 static struct graphics_priv *
1199 graphics_gtk_drawing_area_new_helper(struct graphics_methods *meth)
1200 {
1201         struct font_priv * (*font_freetype_new)(void *meth);
1202         font_freetype_new=plugin_get_font_type("freetype");
1203         if (!font_freetype_new)
1204                 return NULL;
1205         struct graphics_priv *this=g_new0(struct graphics_priv,1);
1206         font_freetype_new(&this->freetype_methods);
1207         *meth=graphics_methods;
1208         meth->font_new=(struct graphics_font_priv *(*)(struct graphics_priv *, struct graphics_font_methods *, char *,  int, int))this->freetype_methods.font_new;
1209         meth->get_text_bbox=this->freetype_methods.get_text_bbox;
1210
1211         return this;
1212 }
1213
1214 static struct graphics_priv *
1215 graphics_gtk_drawing_area_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
1216 {
1217         int i;
1218         GtkWidget *draw;
1219         struct attr *attr;
1220
1221         if (! event_request_system("glib","graphics_gtk_drawing_area_new"))
1222                 return NULL;
1223
1224         draw=gtk_drawing_area_new();
1225         struct graphics_priv *this=graphics_gtk_drawing_area_new_helper(meth);
1226         this->nav = nav;
1227         this->widget=draw;
1228         this->win_w=792;
1229         if ((attr=attr_search(attrs, NULL, attr_w))) 
1230                 this->win_w=attr->u.num;
1231         this->win_h=547;
1232         if ((attr=attr_search(attrs, NULL, attr_h))) 
1233                 this->win_h=attr->u.num;
1234         this->timeout=100;
1235         if ((attr=attr_search(attrs, NULL, attr_timeout))) 
1236                 this->timeout=attr->u.num;
1237         this->delay=0;
1238         if ((attr=attr_search(attrs, NULL, attr_delay))) 
1239                 this->delay=attr->u.num;
1240         if ((attr=attr_search(attrs, NULL, attr_window_title))) 
1241                 this->window_title=g_strdup(attr->u.str);
1242         else
1243                 this->window_title=g_strdup("Navit");
1244         this->cbl=cbl;
1245         this->colormap=gdk_colormap_new(gdk_visual_get_system(),FALSE);
1246         gtk_widget_set_events(draw, GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|GDK_POINTER_MOTION_MASK|GDK_KEY_PRESS_MASK);
1247         g_signal_connect(G_OBJECT(draw), "expose_event", G_CALLBACK(expose), this);
1248         g_signal_connect(G_OBJECT(draw), "configure_event", G_CALLBACK(configure), this);
1249         g_signal_connect(G_OBJECT(draw), "button_press_event", G_CALLBACK(button_press), this);
1250         g_signal_connect(G_OBJECT(draw), "button_release_event", G_CALLBACK(button_release), this);
1251         g_signal_connect(G_OBJECT(draw), "scroll_event", G_CALLBACK(scroll), this);
1252         g_signal_connect(G_OBJECT(draw), "motion_notify_event", G_CALLBACK(motion_notify), this);
1253         g_signal_connect(G_OBJECT(draw), "delete_event", G_CALLBACK(delete), nav);
1254
1255         for (i = 0; i < 8; i++) {
1256                 this->button_press[i].tv_sec = 0;
1257                 this->button_press[i].tv_usec = 0;
1258                 this->button_release[i].tv_sec = 0;
1259                 this->button_release[i].tv_usec = 0;
1260         }
1261
1262         //create hash table for uncompressed image data
1263         if (!hImageDataCount++)
1264                 hImageData = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, graphics_destroy_image);
1265
1266         return this;
1267 }
1268
1269 void
1270 plugin_init(void)
1271 {
1272         gtk_init(&gtk_argc, &gtk_argv);
1273         gtk_set_locale();
1274 #ifdef HAVE_API_WIN32
1275         setlocale(LC_NUMERIC, "C"); /* WIN32 gtk resets LC_NUMERIC */
1276 #endif
1277         plugin_register_graphics_type("gtk_drawing_area", graphics_gtk_drawing_area_new);
1278 }