/[zanavi_public1]/navit/navit/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c
ZANavi

Contents of /navit/navit/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c

Parent Directory Parent Directory | Revision Log Revision Log


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

   
Visit the ZANavi Wiki