1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1998 Alexander Larsson
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
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 Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 
23 #include <string.h>
24 #include <stdio.h>
25 #include <math.h>
26 
27 #ifdef GNOME
28 #undef GTK_DISABLE_DEPRECATED
29 #include <gnome.h>
30 #endif
31 
32 #include <gdk/gdkkeysyms.h>
33 
34 #include "intl.h"
35 
36 #include "display.h"
37 #include "group.h"
38 #include "interface.h"
39 #include "focus.h"
40 #include "color.h"
41 #include "object.h"
42 #include "handle_ops.h"
43 #include "connectionpoint_ops.h"
44 #include "menus.h"
45 #include "cut_n_paste.h"
46 #include "message.h"
47 #include "preferences.h"
48 #include "app_procs.h"
49 #include "layer_dialog.h"
50 #include "load_save.h"
51 #include "dia-props.h"
52 #include "render_gdk.h"
53 #include "diatransform.h"
54 
55 static GHashTable *display_ht = NULL;
56 static GdkCursor *current_cursor = NULL;
57 
58 GdkCursor *default_cursor = NULL;
59 
60 static DDisplay *active_display = NULL;
61 
62 
63 typedef struct _IRectangle {
64   int top, bottom;
65   int left,right;
66 } IRectangle;
67 
68 static guint display_hash(DDisplay *ddisp);
69 
70 static void
update_zoom_status(DDisplay * ddisp)71 update_zoom_status(DDisplay *ddisp)
72 {
73   gchar* zoom_text;
74 
75   if (is_integrated_ui ())
76   {
77     zoom_text = g_strdup_printf("%.0f%%",
78 	   ddisp->zoom_factor * 100.0 / DDISPLAY_NORMAL_ZOOM);
79 
80     integrated_ui_toolbar_set_zoom_text (ddisp->common_toolbar, zoom_text);
81   }
82   else
83   {
84     GtkWidget *zoomcombo;
85     zoom_text = g_strdup_printf("%.1f%%",
86 	     ddisp->zoom_factor * 100.0 / DDISPLAY_NORMAL_ZOOM);
87     zoomcombo = ddisp->zoom_status;
88     gtk_entry_set_text(GTK_ENTRY (g_object_get_data (G_OBJECT(zoomcombo), "user_data")),
89 		       zoom_text);
90   }
91 
92   g_free(zoom_text); /* Copied by gtk_entry_set_text */
93 }
94 
95 static void
selection_changed(Diagram * dia,int n,DDisplay * ddisp)96 selection_changed (Diagram* dia, int n, DDisplay* ddisp)
97 {
98   GtkStatusbar *statusbar;
99   guint context_id;
100 
101   /* nothing to do if there is no display with the diagram anymore */
102   if (g_slist_length(dia->displays) < 1)
103     return;
104 
105   statusbar = GTK_STATUSBAR (ddisp->modified_status);
106   context_id = gtk_statusbar_get_context_id (statusbar, "Selection");
107 
108   if (n > 1)
109   {
110     gchar *msg;
111 
112     /* http://www.gnu.org/software/gettext/manual/html_chapter/gettext_10.html#SEC150
113      * Althoug the single objects wont get triggered here some languages have variations on the other numbers
114      */
115     msg = g_strdup_printf (ngettext ("Selection of %d object", "Selection of %d objects", n), n);
116     gtk_statusbar_pop (statusbar, context_id);
117     gtk_statusbar_push (statusbar, context_id, msg);
118     g_free (msg);
119   }
120   else if (n == 1)
121   {
122     /* find the selected objects name - and display it */
123     DiaObject *object = (DiaObject *)ddisp->diagram->data->selected->data;
124     gchar *name = object_get_displayname (object);
125     gchar *msg = g_strdup_printf (_("Selected '%s'"), name);
126 
127     gtk_statusbar_pop (statusbar, context_id);
128     gtk_statusbar_push (statusbar, context_id, msg);
129 
130     g_free (name);
131     g_free (msg);
132   }
133   else
134   {
135     gtk_statusbar_pop (statusbar, context_id);
136   }
137   /* selection-changed signal can also be emitted from outside of the dia core */
138   ddisplay_do_update_menu_sensitivity (ddisp);
139 }
140 
141 static void
append_im_menu(DDisplay * ddisp,GtkAction * action)142 append_im_menu (DDisplay* ddisp, GtkAction* action)
143 {
144   GSList    *proxies;
145   GtkWidget *im_menu;
146   /* GtkWidget *im_menu_tearoff; */
147 
148   proxies = gtk_action_get_proxies (action);
149   while (proxies) {
150     if (GTK_IS_MENU_ITEM (proxies->data)) {
151       im_menu = gtk_menu_new ();
152       /* tearoff should be added depending on gtk settings
153       im_menu_tearoff = gtk_tearoff_menu_item_new ();
154       gtk_menu_shell_append (GTK_MENU_SHELL(im_menu), im_menu_tearoff);
155       */
156       gtk_im_multicontext_append_menuitems (
157         GTK_IM_MULTICONTEXT(ddisp->im_context),
158         GTK_MENU_SHELL(im_menu));
159       gtk_menu_item_set_submenu (GTK_MENU_ITEM(proxies->data), im_menu);
160       gtk_widget_show (GTK_WIDGET (proxies->data));
161       gtk_widget_show (GTK_WIDGET (im_menu));
162     }
163     proxies = proxies->next;
164   }
165 }
166 
167 /** Initialize the various GTK-level thinks in a display after the internal
168  *  data has been set.
169  * @param ddisp A display with all non-GTK/GDK items set.
170  */
171 static void
initialize_display_widgets(DDisplay * ddisp)172 initialize_display_widgets(DDisplay *ddisp)
173 {
174   GtkAction* im_menu_item;
175   static gboolean input_methods_done = FALSE;
176   Diagram *dia = ddisp->diagram;
177   gchar *filename;
178 
179   /*  ddisp->renderer = new_gdk_renderer(ddisp);*/
180 
181   ddisp->im_context = gtk_im_multicontext_new();
182   g_signal_connect (G_OBJECT (ddisp->im_context), "commit",
183                     G_CALLBACK (ddisplay_im_context_commit), ddisp);
184   ddisp->preedit_string = NULL;
185   g_signal_connect (G_OBJECT (ddisp->im_context), "preedit_changed",
186                     G_CALLBACK (ddisplay_im_context_preedit_changed),
187                     ddisp);
188   ddisp->preedit_attrs = NULL;
189 
190   filename = strrchr(dia->filename, G_DIR_SEPARATOR);
191   if (filename==NULL) {
192     filename = dia->filename;
193   } else {
194     filename++;
195   }
196   create_display_shell(ddisp, prefs.new_view.width, prefs.new_view.height,
197 		       filename, prefs.new_view.use_menu_bar, !app_is_embedded());
198 
199   ddisplay_update_statusbar (ddisp);
200 
201   ddisplay_set_origo(ddisp, ddisp->visible.left, ddisp->visible.top);
202   ddisplay_update_scrollbars(ddisp);
203   ddisplay_add_update_all(ddisp);
204 
205   if (!display_ht)
206     display_ht = g_hash_table_new ((GHashFunc) display_hash, NULL);
207 
208   if (!app_is_embedded())
209     ddisplay_set_cursor(ddisp, current_cursor);
210 
211   g_hash_table_insert (display_ht, ddisp->shell, ddisp);
212   g_hash_table_insert (display_ht, ddisp->canvas, ddisp);
213 
214   if (!input_methods_done) {
215       im_menu_item = menus_get_action ("InputMethods");
216       g_assert (im_menu_item);
217       append_im_menu (ddisp, im_menu_item);
218       input_methods_done = TRUE;
219   }
220   /* the diagram menubar gets recreated for every diagram */
221   if (ddisp->menu_bar) {
222     im_menu_item = gtk_action_group_get_action (ddisp->actions, "InputMethods");
223     g_assert (im_menu_item);
224     append_im_menu (ddisp, im_menu_item);
225   }
226 }
227 
228 /** Make a copy of an existing display.  The original does not need to have
229  *  the various GTK-related fields initialized, and so can just have been read
230  *  from a savefile.
231  *  Note that size and position are not handled here yet, but taken from prefs.
232  * @param A display object with non-GTK/GDK fields initialized (same fields as
233  *  new_display initializes before calling initialize_display_widgets()).
234  * @returns A newly allocated display, inserted into the diagram list, with
235  *  same basic layout as the original.
236  */
237 DDisplay *
copy_display(DDisplay * orig_ddisp)238 copy_display(DDisplay *orig_ddisp)
239 {
240   DDisplay *ddisp;
241   Diagram *dia = orig_ddisp->diagram;
242 
243   ddisp = g_new0(DDisplay,1);
244 
245   ddisp->diagram = orig_ddisp->diagram;
246   /* Every display has its own reference */
247   g_object_ref(dia);
248 
249   ddisp->grid = orig_ddisp->grid;
250 
251   ddisp->show_cx_pts = orig_ddisp->show_cx_pts;
252 
253 
254   ddisp->autoscroll = orig_ddisp->autoscroll;
255   ddisp->mainpoint_magnetism = orig_ddisp->mainpoint_magnetism;
256 
257   ddisp->aa_renderer = orig_ddisp->aa_renderer;
258 
259   ddisp->update_areas = orig_ddisp->update_areas;
260   ddisp->display_areas = orig_ddisp->display_areas;
261   ddisp->update_id = 0;
262 
263   diagram_add_ddisplay(dia, ddisp);
264   g_signal_connect (dia, "selection_changed", G_CALLBACK(selection_changed), ddisp);
265   ddisp->origo = orig_ddisp->origo;
266   ddisp->zoom_factor = orig_ddisp->zoom_factor;
267   ddisp->visible = orig_ddisp->visible;
268 
269   initialize_display_widgets(ddisp);
270   return ddisp;  /*  set the user data  */
271 }
272 
273 
274 /** Create a new display for a diagram, using prefs settings.
275  * @param dia Otherwise initialize diagram to create a display for.
276  * @returns A newly created display.
277  */
278 DDisplay *
new_display(Diagram * dia)279 new_display(Diagram *dia)
280 {
281   DDisplay *ddisp;
282   Rectangle visible;
283 
284   ddisp = g_new0(DDisplay,1);
285 
286   ddisp->diagram = dia;
287   /* Every display has it's own reference */
288   g_object_ref(dia);
289 
290   ddisp->grid.visible = prefs.grid.visible;
291   ddisp->grid.snap = prefs.grid.snap;
292 
293   ddisp->show_cx_pts = prefs.show_cx_pts;
294 
295   ddisp->autoscroll = TRUE;
296   ddisp->mainpoint_magnetism = prefs.snap_object;
297 
298   ddisp->aa_renderer = prefs.view_antialised;
299 
300   ddisp->update_areas = NULL;
301   ddisp->display_areas = NULL;
302   ddisp->update_id = 0;
303 
304   diagram_add_ddisplay(dia, ddisp);
305   g_signal_connect (dia, "selection_changed", G_CALLBACK(selection_changed), ddisp);
306   ddisp->origo.x = 0.0;
307   ddisp->origo.y = 0.0;
308   ddisp->zoom_factor = prefs.new_view.zoom/100.0*DDISPLAY_NORMAL_ZOOM;
309   if ((ddisp->diagram) && (ddisp->diagram->data)) {
310     Rectangle *extents = &ddisp->diagram->data->extents;
311 
312     visible.left = extents->left;
313     visible.top = extents->top;
314   } else {
315     visible.left = 0.0;
316     visible.top = 0.0;
317   }
318   visible.right = visible.left + prefs.new_view.width/ddisp->zoom_factor;
319   visible.bottom = visible.top + prefs.new_view.height/ddisp->zoom_factor;
320 
321   ddisp->visible = visible;
322 
323   initialize_display_widgets(ddisp);
324   return ddisp;  /*  set the user data  */
325 }
326 
327 static guint
display_hash(DDisplay * ddisp)328 display_hash(DDisplay *ddisp)
329 {
330   return (gulong) ddisp;
331 }
332 
333 void
ddisplay_transform_coords_double(DDisplay * ddisp,coord x,coord y,double * xi,double * yi)334 ddisplay_transform_coords_double(DDisplay *ddisp,
335 				 coord x, coord y,
336 				 double *xi, double *yi)
337 {
338   Rectangle *visible = &ddisp->visible;
339   double width = dia_renderer_get_width_pixels (ddisp->renderer);
340   double height = dia_renderer_get_height_pixels (ddisp->renderer);
341 
342   *xi = (x - visible->left)  * (real)width / (visible->right - visible->left);
343   *yi = (y - visible->top)  * (real)height / (visible->bottom - visible->top);
344 }
345 
346 
347 void
ddisplay_transform_coords(DDisplay * ddisp,coord x,coord y,int * xi,int * yi)348 ddisplay_transform_coords(DDisplay *ddisp,
349 			  coord x, coord y,
350 			  int *xi, int *yi)
351 {
352   Rectangle *visible = &ddisp->visible;
353   int width = dia_renderer_get_width_pixels (ddisp->renderer);
354   int height = dia_renderer_get_height_pixels (ddisp->renderer);
355 
356   *xi = ROUND ( (x - visible->left)  * (real)width /
357 		(visible->right - visible->left) );
358   *yi = ROUND ( (y - visible->top)  * (real)height /
359 		(visible->bottom - visible->top) );
360 }
361 
362 /* Takes real length and returns pixel length */
363 real
ddisplay_transform_length(DDisplay * ddisp,real len)364 ddisplay_transform_length(DDisplay *ddisp, real len)
365 {
366   return len * ddisp->zoom_factor;
367 }
368 
369 /* Takes pixel length and returns real length */
370 real
ddisplay_untransform_length(DDisplay * ddisp,real len)371 ddisplay_untransform_length(DDisplay *ddisp, real len)
372 {
373   return len / ddisp->zoom_factor;
374 }
375 
376 
377 void
ddisplay_untransform_coords(DDisplay * ddisp,int xi,int yi,coord * x,coord * y)378 ddisplay_untransform_coords(DDisplay *ddisp,
379 			    int xi, int yi,
380 			    coord *x, coord *y)
381 {
382   Rectangle *visible = &ddisp->visible;
383   int width = dia_renderer_get_width_pixels (ddisp->renderer);
384   int height = dia_renderer_get_height_pixels (ddisp->renderer);
385 
386   *x = visible->left + xi*(visible->right - visible->left) / (real)width;
387   *y = visible->top +  yi*(visible->bottom - visible->top) / (real)height;
388 }
389 
390 
391 void
ddisplay_add_update_pixels(DDisplay * ddisp,Point * point,int pixel_width,int pixel_height)392 ddisplay_add_update_pixels(DDisplay *ddisp, Point *point,
393 			  int pixel_width, int pixel_height)
394 {
395   Rectangle rect;
396   real size_x, size_y;
397 
398   size_x = ddisplay_untransform_length(ddisp, pixel_width+1);
399   size_y = ddisplay_untransform_length(ddisp, pixel_height+1);
400 
401   rect.left = point->x - size_x/2.0;
402   rect.top = point->y - size_y/2.0;
403   rect.right = point->x + size_x/2.0;
404   rect.bottom = point->y + size_y/2.0;
405 
406   ddisplay_add_update(ddisp, &rect);
407 }
408 
409 /** Free display_areas list */
410 static void
ddisplay_free_display_areas(DDisplay * ddisp)411 ddisplay_free_display_areas(DDisplay *ddisp)
412 {
413   GSList *l;
414   l = ddisp->display_areas;
415   while(l!=NULL) {
416     g_free(l->data);
417     l = g_slist_next(l);
418   }
419   g_slist_free(ddisp->display_areas);
420   ddisp->display_areas = NULL;
421 }
422 
423 /** Free update_areas list */
424 static void
ddisplay_free_update_areas(DDisplay * ddisp)425 ddisplay_free_update_areas(DDisplay *ddisp)
426 {
427   GSList *l;
428   l = ddisp->update_areas;
429   while(l!=NULL) {
430     g_free(l->data);
431     l = g_slist_next(l);
432   }
433   g_slist_free(ddisp->update_areas);
434   ddisp->update_areas = NULL;
435 }
436 
437 /** Marks the entire visible area for update.
438  * Throws out old updates, since everything will be updated anyway.
439  */
440 void
ddisplay_add_update_all(DDisplay * ddisp)441 ddisplay_add_update_all(DDisplay *ddisp)
442 {
443   if (ddisp->update_areas != NULL) {
444     ddisplay_free_update_areas(ddisp);
445   }
446   if (ddisp->display_areas != NULL) {
447     ddisplay_free_display_areas(ddisp);
448   }
449   ddisplay_add_update(ddisp, &ddisp->visible);
450 }
451 
452 /** Marks a rectangle for update, with a pixel border around it.
453  */
454 void
ddisplay_add_update_with_border(DDisplay * ddisp,Rectangle * rect,int pixel_border)455 ddisplay_add_update_with_border(DDisplay *ddisp, Rectangle *rect,
456 				int pixel_border)
457 {
458   Rectangle r;
459   real size = ddisplay_untransform_length(ddisp, pixel_border+1);
460 
461   r.left = rect->left-size;
462   r.top = rect->top-size;
463   r.right = rect->right+size;
464   r.bottom = rect->bottom+size;
465 
466   ddisplay_add_update(ddisp, &r);
467 }
468 
469 void
ddisplay_add_update(DDisplay * ddisp,Rectangle * rect)470 ddisplay_add_update(DDisplay *ddisp, Rectangle *rect)
471 {
472   Rectangle *r;
473   int top,bottom,left,right;
474   Rectangle *visible;
475   int width, height;
476 
477   if (!ddisp->renderer)
478     return; /* can happen at creation time of the diagram */
479   width = dia_renderer_get_width_pixels (ddisp->renderer);
480   height = dia_renderer_get_height_pixels (ddisp->renderer);
481 
482   if (!rectangle_intersects(rect, &ddisp->visible))
483     return;
484 
485   /* Temporarily just do a union of all rectangles: */
486   if (ddisp->update_areas==NULL) {
487     r = g_new(Rectangle,1);
488     *r = *rect;
489     rectangle_intersection(r, &ddisp->visible);
490     ddisp->update_areas = g_slist_prepend(ddisp->update_areas, r);
491   } else {
492     r = (Rectangle *) ddisp->update_areas->data;
493     rectangle_union(r, rect);
494     rectangle_intersection(r, &ddisp->visible);
495   }
496 
497   visible = &ddisp->visible;
498   left = floor( (r->left - visible->left)  * (real)width /
499 		(visible->right - visible->left) ) - 1;
500   top = floor( (r->top - visible->top)  * (real)height /
501 	       (visible->bottom - visible->top) ) - 1;
502   right = ceil( (r->right - visible->left)  * (real)width /
503 		(visible->right - visible->left) ) + 1;
504   bottom = ceil( (r->bottom - visible->top)  * (real)height /
505 		 (visible->bottom - visible->top) ) + 1;
506 
507   ddisplay_add_display_area(ddisp,
508 			    left, top,
509 			    right, bottom);
510 }
511 
512 void
ddisplay_add_display_area(DDisplay * ddisp,int left,int top,int right,int bottom)513 ddisplay_add_display_area(DDisplay *ddisp,
514 			  int left, int top,
515 			  int right, int bottom)
516 {
517   IRectangle *r;
518 
519   if (!ddisp->renderer)
520     return; /* if we don't have a renderer yet prefer ignoring over crashing */
521   if (left < 0)
522     left = 0;
523   if (top < 0)
524     top = 0;
525   if (right > dia_renderer_get_width_pixels (ddisp->renderer))
526     right = dia_renderer_get_width_pixels (ddisp->renderer);
527   if (bottom > dia_renderer_get_height_pixels (ddisp->renderer))
528     bottom = dia_renderer_get_height_pixels (ddisp->renderer);
529 
530   /* draw some rectangles to show where updates are...*/
531   /*  gdk_draw_rectangle(ddisp->canvas->window, ddisp->canvas->style->black_gc, TRUE, left, top, right-left,bottom-top); */
532 
533   /* Temporarily just do a union of all Irectangles: */
534   if (ddisp->display_areas==NULL) {
535     r = g_new(IRectangle,1);
536     r->top = top; r->bottom = bottom;
537     r->left = left; r->right = right;
538     ddisp->display_areas = g_slist_prepend(ddisp->display_areas, r);
539   } else {
540     r = (IRectangle *) ddisp->display_areas->data;
541 
542     r->top = MIN( r->top, top );
543     r->bottom = MAX( r->bottom, bottom );
544     r->left = MIN( r->left, left );
545     r->right = MAX( r->right, right );
546   }
547 }
548 
549 static gboolean
ddisplay_update_handler(DDisplay * ddisp)550 ddisplay_update_handler(DDisplay *ddisp)
551 {
552   GSList *l;
553   IRectangle *ir;
554   Rectangle *r, totrect;
555   DiaInteractiveRendererInterface *renderer;
556 
557   /* Renders updates to pixmap + copies display_areas to canvas(screen) */
558   renderer = DIA_GET_INTERACTIVE_RENDERER_INTERFACE (ddisp->renderer);
559 
560   /* Only update if update_areas exist */
561   l = ddisp->update_areas;
562   if (l != NULL)
563   {
564     totrect = *(Rectangle *) l->data;
565 
566     g_return_val_if_fail (   renderer->clip_region_clear != NULL
567                           && renderer->clip_region_add_rect != NULL, FALSE);
568 
569     renderer->clip_region_clear (ddisp->renderer);
570 
571     while(l!=NULL) {
572       r = (Rectangle *) l->data;
573 
574       rectangle_union(&totrect, r);
575       renderer->clip_region_add_rect (ddisp->renderer, r);
576 
577       l = g_slist_next(l);
578     }
579     /* Free update_areas list: */
580     ddisplay_free_update_areas(ddisp);
581 
582     totrect.left -= 0.1;
583     totrect.right += 0.1;
584     totrect.top -= 0.1;
585     totrect.bottom += 0.1;
586 
587     ddisplay_render_pixmap(ddisp, &totrect);
588   }
589 
590   l = ddisp->display_areas;
591   while(l!=NULL) {
592     ir = (IRectangle *) l->data;
593 
594     g_return_val_if_fail (renderer->copy_to_window, FALSE);
595     renderer->copy_to_window(ddisp->renderer,
596                              ddisp->canvas->window,
597                              ir->left, ir->top,
598                              ir->right - ir->left, ir->bottom - ir->top);
599 
600     l = g_slist_next(l);
601   }
602 
603   ddisplay_free_display_areas(ddisp);
604 
605   ddisp->update_id = 0;
606 
607   return FALSE;
608 }
609 
610 void
ddisplay_flush(DDisplay * ddisp)611 ddisplay_flush(DDisplay *ddisp)
612 {
613   /* if no update is queued, queue update */
614   if (!ddisp->update_id)
615     ddisp->update_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)ddisplay_update_handler, ddisp, NULL);
616 }
617 
618 static void
ddisplay_obj_render(DiaObject * obj,DiaRenderer * renderer,int active_layer,gpointer data)619 ddisplay_obj_render(DiaObject *obj, DiaRenderer *renderer,
620 		    int active_layer,
621 		    gpointer data)
622 {
623   DDisplay *ddisp = (DDisplay *)data;
624   int i;
625 
626   DIA_RENDERER_GET_CLASS(renderer)->draw_object(renderer, obj);
627   if (ddisp->show_cx_pts &&
628       obj->parent_layer != NULL && obj->parent_layer->connectable) {
629     for (i=0;i<obj->num_connections;i++) {
630       connectionpoint_draw(obj->connections[i], ddisp);
631     }
632   }
633 }
634 
635 void
ddisplay_render_pixmap(DDisplay * ddisp,Rectangle * update)636 ddisplay_render_pixmap(DDisplay *ddisp, Rectangle *update)
637 {
638   GList *list;
639   DiaObject *obj;
640   int i;
641   DiaInteractiveRendererInterface *renderer;
642 #ifdef TRACES
643   GTimer *timer;
644 #endif
645 
646   if (ddisp->renderer==NULL) {
647     printf("ERROR! Renderer was NULL!!\n");
648     return;
649   }
650 
651   renderer = DIA_GET_INTERACTIVE_RENDERER_INTERFACE (ddisp->renderer);
652 
653   /* Erase background */
654   g_return_if_fail (renderer->fill_pixel_rect != NULL);
655   DIA_RENDERER_GET_CLASS(ddisp->renderer)->begin_render(ddisp->renderer);
656   renderer->fill_pixel_rect (ddisp->renderer,
657 			     0, 0,
658 		             dia_renderer_get_width_pixels (ddisp->renderer),
659 			     dia_renderer_get_height_pixels (ddisp->renderer),
660 			     &ddisp->diagram->data->bg_color);
661 
662   /* Draw grid */
663   grid_draw(ddisp, update);
664   pagebreak_draw(ddisp, update);
665 
666 #ifdef TRACES
667   timer = g_timer_new();
668 #endif
669   data_render(ddisp->diagram->data, ddisp->renderer, update,
670 	      ddisplay_obj_render, (gpointer) ddisp);
671 #ifdef TRACES
672   g_print ("data_render(%g%%) took %g seconds\n", ddisp->zoom_factor * 5.0, g_timer_elapsed (timer, NULL));
673   g_timer_destroy (timer);
674 #endif
675   /* Draw handles for all selected objects */
676   list = ddisp->diagram->data->selected;
677   while (list!=NULL) {
678     obj = (DiaObject *) list->data;
679 
680     for (i=0;i<obj->num_handles;i++) {
681        handle_draw(obj->handles[i], ddisp);
682      }
683     list = g_list_next(list);
684   }
685   DIA_RENDERER_GET_CLASS(ddisp->renderer)->end_render(ddisp->renderer);
686 }
687 
688 void
ddisplay_update_scrollbars(DDisplay * ddisp)689 ddisplay_update_scrollbars(DDisplay *ddisp)
690 {
691   Rectangle *extents = &ddisp->diagram->data->extents;
692   Rectangle *visible = &ddisp->visible;
693   GtkAdjustment *hsbdata, *vsbdata;
694 
695   hsbdata = ddisp->hsbdata;
696   /* Horizontal: */
697   hsbdata->lower = MIN(extents->left, visible->left);
698   hsbdata->upper = MAX(extents->right, visible->right);
699   hsbdata->page_size = visible->right - visible->left - 0.0001;
700   /* remove some to fix strange behaviour in gtk_range_adjustment_changed */
701   hsbdata->page_increment = (visible->right - visible->left) / 2.0;
702   hsbdata->step_increment = (visible->right - visible->left) / 10.0;
703   hsbdata->value = visible->left;
704 
705   g_signal_emit_by_name (G_OBJECT (ddisp->hsbdata), "changed");
706 
707   /* Vertical: */
708   vsbdata = ddisp->vsbdata;
709   vsbdata->lower = MIN(extents->top, visible->top);
710   vsbdata->upper = MAX(extents->bottom, visible->bottom);
711   vsbdata->page_size = visible->bottom - visible->top - 0.00001;
712   /* remove some to fix strange behaviour in gtk_range_adjustment_changed */
713   vsbdata->page_increment = (visible->bottom - visible->top) / 2.0;
714   vsbdata->step_increment = (visible->bottom - visible->top) / 10.0;
715   vsbdata->value = visible->top;
716 
717   g_signal_emit_by_name (G_OBJECT (ddisp->vsbdata), "changed");
718 }
719 
720 void
ddisplay_set_origo(DDisplay * ddisp,coord x,coord y)721 ddisplay_set_origo(DDisplay *ddisp, coord x, coord y)
722 {
723   Rectangle *extents = &ddisp->diagram->data->extents;
724   Rectangle *visible = &ddisp->visible;
725   int width, height;
726 
727   /*  updaterar origo+visible+rulers */
728   ddisp->origo.x = x;
729   ddisp->origo.y = y;
730 
731   if (ddisp->zoom_factor<DDISPLAY_MIN_ZOOM)
732     ddisp->zoom_factor = DDISPLAY_MIN_ZOOM;
733 
734   if (ddisp->zoom_factor > DDISPLAY_MAX_ZOOM)
735     ddisp->zoom_factor = DDISPLAY_MAX_ZOOM;
736 
737   width = dia_renderer_get_width_pixels (ddisp->renderer);
738   height = dia_renderer_get_height_pixels (ddisp->renderer);
739 
740   visible->left = ddisp->origo.x;
741   visible->top = ddisp->origo.y;
742   visible->right = ddisp->origo.x + ddisplay_untransform_length(ddisp, width);
743   visible->bottom = ddisp->origo.y + ddisplay_untransform_length(ddisp, height);
744 
745   gtk_ruler_set_range  (GTK_RULER (ddisp->hrule),
746 			visible->left,
747 			visible->right,
748 			0.0f /* position*/,
749 			MAX(extents->right, visible->right)/* max_size*/);
750   gtk_ruler_set_range  (GTK_RULER (ddisp->vrule),
751 			visible->top,
752 			visible->bottom,
753 			0.0f /*        position*/,
754 			MAX(extents->bottom, visible->bottom)/* max_size*/);
755 }
756 
757 void
ddisplay_zoom(DDisplay * ddisp,Point * point,real magnify)758 ddisplay_zoom(DDisplay *ddisp, Point *point, real magnify)
759 {
760   Rectangle *visible;
761   real width, height, old_zoom;
762 
763   visible = &ddisp->visible;
764 
765   if ((ddisp->zoom_factor <= DDISPLAY_MIN_ZOOM) && (magnify<=1.0))
766     return;
767   if ((ddisp->zoom_factor >= DDISPLAY_MAX_ZOOM) && (magnify>=1.0))
768     return;
769 
770   old_zoom = ddisp->zoom_factor;
771   ddisp->zoom_factor = old_zoom * magnify;
772 
773   /* clip once more */
774   if (ddisp->zoom_factor < DDISPLAY_MIN_ZOOM)
775     ddisp->zoom_factor = DDISPLAY_MIN_ZOOM;
776   else if (ddisp->zoom_factor > DDISPLAY_MAX_ZOOM)
777     ddisp->zoom_factor = DDISPLAY_MAX_ZOOM;
778 
779   /* the real one used - after clipping */
780   magnify = ddisp->zoom_factor / old_zoom;
781   width = (visible->right - visible->left)/magnify;
782   height = (visible->bottom - visible->top)/magnify;
783 
784 
785   ddisplay_set_origo(ddisp, point->x - width/2.0, point->y - height/2.0);
786 
787   ddisplay_update_scrollbars(ddisp);
788   ddisplay_add_update_all(ddisp);
789   ddisplay_flush(ddisp);
790 
791   update_zoom_status (ddisp);
792 }
793 
794 /*
795    When using the mouse wheel button to zoom in and out, it is more
796    intuitive to maintain the drawing zoom center-point based on the
797    cursor position. This can help orientation and prevent the drawing
798    from "jumping" around while zooming in and out.
799  */
800 void
ddisplay_zoom_centered(DDisplay * ddisp,Point * point,real magnify)801 ddisplay_zoom_centered(DDisplay *ddisp, Point *point, real magnify)
802 {
803   Rectangle *visible;
804   real width, height;
805   /* cursor position ratios */
806   real rx,ry;
807 
808   if ((ddisp->zoom_factor <= DDISPLAY_MIN_ZOOM) && (magnify<=1.0))
809     return;
810   if ((ddisp->zoom_factor >= DDISPLAY_MAX_ZOOM) && (magnify>=1.0))
811     return;
812 
813   visible = &ddisp->visible;
814 
815   /* calculate cursor position ratios */
816   rx = (point->x-visible->left)/(visible->right - visible->left);
817   ry = (point->y-visible->top)/(visible->bottom - visible->top);
818 
819   width = (visible->right - visible->left)/magnify;
820   height = (visible->bottom - visible->top)/magnify;
821 
822   ddisp->zoom_factor *= magnify;
823 
824   /* set new origin based on the calculated ratios before zooming */
825   ddisplay_set_origo(ddisp, point->x-(width*rx),point->y-(height*ry));
826 
827   ddisplay_update_scrollbars(ddisp);
828   ddisplay_add_update_all(ddisp);
829   ddisplay_flush(ddisp);
830 
831   update_zoom_status (ddisp);
832 }
833 
834 /** Set the display's snap-to-grid setting, updating menu and button
835  * in the process */
836 void
ddisplay_set_snap_to_grid(DDisplay * ddisp,gboolean snap)837 ddisplay_set_snap_to_grid(DDisplay *ddisp, gboolean snap)
838 {
839   GtkToggleAction *snap_to_grid;
840   ddisp->grid.snap = snap;
841 
842     if (ddisp->menu_bar == NULL) {
843       snap_to_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptogrid"));
844       if (is_integrated_ui ())
845          integrated_ui_toolbar_grid_snap_synchronize_to_display (ddisp);
846     } else {
847       snap_to_grid = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewSnaptogrid"));
848     }
849   /* Currently, this can cause double emit, but that's a small problem.
850    */
851   gtk_toggle_action_set_active (snap_to_grid, ddisp->grid.snap);
852   ddisplay_update_statusbar(ddisp);
853 }
854 
855 /** Update the button showing whether snap-to-grid is on */
856 static void
update_snap_grid_status(DDisplay * ddisp)857 update_snap_grid_status(DDisplay *ddisp)
858 {
859   if (ddisp->grid_status)
860   {
861     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ddisp->grid_status),
862                                   ddisp->grid.snap);
863   }
864 }
865 
866 /** Set the display's mainpoint magnetism setting, updating menu and button
867  * in the process */
868 void
ddisplay_set_snap_to_objects(DDisplay * ddisp,gboolean magnetic)869 ddisplay_set_snap_to_objects(DDisplay *ddisp, gboolean magnetic)
870 {
871   GtkToggleAction *mainpoint_magnetism;
872   ddisp->mainpoint_magnetism = magnetic;
873 
874   if (ddisp->menu_bar == NULL) {
875     mainpoint_magnetism = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptoobjects"));
876     if (is_integrated_ui ())
877       integrated_ui_toolbar_object_snap_synchronize_to_display (ddisp);
878   } else {
879     mainpoint_magnetism = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewSnaptoobjects"));
880   }
881 
882   /* Currently, this can cause double emit, but that's a small problem.
883    */
884   gtk_toggle_action_set_active (mainpoint_magnetism, ddisp->mainpoint_magnetism);
885   ddisplay_update_statusbar(ddisp);
886 }
887 
888 /** Update the button showing whether mainpoint magnetism is on */
889 static void
update_mainpoint_status(DDisplay * ddisp)890 update_mainpoint_status(DDisplay *ddisp)
891 {
892   if (ddisp->mainpoint_status)
893   {
894     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ddisp->mainpoint_status),
895                                  ddisp->mainpoint_magnetism);
896   }
897 }
898 
899 /** Scroll display to where point x,y (window coords) is visible */
900 gboolean
ddisplay_autoscroll(DDisplay * ddisp,int x,int y)901 ddisplay_autoscroll(DDisplay *ddisp, int x, int y)
902 {
903   guint16 width, height;
904   Point scroll;
905 
906   if (! ddisp->autoscroll)
907     return FALSE;
908 
909   scroll.x = scroll.y = 0;
910 
911   width = GTK_WIDGET(ddisp->canvas)->allocation.width;
912   height = GTK_WIDGET(ddisp->canvas)->allocation.height;
913 
914   if (x < 0)
915   {
916     scroll.x = x;
917   }
918   else if ( x > width)
919   {
920     scroll.x = x - width;
921   }
922 
923   if (y < 0)
924   {
925     scroll.y = y;
926   }
927   else if (y > height)
928   {
929     scroll.y = y - height;
930   }
931 
932   if ((scroll.x != 0) || (scroll.y != 0))
933   {
934     gboolean scrolled;
935 
936     scroll.x = ddisplay_untransform_length(ddisp, scroll.x);
937     scroll.y = ddisplay_untransform_length(ddisp, scroll.y);
938 
939     scrolled = ddisplay_scroll(ddisp, &scroll);
940 
941     if (scrolled) {
942       ddisplay_flush(ddisp);
943       return TRUE;
944     }
945   }
946   return FALSE;
947 }
948 
949 /** Scroll the display by delta (diagram coords) */
950 gboolean
ddisplay_scroll(DDisplay * ddisp,Point * delta)951 ddisplay_scroll(DDisplay *ddisp, Point *delta)
952 {
953   Rectangle *visible = &ddisp->visible;
954   real width = visible->right - visible->left;
955   real height = visible->bottom - visible->top;
956 
957   Rectangle extents = ddisp->diagram->data->extents;
958   real ex_width = extents.right - extents.left;
959   real ex_height = extents.bottom - extents.top;
960 
961   Point new_origo = ddisp->origo;
962   point_add(&new_origo, delta);
963 
964   rectangle_union(&extents, visible);
965 
966   if (new_origo.x < extents.left - ex_width)
967     new_origo.x = extents.left - ex_width;
968 
969   if (new_origo.x+width > extents.right + ex_width)
970     new_origo.x = extents.right - width + ex_width;
971 
972   if (new_origo.y < extents.top - ex_height)
973     new_origo.y = extents.top - ex_height;
974 
975   if (new_origo.y+height > extents.bottom + ex_height)
976     new_origo.y = extents.bottom - height + ex_height;
977 
978   if ( (new_origo.x != ddisp->origo.x) ||
979        (new_origo.y != ddisp->origo.y) ) {
980     ddisplay_set_origo(ddisp, new_origo.x, new_origo.y);
981     ddisplay_update_scrollbars(ddisp);
982     ddisplay_add_update_all(ddisp);
983     return TRUE;
984   }
985   return FALSE;
986 }
987 
ddisplay_scroll_up(DDisplay * ddisp)988 void ddisplay_scroll_up(DDisplay *ddisp)
989 {
990   Point delta;
991 
992   delta.x = 0;
993   delta.y = -(ddisp->visible.bottom - ddisp->visible.top)/4.0;
994 
995   ddisplay_scroll(ddisp, &delta);
996 }
997 
ddisplay_scroll_down(DDisplay * ddisp)998 void ddisplay_scroll_down(DDisplay *ddisp)
999 {
1000   Point delta;
1001 
1002   delta.x = 0;
1003   delta.y = (ddisp->visible.bottom - ddisp->visible.top)/4.0;
1004 
1005   ddisplay_scroll(ddisp, &delta);
1006 }
1007 
ddisplay_scroll_left(DDisplay * ddisp)1008 void ddisplay_scroll_left(DDisplay *ddisp)
1009 {
1010   Point delta;
1011 
1012   delta.x = -(ddisp->visible.right - ddisp->visible.left)/4.0;
1013   delta.y = 0;
1014 
1015   ddisplay_scroll(ddisp, &delta);
1016 }
1017 
ddisplay_scroll_right(DDisplay * ddisp)1018 void ddisplay_scroll_right(DDisplay *ddisp)
1019 {
1020   Point delta;
1021 
1022   delta.x = (ddisp->visible.right - ddisp->visible.left)/4.0;
1023   delta.y = 0;
1024 
1025   ddisplay_scroll(ddisp, &delta);
1026 }
1027 
1028 /** Scroll display to have the diagram point p at the center.
1029  * Returns TRUE if anything changed. */
1030 gboolean
ddisplay_scroll_center_point(DDisplay * ddisp,Point * p)1031 ddisplay_scroll_center_point(DDisplay *ddisp, Point *p)
1032 {
1033   Point center;
1034 
1035   /* Find current center */
1036   center.x = (ddisp->visible.right+ddisp->visible.left)/2;
1037   center.y = (ddisp->visible.top+ddisp->visible.bottom)/2;
1038 
1039   point_sub(p, &center);
1040   return ddisplay_scroll(ddisp, p);
1041 }
1042 
1043 /** Scroll display so that obj is centered.
1044  * Returns TRUE if anything changed.  */
1045 gboolean
ddisplay_scroll_to_object(DDisplay * ddisp,DiaObject * obj)1046 ddisplay_scroll_to_object(DDisplay *ddisp, DiaObject *obj)
1047 {
1048   Rectangle r = obj->bounding_box;
1049 
1050   Point p;
1051   p.x = (r.left+r.right)/2;
1052   p.y = (r.top+r.bottom)/2;
1053 
1054   display_set_active(ddisp);
1055   return ddisplay_scroll_center_point(ddisp, &p);
1056 }
1057 
1058 /** Ensure the object is visible but minimize scrolling
1059  */
1060 gboolean
ddisplay_present_object(DDisplay * ddisp,DiaObject * obj)1061 ddisplay_present_object(DDisplay *ddisp, DiaObject *obj)
1062 {
1063   const Rectangle *r = dia_object_get_enclosing_box(obj);
1064   const Rectangle *v = &ddisp->visible;
1065 
1066   display_set_active(ddisp);
1067   if  (!rectangle_in_rectangle(v, r)) {
1068     Point delta = { 0, 0 };
1069 
1070     if ((r->right - r->left) > (v->right - v->left)) /* object bigger than visible area */
1071       delta.x = (r->left - v->left + r->right - v->right) / 2;
1072     else if (r->left < v->left)
1073       delta.x = r->left - v->left;
1074     else if  (r->right > v->right)
1075       delta.x = r->right - v->right;
1076 
1077     if ((r->bottom - r->top) > (v->bottom - v->top)) /* object bigger than visible area */
1078       delta.y = (r->top - v->top + r->bottom - v->bottom) / 2;
1079     else if (r->top < v->top)
1080       delta.y = r->top - v->top;
1081     else if  (r->bottom > v->bottom)
1082       delta.y = r->bottom - v->bottom;
1083 
1084     ddisplay_scroll(ddisp, &delta);
1085     return TRUE;
1086   }
1087   return FALSE;
1088 }
1089 
1090 /**
1091  * Kind of dirty way to init an antialiased renderer, there should be some plug-in interface to do this.
1092  * Now with the Libart renderer being a plug-in and the cairo renderer having issues with highlighting
1093  * (  http://bugzilla.gnome.org/show_bug.cgi?id=576548 ) it seems reasonable to have default at
1094  * Libart, also becuase you loose less when it is switched off ;-)
1095  */
1096 static DiaRenderer *
new_aa_renderer(DDisplay * ddisp)1097 new_aa_renderer (DDisplay *ddisp)
1098 {
1099   GType renderer_type;
1100 
1101   renderer_type = g_type_from_name ("DiaLibartRenderer");
1102   if (renderer_type) {
1103     DiaRenderer *renderer = g_object_new(renderer_type, NULL);
1104     g_object_set (renderer,
1105                   "transform", dia_transform_new (&ddisp->visible, &ddisp->zoom_factor),
1106 		  NULL);
1107     return renderer;
1108   }
1109 
1110   renderer_type = g_type_from_name ("DiaCairoInteractiveRenderer");
1111   if (renderer_type) {
1112     DiaRenderer *renderer = g_object_new(renderer_type, NULL);
1113     g_object_set (renderer,
1114                   "zoom", &ddisp->zoom_factor,
1115 		  "rect", &ddisp->visible,
1116 		  NULL);
1117     return renderer;
1118   }
1119 
1120   /* we really should not come here but instead disable the menu command earlier */
1121   message_warning (_("No anti-aliased renderer found"));
1122   /* fallback: built-in libart renderer */
1123   return new_gdk_renderer (ddisp);
1124 }
1125 
1126 void
ddisplay_set_renderer(DDisplay * ddisp,int aa_renderer)1127 ddisplay_set_renderer(DDisplay *ddisp, int aa_renderer)
1128 {
1129   int width, height;
1130 
1131   /* dont mix new renderer with old updates */
1132   if (ddisp->update_id) {
1133     g_source_remove (ddisp->update_id);
1134     ddisp->update_id = 0;
1135   }
1136 
1137   if (ddisp->renderer)
1138     g_object_unref (ddisp->renderer);
1139 
1140   ddisp->aa_renderer = aa_renderer;
1141 
1142   width = ddisp->canvas->allocation.width;
1143   height = ddisp->canvas->allocation.height;
1144 
1145   if (ddisp->aa_renderer){
1146     ddisp->renderer = new_aa_renderer (ddisp);
1147   } else {
1148     ddisp->renderer = new_gdk_renderer(ddisp);
1149   }
1150 
1151   dia_renderer_set_size(ddisp->renderer, ddisp->canvas->window, width, height);
1152 }
1153 
1154 void
ddisplay_resize_canvas(DDisplay * ddisp,int width,int height)1155 ddisplay_resize_canvas(DDisplay *ddisp,
1156 		       int width,  int height)
1157 {
1158   if (ddisp->renderer==NULL) {
1159     if (ddisp->aa_renderer)
1160       ddisp->renderer = new_aa_renderer (ddisp);
1161     else
1162       ddisp->renderer = new_gdk_renderer(ddisp);
1163   }
1164 
1165   dia_renderer_set_size(ddisp->renderer, ddisp->canvas->window, width, height);
1166 
1167   ddisplay_set_origo(ddisp, ddisp->origo.x, ddisp->origo.y);
1168 
1169   ddisplay_add_update_all(ddisp);
1170   ddisplay_flush(ddisp);
1171 }
1172 
1173 DDisplay *
ddisplay_active(void)1174 ddisplay_active(void)
1175 {
1176   return active_display;
1177 }
1178 
1179 Diagram *
ddisplay_active_diagram(void)1180 ddisplay_active_diagram(void)
1181 {
1182   DDisplay *ddisp = ddisplay_active ();
1183 
1184   if (!ddisp) return NULL;
1185   return ddisp->diagram;
1186 }
1187 
1188 static void
ddisp_destroy(DDisplay * ddisp)1189 ddisp_destroy(DDisplay *ddisp)
1190 {
1191   g_signal_handlers_disconnect_by_func (ddisp->diagram, selection_changed, ddisp);
1192 
1193   g_object_unref (G_OBJECT (ddisp->im_context));
1194   ddisp->im_context = NULL;
1195 
1196   ddisplay_im_context_preedit_reset(ddisp, get_active_focus((DiagramData *) ddisp->diagram));
1197 
1198   /* This calls ddisplay_really_destroy */
1199   if (ddisp->is_standalone_window)
1200     gtk_widget_destroy (ddisp->shell);
1201   else {
1202     gtk_widget_destroy (ddisp->container);
1203     ddisplay_really_destroy (ddisp);
1204   }
1205 }
1206 
1207 static void
are_you_sure_close_dialog_respond(GtkWidget * widget,gint response_id,gpointer user_data)1208 are_you_sure_close_dialog_respond(GtkWidget *widget, /* the dialog */
1209                                   gint       response_id,
1210                                   gpointer   user_data) /* the display */
1211 {
1212   DDisplay *ddisp = (DDisplay *)user_data;
1213   gboolean close_ddisp = TRUE;
1214 
1215   switch (response_id) {
1216   case GTK_RESPONSE_YES :
1217     /* save changes */
1218     if (!diagram_save(ddisp->diagram, ddisp->diagram->filename))
1219       close_ddisp = FALSE;
1220 
1221     if (ddisp->update_id && close_ddisp) {
1222       g_source_remove (ddisp->update_id);
1223       ddisp->update_id = 0;
1224     }
1225     /* fall through */
1226   case GTK_RESPONSE_NO :
1227     if (close_ddisp)
1228       ddisp_destroy (ddisp);
1229     /* fall through */
1230   case GTK_RESPONSE_CANCEL :
1231   case GTK_RESPONSE_NONE :
1232   case GTK_RESPONSE_DELETE_EVENT : /* closing via window manager */
1233     gtk_widget_destroy(widget);
1234     break;
1235   default :
1236     g_assert_not_reached();
1237   }
1238 }
1239 
1240 void
ddisplay_close(DDisplay * ddisp)1241 ddisplay_close(DDisplay *ddisp)
1242 {
1243   Diagram *dia;
1244   GtkWidget *dialog, *button;
1245   gchar *fname;
1246 
1247   g_return_if_fail(ddisp != NULL);
1248 
1249   dia = ddisp->diagram;
1250 
1251   if ( (g_slist_length(dia->displays) > 1) ||
1252        (!diagram_is_modified(dia)) ) {
1253     ddisp_destroy(ddisp);
1254     return;
1255   }
1256 
1257   fname = dia->filename;
1258   if (!fname)
1259     fname = _("<unnamed>");
1260 
1261   dialog = gtk_message_dialog_new(GTK_WINDOW (ddisp->shell),
1262                                   GTK_DIALOG_MODAL,
1263                                   GTK_MESSAGE_QUESTION,
1264                                   GTK_BUTTONS_NONE, /* no standard buttons */
1265 				  _("Closing diagram without saving"));
1266   gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1267     _("The diagram '%s'\n"
1268       "has not been saved. Save changes now?"), fname);
1269   gtk_window_set_title (GTK_WINDOW(dialog), _("Close Diagram"));
1270 
1271   button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
1272   gtk_dialog_add_action_widget (GTK_DIALOG(dialog), button, GTK_RESPONSE_CANCEL);
1273 
1274   button = gtk_button_new_with_mnemonic (_("_Discard Changes"));
1275   gtk_dialog_add_action_widget (GTK_DIALOG(dialog), button, GTK_RESPONSE_NO);
1276 
1277   /* button = gtk_button_new_with_label (_("Save and Close")); */
1278   button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
1279   gtk_dialog_add_action_widget (GTK_DIALOG(dialog), button, GTK_RESPONSE_YES);
1280   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1281   gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_YES);
1282 
1283   g_signal_connect (G_OBJECT (dialog), "response",
1284 		    G_CALLBACK(are_you_sure_close_dialog_respond),
1285 		    ddisp);
1286 
1287   gtk_widget_show_all(dialog);
1288 }
1289 
1290 void
display_update_menu_state(DDisplay * ddisp)1291 display_update_menu_state(DDisplay *ddisp)
1292 {
1293   GtkToggleAction *rulers;
1294   GtkToggleAction *visible_grid;
1295   GtkToggleAction *snap_to_grid;
1296   GtkToggleAction *show_cx_pts;
1297   GtkToggleAction *antialiased;
1298 
1299   if (ddisp->menu_bar == NULL) {
1300     rulers       = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowrulers"));
1301     visible_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowgrid"));
1302     snap_to_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptogrid"));
1303     show_cx_pts  = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowconnectionpoints"));
1304     antialiased  = GTK_TOGGLE_ACTION (menus_get_action ("ViewAntialiased"));
1305   } else {
1306     rulers       = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewShowrulers"));
1307     visible_grid = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewShowgrid"));
1308     snap_to_grid = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewSnaptogrid"));
1309     show_cx_pts  = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewShowconnectionpoints"));
1310 
1311     antialiased  = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewAntialiased"));
1312   }
1313   gtk_action_set_sensitive (menus_get_action ("ViewAntialiased"),
1314 		            g_type_from_name ("DiaCairoInteractiveRenderer") != 0 || g_type_from_name ("DiaLibartRenderer") != 0);
1315 
1316 
1317   ddisplay_do_update_menu_sensitivity (ddisp);
1318 
1319   gtk_toggle_action_set_active (rulers, display_get_rulers_showing(ddisp));
1320   gtk_toggle_action_set_active (visible_grid,
1321 				 ddisp->grid.visible);
1322   gtk_toggle_action_set_active (snap_to_grid,
1323 				 ddisp->grid.snap);
1324   gtk_toggle_action_set_active (show_cx_pts,
1325 				 ddisp->show_cx_pts);
1326 
1327   gtk_toggle_action_set_active (antialiased,
1328 				ddisp->aa_renderer);
1329 }
1330 
1331 void
ddisplay_do_update_menu_sensitivity(DDisplay * ddisp)1332 ddisplay_do_update_menu_sensitivity (DDisplay *ddisp)
1333 {
1334     Diagram *dia;
1335 
1336     if (ddisp == NULL) {
1337       return;
1338     }
1339     dia = ddisp->diagram;
1340     diagram_update_menu_sensitivity (dia);
1341 }
1342 
1343 
1344 
1345 /* This is called when ddisp->shell is destroyed... */
1346 void
ddisplay_really_destroy(DDisplay * ddisp)1347 ddisplay_really_destroy(DDisplay *ddisp)
1348 {
1349   if (active_display == ddisp)
1350     display_set_active(NULL);
1351 
1352   /* last chance to avoid crashing in the idle update */
1353   if (ddisp->update_id) {
1354     g_source_remove (ddisp->update_id);
1355     ddisp->update_id = 0;
1356   }
1357 
1358   if (ddisp->diagram) {
1359     diagram_remove_ddisplay(ddisp->diagram, ddisp);
1360     /* if we are the last user of the diagram it will be unref'ed */
1361     g_object_unref(ddisp->diagram);
1362     ddisp->diagram = NULL;
1363   }
1364 
1365   g_object_unref (ddisp->renderer);
1366   ddisp->renderer = NULL;
1367 
1368   g_hash_table_remove(display_ht, ddisp->shell);
1369   g_hash_table_remove(display_ht, ddisp->canvas);
1370 
1371   /* Free update_areas list: */
1372   ddisplay_free_update_areas(ddisp);
1373   /* Free display_areas list */
1374   ddisplay_free_display_areas(ddisp);
1375 
1376   g_free(ddisp);
1377 }
1378 
1379 
1380 void
ddisplay_set_title(DDisplay * ddisp,char * title)1381 ddisplay_set_title(DDisplay  *ddisp, char *title)
1382 {
1383   if (ddisp->is_standalone_window)
1384     gtk_window_set_title (GTK_WINDOW (ddisp->shell), title);
1385   else
1386   {
1387     GtkNotebook *notebook = g_object_get_data (G_OBJECT (ddisp->shell),
1388                                                DIA_MAIN_NOTEBOOK);
1389     /* Find the page with ddisp then set the label on the tab */
1390     gint num_pages = gtk_notebook_get_n_pages (notebook);
1391     gint num;
1392     GtkWidget *page;
1393     for (num = 0 ; num < num_pages ; num++)
1394     {
1395       page = gtk_notebook_get_nth_page (notebook,num);
1396       if (g_object_get_data (G_OBJECT (page), "DDisplay") == ddisp)
1397       {
1398         GtkLabel *label = g_object_get_data (G_OBJECT (page), "tab-label");
1399         /* not using the passed in title here, because it may be too long */
1400         gchar *name = diagram_get_name(ddisp->diagram);
1401         gtk_label_set_text(label,name);
1402         g_free(name);
1403         break;
1404       }
1405     }
1406     /* now modify the application window title */
1407     {
1408       const gchar *pname = g_get_prgname();
1409       gchar *fulltitle = g_strdup_printf ("%s - %s", title, pname ? pname : "Dia");
1410       gtk_window_set_title (GTK_WINDOW (ddisp->shell), fulltitle);
1411       g_free(fulltitle);
1412     }
1413   }
1414 }
1415 
1416 void
ddisplay_set_all_cursor(GdkCursor * cursor)1417 ddisplay_set_all_cursor(GdkCursor *cursor)
1418 {
1419   Diagram *dia;
1420   DDisplay *ddisp;
1421   GList *list;
1422   GSList *slist;
1423 
1424   current_cursor = cursor;
1425 
1426   list = dia_open_diagrams();
1427   while (list != NULL) {
1428     dia = (Diagram *) list->data;
1429 
1430     slist = dia->displays;
1431     while (slist != NULL) {
1432       ddisp = (DDisplay *) slist->data;
1433 
1434       ddisplay_set_cursor(ddisp, cursor);
1435 
1436       slist = g_slist_next(slist);
1437     }
1438 
1439     list = g_list_next(list);
1440   }
1441 }
1442 
1443 void
ddisplay_set_cursor(DDisplay * ddisp,GdkCursor * cursor)1444 ddisplay_set_cursor(DDisplay *ddisp, GdkCursor *cursor)
1445 {
1446   if (ddisp->canvas->window)
1447     gdk_window_set_cursor(ddisp->canvas->window, cursor);
1448 }
1449 
1450 /** Returns whether the rulers are currently showing on the display.
1451  */
display_get_rulers_showing(DDisplay * ddisp)1452 gboolean display_get_rulers_showing(DDisplay *ddisp) {
1453   return ddisp->rulers_are_showing;
1454 }
1455 
1456 
1457 /**
1458  * Shows the rulers and sets flag ddisp->rulers_are_showing.  This
1459  * is needed to detect whether a show() has been issued.  There is a
1460  * delay between the time that gtk_widget_show() is called and the time
1461  * when GTK_WIDGET_IS_VISIBLE(w) will indicate true.
1462  * @param ddisp The display to show the rulers on.
1463  */
display_rulers_show(DDisplay * ddisp)1464 void display_rulers_show (DDisplay *ddisp)
1465 {
1466   if (ddisp)
1467   {
1468     GtkWidget *parent = GTK_WIDGET (ddisp->origin->parent);
1469 
1470     gtk_widget_show (ddisp->origin);
1471     gtk_widget_show (ddisp->hrule);
1472     gtk_widget_show (ddisp->vrule);
1473 
1474     if (GTK_WIDGET_VISIBLE (parent))
1475       gtk_widget_queue_resize (parent);
1476 
1477     ddisp->rulers_are_showing = TRUE;
1478   }
1479 }
1480 
1481 /**
1482  * Hides the rulers and resets the flag ddisp->rulers_are_showing.  This
1483  * is needed to detect whether a hide() has been issued.  There is a
1484  * delay between the time that gtk_widget_hide() is called and the time
1485  * when GTK_WIDGET_IS_VISIBLE(w) will indicate false.
1486  * @param ddisp The display to hide the rulers on.
1487  */
display_rulers_hide(DDisplay * ddisp)1488 void display_rulers_hide (DDisplay *ddisp)
1489 {
1490   if (ddisp)
1491   {
1492     GtkWidget *parent = GTK_WIDGET (ddisp->origin->parent);
1493 
1494     gtk_widget_hide (ddisp->origin);
1495     gtk_widget_hide (ddisp->hrule);
1496     gtk_widget_hide (ddisp->vrule);
1497 
1498     if (GTK_WIDGET_VISIBLE (parent))
1499       gtk_widget_queue_resize (parent);
1500 
1501     ddisp->rulers_are_showing = FALSE;
1502   }
1503 }
1504 
1505 void
ddisplay_update_statusbar(DDisplay * ddisp)1506 ddisplay_update_statusbar(DDisplay *ddisp)
1507 {
1508   update_zoom_status (ddisp);
1509   update_snap_grid_status (ddisp);
1510   update_mainpoint_status (ddisp);
1511 }
1512 
1513 void
display_set_active(DDisplay * ddisp)1514 display_set_active(DDisplay *ddisp)
1515 {
1516   if (ddisp != active_display) {
1517     active_display = ddisp;
1518 
1519     /* perform notification here (such as switch layers dialog) */
1520     layer_dialog_set_diagram(ddisp ? ddisp->diagram : NULL);
1521     diagram_properties_set_diagram(ddisp ? ddisp->diagram : NULL);
1522 
1523     if (ddisp) {
1524       if (ddisp->is_standalone_window)
1525       {
1526         display_update_menu_state(ddisp);
1527 
1528         if (prefs.toolbox_on_top) {
1529           gtk_window_set_transient_for(GTK_WINDOW(interface_get_toolbox_shell()),
1530                                        GTK_WINDOW(ddisp->shell));
1531         } else {
1532           gtk_window_set_transient_for(GTK_WINDOW(interface_get_toolbox_shell()),
1533                                        NULL);
1534         }
1535       } else {
1536         GtkNotebook *notebook = g_object_get_data (G_OBJECT (ddisp->shell),
1537                                                    DIA_MAIN_NOTEBOOK);
1538         /* Find the page with ddisp then set the label on the tab */
1539         gint num_pages = gtk_notebook_get_n_pages (notebook);
1540         gint num;
1541         GtkWidget *page;
1542         for (num = 0 ; num < num_pages ; num++)
1543         {
1544           page = gtk_notebook_get_nth_page (notebook,num);
1545           if (g_object_get_data (G_OBJECT (page), "DDisplay") == ddisp)
1546           {
1547             gtk_notebook_set_current_page (notebook,num);
1548             break;
1549           }
1550         }
1551         /* synchronize_ui_to_active_display (ddisp); */
1552         /* updates display title, etc */
1553         diagram_modified(ddisp->diagram);
1554 
1555         /* ZOOM */
1556         update_zoom_status (ddisp);
1557 
1558         /* Snap to grid */
1559         ddisplay_set_snap_to_grid (ddisp, ddisp->grid.snap); /* menus */
1560 
1561         /* Object snapping */
1562         ddisplay_set_snap_to_objects (ddisp, ddisp->mainpoint_magnetism);
1563 
1564         display_update_menu_state (ddisp);
1565 
1566         gtk_window_present (GTK_WINDOW(ddisp->shell));
1567       }
1568     } else {
1569       /* TODO: Prevent gtk_window_set_transient_for() in Integrated UI case */
1570       gtk_window_set_transient_for(GTK_WINDOW(interface_get_toolbox_shell()),
1571                                    NULL);
1572     }
1573   }
1574 }
1575 
1576 void
ddisplay_im_context_preedit_reset(DDisplay * ddisp,Focus * focus)1577 ddisplay_im_context_preedit_reset(DDisplay *ddisp, Focus *focus)
1578 {
1579   if (ddisp->preedit_string != NULL) {
1580     if (focus != NULL) {
1581       int i;
1582       ObjectChange *change;
1583 
1584       for (i = 0; i < g_utf8_strlen(ddisp->preedit_string, -1); i++) {
1585         (focus->key_event)(focus, GDK_BackSpace, NULL, 0, &change);
1586       }
1587     }
1588 
1589     g_free(ddisp->preedit_string);
1590     ddisp->preedit_string = NULL;
1591   }
1592   if (ddisp->preedit_attrs != NULL) {
1593     pango_attr_list_unref(ddisp->preedit_attrs);
1594     ddisp->preedit_attrs = NULL;
1595   }
1596 }
1597 
1598 /** Get the active focus for the given display, or NULL.
1599  *
1600  * @param ddisp Display to get active focus for.  This display need not
1601  *              be the currently active display.
1602  * @returns The focus that is active for the given display, or NULL if no
1603  *          focus is active (i.e. no text is being edited).
1604  */
1605 Focus *
ddisplay_active_focus(DDisplay * ddisp)1606 ddisplay_active_focus(DDisplay *ddisp)
1607 {
1608   return ddisp ? ddisp->active_focus : NULL;
1609 }
1610 
1611 /** Set the currently active focus for this display.  This field should be
1612  *  set to non-null when a text is being edited and to null when no text
1613  *  is being edited.  Only textedit.c really needs to call this function.
1614  *
1615  * @param ddisp The display to set active focus for.
1616  * @param focus The focus that should be active for this display.  May be
1617  *              NULL, indicating that no text is currently being edited on
1618  *              this display.
1619  */
1620 void
ddisplay_set_active_focus(DDisplay * ddisp,Focus * focus)1621 ddisplay_set_active_focus(DDisplay *ddisp, Focus *focus)
1622 {
1623   ddisp->active_focus = focus;
1624 }
1625 
1626 void
ddisplay_show_all(DDisplay * ddisp)1627 ddisplay_show_all (DDisplay *ddisp)
1628 {
1629   Diagram *dia;
1630   real magnify_x, magnify_y;
1631   int width, height;
1632   Point middle;
1633 
1634   g_return_if_fail (ddisp != NULL);
1635 
1636   dia = ddisp->diagram;
1637 
1638   width = dia_renderer_get_width_pixels (ddisp->renderer);
1639   height = dia_renderer_get_height_pixels (ddisp->renderer);
1640 
1641   /* if there is something selected show that instead of all exisiting objects */
1642   if (dia->data->selected) {
1643     GList *list = dia->data->selected;
1644     Rectangle extents = *dia_object_get_enclosing_box ((DiaObject*)list->data);
1645     list = g_list_next(list);
1646     while (list) {
1647       DiaObject *obj = (DiaObject *)list->data;
1648       rectangle_union(&extents, dia_object_get_enclosing_box (obj));
1649       list = g_list_next(list);
1650     }
1651     magnify_x = (real)width / (extents.right - extents.left) / ddisp->zoom_factor;
1652     magnify_y = (real)height / (extents.bottom - extents.top) / ddisp->zoom_factor;
1653     middle.x = extents.left + (extents.right - extents.left) / 2.0;
1654     middle.y = extents.top + (extents.bottom - extents.top) / 2.0;
1655   } else {
1656     magnify_x = (real)width /
1657       (dia->data->extents.right - dia->data->extents.left) / ddisp->zoom_factor;
1658     magnify_y = (real)height /
1659       (dia->data->extents.bottom - dia->data->extents.top) / ddisp->zoom_factor;
1660 
1661     middle.x = dia->data->extents.left +
1662       (dia->data->extents.right - dia->data->extents.left) / 2.0;
1663     middle.y = dia->data->extents.top +
1664       (dia->data->extents.bottom - dia->data->extents.top) / 2.0;
1665   }
1666 
1667   ddisplay_zoom (ddisp, &middle,
1668 		 ((magnify_x<magnify_y)?magnify_x:magnify_y)/1.05);
1669 
1670   ddisplay_update_scrollbars(ddisp);
1671   ddisplay_add_update_all(ddisp);
1672   ddisplay_flush(ddisp);
1673 }
1674