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