1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1998 Alexander Larsson
3  * Copyright (C) 2006 Robert Staudinger <robert.staudinger@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #undef GTK_DISABLE_DEPRECATED /* GtkTooltips */
25 #include <gtk/gtk.h>
26 #include <gdk/gdkkeysyms.h>
27 #include <string.h>
28 
29 #include "intl.h"
30 #include "menus.h"
31 #include "tool.h"
32 #include "commands.h"
33 #include "message.h"
34 #include "interface.h"
35 #include "display.h"
36 #include "filedlg.h"
37 #include "find-and-replace.h"
38 #include "plugin-manager.h"
39 #include "select.h"
40 #include "dia_dirs.h"
41 #include "diagram_tree_window.h"
42 #include "object_ops.h"
43 #include "sheets.h"
44 #include "dia-app-icons.h"
45 #include "widgets.h"
46 #include "preferences.h"
47 
48 #define DIA_STOCK_GROUP "dia-stock-group"
49 #define DIA_STOCK_UNGROUP "dia-stock-ungroup"
50 #define DIA_STOCK_LAYER_ADD "dia-stock-layer-add"
51 #define DIA_STOCK_LAYER_RENAME "dia-stock-layer-rename"
52 #define DIA_STOCK_OBJECTS_LAYER_ABOVE "dia-stock-objects-layer-above"
53 #define DIA_STOCK_OBJECTS_LAYER_BELOW "dia-stock-objects-layer-below"
54 #define DIA_STOCK_LAYERS "dia-stock-layers"
55 
56 #define DIA_SHOW_TEAROFFS TRUE
57 
58 /* Integrated UI Toolbar Constants */
59 #define DIA_INTEGRATED_TOOLBAR_ZOOM_COMBO  "dia-integrated-toolbar-zoom-combo_entry"
60 #define DIA_INTEGRATED_TOOLBAR_SNAP_GRID   "dia-integrated-toolbar-snap-grid"
61 #define DIA_INTEGRATED_TOOLBAR_OBJECT_SNAP "dia-integrated-toolbar-object-snap"
62 
63 #define ZOOM_FIT        _("Fit")
64 
65 static void plugin_callback (GtkWidget *widget, gpointer data);
66 
67 static GtkWidget *
68 create_integrated_ui_toolbar (void);
69 
70 static void add_plugin_actions (GtkUIManager *ui_manager, const char *base_path);
71 
72 static gchar*
73 build_ui_filename (const gchar* name);
74 
75 /* Active/inactive state is set in diagram_update_menu_sensitivity()
76  * in diagram.c */
77 
78 /* Actions common to toolbox and diagram window */
79 static const GtkActionEntry common_entries[] =
80 {
81   { "File", NULL, N_("_File"), NULL, NULL, NULL },
82     { "FileNew", GTK_STOCK_NEW, NULL, "<control>N", NULL, G_CALLBACK (file_new_callback) },
83     { "FileOpen", GTK_STOCK_OPEN, NULL,"<control>O", NULL, G_CALLBACK (file_open_callback) },
84     { "FileQuit", GTK_STOCK_QUIT, NULL, "<control>Q", NULL, G_CALLBACK (file_quit_callback) },
85   { "Help", NULL, N_("_Help"), NULL, NULL, NULL },
86     { "HelpContents", GTK_STOCK_HELP, NULL, "F1", NULL, G_CALLBACK (help_manual_callback) },
87     { "HelpAbout", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK (help_about_callback) }
88 };
89 
90 /* Actions for toolbox menu */
91 static const GtkActionEntry toolbox_entries[] =
92 {
93     { "FileSheets", NULL, N_("Sheets and Objects..."), "F9", NULL, G_CALLBACK (sheets_dialog_show_callback) },
94     { "FilePrefs", GTK_STOCK_PREFERENCES, NULL, NULL, NULL, G_CALLBACK (file_preferences_callback) },
95     { "FilePlugins", NULL, N_("Plugins..."), NULL, NULL, G_CALLBACK (file_plugins_callback) }
96 };
97 
98 /* Toggle-Actions for toolbox menu */
99 static const GtkToggleActionEntry toolbox_toggle_entries[] =
100 {
101     { "FileTree", NULL, N_("_Diagram tree..."), "F8", NULL, G_CALLBACK (diagtree_show_callback) }
102 };
103 
104 /* Toggle-Actions for toolbox menu */
105 static const GtkToggleActionEntry integrated_ui_view_toggle_entries[] =
106 {
107     { VIEW_MAIN_TOOLBAR_ACTION,   NULL, N_("Show Toolbar"),   NULL, NULL, G_CALLBACK (view_main_toolbar_callback) },
108     { VIEW_MAIN_STATUSBAR_ACTION, NULL, N_("Show Statusbar"), NULL, NULL, G_CALLBACK (view_main_statusbar_callback) },
109     { VIEW_LAYERS_ACTION,    NULL, N_("Show Layers"), "<control>L", NULL, G_CALLBACK (view_layers_callback) }
110 };
111 
112 /* Actions for diagram window */
113 static const GtkActionEntry display_entries[] =
114 {
115     { "FileSave", GTK_STOCK_SAVE, NULL, "<control>S", NULL, G_CALLBACK (file_save_callback) },
116     { "FileSaveas", GTK_STOCK_SAVE_AS, NULL, "<control><shift>S", NULL, G_CALLBACK (file_save_as_callback) },
117     { "FileExport", GTK_STOCK_CONVERT, N_("_Export ..."), NULL, NULL, G_CALLBACK (file_export_callback) },
118     { "DiagramProperties", GTK_STOCK_PROPERTIES, N_("_Diagram Properties"), "<shift><alt>Return", NULL, G_CALLBACK (view_diagram_properties_callback) },
119     { "FilePagesetup", NULL, N_("Page Set_up..."), NULL, NULL, G_CALLBACK (file_pagesetup_callback) },
120     { "FilePrint", GTK_STOCK_PRINT, NULL, "<control>P", NULL, G_CALLBACK (file_print_callback) },
121     { "FileClose", GTK_STOCK_CLOSE, NULL, "<control>W", NULL, G_CALLBACK (file_close_callback) },
122 
123   { "Edit", NULL, N_("_Edit"), NULL, NULL, NULL },
124     { "EditUndo", GTK_STOCK_UNDO, NULL, "<control>Z", NULL, G_CALLBACK (edit_undo_callback) },
125     { "EditRedo", GTK_STOCK_REDO, NULL, "<control><shift>Z", NULL, G_CALLBACK (edit_redo_callback) },
126 
127     { "EditCopy", GTK_STOCK_COPY, NULL, "<control>C", NULL, G_CALLBACK (edit_copy_callback) },
128     { "EditCut", GTK_STOCK_CUT, NULL, "<control>X", NULL, G_CALLBACK (edit_cut_callback) },
129     { "EditPaste", GTK_STOCK_PASTE, NULL, "<control>V", NULL, G_CALLBACK (edit_paste_callback) },
130     { "EditDuplicate", NULL, N_("_Duplicate"), "<control>D", NULL, G_CALLBACK (edit_duplicate_callback) },
131     { "EditDelete", GTK_STOCK_DELETE, NULL, "Delete", NULL, G_CALLBACK (edit_delete_callback) },
132 
133     { "EditFind", GTK_STOCK_FIND, NULL, "<control>F", NULL, G_CALLBACK (edit_find_callback) },
134     { "EditReplace", GTK_STOCK_FIND_AND_REPLACE, NULL, "<control>H", NULL, G_CALLBACK (edit_replace_callback) },
135 
136     /* the following used to bind to <control><shift>C which collides with Unicode input.
137      * <control>>alt> doesn't work either */
138     { "EditCopytext", NULL, N_("Copy Text"), NULL, NULL, G_CALLBACK (edit_copy_text_callback) },
139     { "EditCuttext", NULL, N_("Cut Text"), "<control><shift>X", NULL, G_CALLBACK (edit_cut_text_callback) },
140     { "EditPastetext", NULL, N_("Paste _Text"), "<control><shift>V", NULL, G_CALLBACK (edit_paste_text_callback) },
141 
142   { "Layers", NULL, N_("_Layers"), NULL, NULL, NULL },
143     { "LayerAdd", DIA_STOCK_LAYER_ADD, N_("Add Layer..."), NULL, NULL, G_CALLBACK (layers_add_layer_callback) },
144     { "LayerRename", DIA_STOCK_LAYER_RENAME, N_("Rename Layer..."), NULL, NULL, G_CALLBACK (layers_rename_layer_callback) },
145     { "ObjectsLayerAbove", DIA_STOCK_OBJECTS_LAYER_ABOVE, N_("Move selection to layer above"), NULL, NULL, G_CALLBACK (objects_move_up_layer) },
146     { "ObjectsLayerBelow", DIA_STOCK_OBJECTS_LAYER_BELOW, N_("Move selection to layer below"), NULL, NULL, G_CALLBACK (objects_move_down_layer) },
147     { "DiagramLayers", DIA_STOCK_LAYERS, N_("_Layers..."), "<control>L", NULL, G_CALLBACK (dialogs_layers_callback) },
148 
149   { "View", NULL, N_("_View"), NULL, NULL, NULL },
150     { "ViewZoomin", GTK_STOCK_ZOOM_IN, NULL, "<control>plus", NULL, G_CALLBACK (view_zoom_in_callback) },
151     { "ViewZoomout", GTK_STOCK_ZOOM_OUT, NULL, "<control>minus", NULL, G_CALLBACK (view_zoom_out_callback) },
152     { "ViewZoom", NULL, N_("_Zoom"), NULL, NULL, NULL },
153       { "ViewZoom16000", NULL, N_("1600%"), NULL, NULL, G_CALLBACK (view_zoom_set_callback) },
154       { "ViewZoom8000", NULL, N_("800%"), NULL, NULL, G_CALLBACK (view_zoom_set_callback) },
155       { "ViewZoom4000", NULL, N_("400%"), "<alt>4", NULL, G_CALLBACK (view_zoom_set_callback) },
156       { "ViewZoom2830", NULL, N_("283"), NULL, NULL, G_CALLBACK (view_zoom_set_callback) },
157       { "ViewZoom2000", NULL, N_("200"), "<alt>2", NULL, G_CALLBACK (view_zoom_set_callback) },
158       { "ViewZoom1410", NULL, N_("141"), NULL, NULL, G_CALLBACK (view_zoom_set_callback) },
159       { "ViewZoom1000", GTK_STOCK_ZOOM_100, NULL, "<alt>1", NULL, G_CALLBACK (view_zoom_set_callback) },
160       { "ViewZoom850", NULL, N_("85"), NULL, NULL, G_CALLBACK (view_zoom_set_callback) },
161       { "ViewZoom707", NULL, N_("70.7"), NULL, NULL, G_CALLBACK (view_zoom_set_callback) },
162       { "ViewZoom500", NULL, N_("50"), "<alt>5", NULL, G_CALLBACK (view_zoom_set_callback) },
163       { "ViewZoom354", NULL, N_("35.4"), NULL, NULL, G_CALLBACK (view_zoom_set_callback) },
164       { "ViewZoom250", NULL, N_("25"), NULL, NULL, G_CALLBACK (view_zoom_set_callback) },
165     /* Show All, Best Fit.  Same as the Gimp, Ctrl+E */
166     { "ViewShowall", GTK_STOCK_ZOOM_FIT, NULL, "<control>E", NULL, G_CALLBACK (view_show_all_callback) },
167 
168   /* "display_toggle_entries" items go here */
169 
170     { "ViewNewview", NULL, N_("New _View"), NULL, NULL, G_CALLBACK (view_new_view_callback) },
171     { "ViewCloneview", NULL, N_("C_lone View"), NULL, NULL, G_CALLBACK (view_clone_view_callback) },
172     { "ViewRedraw", GTK_STOCK_REFRESH, NULL, NULL, NULL, G_CALLBACK (view_redraw_callback) },
173 
174   { "Objects", NULL, N_("_Objects"), NULL, NULL },
175     { "ObjectsSendtoback", GTK_STOCK_GOTO_BOTTOM, N_("Send to _Back"), "<control><shift>B", NULL, G_CALLBACK (objects_place_under_callback) },
176     { "ObjectsBringtofront", GTK_STOCK_GOTO_TOP, N_("Bring to _Front"), "<control><shift>F", NULL, G_CALLBACK (objects_place_over_callback) },
177     { "ObjectsSendbackwards", GTK_STOCK_GO_DOWN, N_("Send Backwards"), NULL, NULL, G_CALLBACK (objects_place_down_callback) },
178     { "ObjectsBringforwards", GTK_STOCK_GO_UP, N_("Bring Forwards"), NULL, NULL, G_CALLBACK (objects_place_up_callback) },
179 
180     { "ObjectsGroup", DIA_STOCK_GROUP, N_("_Group"), "<control>G", NULL, G_CALLBACK (objects_group_callback) },
181     /* deliberately not using Ctrl+U for Ungroup */
182     { "ObjectsUngroup", DIA_STOCK_UNGROUP, N_("_Ungroup"), "<control><shift>G", NULL, G_CALLBACK (objects_ungroup_callback) },
183 
184     { "ObjectsParent", NULL, N_("_Parent"), "<control>K", NULL, G_CALLBACK (objects_parent_callback) },
185     { "ObjectsUnparent", NULL, N_("_Unparent"), "<control><shift>K", NULL, G_CALLBACK (objects_unparent_callback) },
186     { "ObjectsUnparentchildren", NULL, N_("_Unparent Children"), NULL, NULL, G_CALLBACK (objects_unparent_children_callback) },
187 
188     { "ObjectsAlign", NULL, N_("Align"), NULL, NULL, NULL },
189       { "ObjectsAlignLeft", GTK_STOCK_JUSTIFY_LEFT, NULL, "<alt><shift>L", NULL, G_CALLBACK (objects_align_h_callback) },
190       { "ObjectsAlignCenter", GTK_STOCK_JUSTIFY_CENTER, NULL, "<alt><shift>C", NULL, G_CALLBACK (objects_align_h_callback) },
191       { "ObjectsAlignRight", GTK_STOCK_JUSTIFY_RIGHT, NULL, "<alt><shift>R", NULL, G_CALLBACK (objects_align_h_callback) },
192 
193       { "ObjectsAlignTop", NULL, N_("Top"), "<alt><shift>T", NULL, G_CALLBACK (objects_align_v_callback) },
194       { "ObjectsAlignMiddle", NULL, N_("Middle"), "<alt><shift>M", NULL, G_CALLBACK (objects_align_v_callback) },
195       { "ObjectsAlignBottom", NULL, N_("Bottom"), "<alt><shift>B", NULL, G_CALLBACK (objects_align_v_callback) },
196 
197       { "ObjectsAlignSpreadouthorizontally", NULL, N_("Spread Out Horizontally"), "<alt><shift>H", NULL, G_CALLBACK (objects_align_h_callback) },
198       { "ObjectsAlignSpreadoutvertically", NULL, N_("Spread Out Vertically"), "<alt><shift>V", NULL, G_CALLBACK (objects_align_v_callback) },
199       { "ObjectsAlignAdjacent", NULL, N_("Adjacent"), "<alt><shift>A", NULL, G_CALLBACK (objects_align_h_callback) },
200       { "ObjectsAlignStacked", NULL, N_("Stacked"), "<alt><shift>S", NULL, G_CALLBACK (objects_align_v_callback) },
201 
202       { "ObjectsProperties", GTK_STOCK_PROPERTIES, NULL, "<alt>Return", NULL, G_CALLBACK (dialogs_properties_callback) },
203 
204   { "Select", NULL, N_("_Select"), NULL, NULL, NULL },
205     { "SelectAll", NULL, N_("All"), "<control>A", NULL, G_CALLBACK (select_all_callback) },
206     { "SelectNone", NULL, N_("None"), "<control><shift>A", NULL, G_CALLBACK (select_none_callback) },
207     { "SelectInvert", NULL, N_("Invert"), "<control>I", NULL, G_CALLBACK (select_invert_callback) },
208 
209     { "SelectTransitive", NULL, N_("Transitive"), "<control>T", NULL, G_CALLBACK (select_transitive_callback) },
210     { "SelectConnected", NULL, N_("Connected"), "<control><shift>T", NULL, G_CALLBACK (select_connected_callback) },
211     { "SelectSametype", NULL, N_("Same Type"), NULL, NULL, G_CALLBACK (select_same_type_callback) },
212 
213     /* display_select_radio_entries go here */
214 
215     { "SelectBy", NULL, N_("Select By"), NULL, NULL, NULL },
216 
217   { "InputMethods", NULL, N_("_Input Methods"), NULL, NULL, NULL },
218 
219   { "Dialogs", NULL, N_("D_ialogs"), NULL, NULL, NULL },
220 
221   { "Debug", NULL, N_("D_ebug"), NULL, NULL, NULL }
222 };
223 
224 /* Standard-Tool entries */
225 static const GtkActionEntry tool_entries[] =
226 {
227   { "Tools", NULL, N_("_Tools"), NULL, NULL, NULL },
228     { "ToolsModify", NULL, N_("Modify"), "N", NULL, NULL },
229     { "ToolsMagnify", NULL, N_("Magnify"), "M", NULL, NULL },
230     { "ToolsTextedit", NULL, N_("Edit text"), "F2", NULL, NULL },
231     { "ToolsScroll", NULL, N_("Scroll"), "S", NULL, NULL },
232     { "ToolsText", NULL, N_("Text"), "T", NULL, NULL },
233     { "ToolsBox", NULL, N_("Box"), "R", NULL, NULL },
234     { "ToolsEllipse", NULL, N_("Ellipse"), "E", NULL, NULL },
235     { "ToolsPolygon", NULL, N_("Polygon"), "P", NULL, NULL },
236     { "ToolsBeziergon", NULL, N_("Beziergon"), "B", NULL, NULL },
237 
238     { "ToolsLine", NULL, N_("Line"), "L", NULL, NULL },
239     { "ToolsArc", NULL, N_("Arc"), "A", NULL, NULL },
240     { "ToolsZigzagline", NULL, N_("Zigzagline"), "Z", NULL, NULL },
241     { "ToolsPolyline", NULL, N_("Polyline"), "Y", NULL },
242     { "ToolsBezierline", NULL, N_("Bezierline"), "C", NULL, NULL },
243     { "ToolsOutline", NULL, N_("Outline"), "O", NULL, NULL },
244 
245     { "ToolsImage", NULL, N_("Image"), "I", NULL, NULL },
246 };
247 
248 /* Toggle-Actions for diagram window */
249 static const GtkToggleActionEntry display_toggle_entries[] =
250 {
251 #ifdef GTK_STOCK_FULLSCREEN /* added with gtk+-2.8, but no reason to depend on it */
252     { "ViewFullscreen", GTK_STOCK_FULLSCREEN, NULL, "F11", NULL, G_CALLBACK (view_fullscreen_callback) },
253 #else
254     { "ViewFullscreen", NULL, N_("Fullscr_een"), "F11", NULL, G_CALLBACK (view_fullscreen_callback) },
255 #endif
256     { "ViewAntialiased", NULL, N_("_AntiAliased"), NULL, NULL, G_CALLBACK (view_aa_callback) },
257     { "ViewShowgrid", NULL, N_("Show _Grid"), NULL, NULL, G_CALLBACK (view_visible_grid_callback) },
258     { "ViewSnaptogrid", NULL, N_("_Snap To Grid"), NULL, NULL, G_CALLBACK (view_snap_to_grid_callback) },
259     { "ViewSnaptoobjects", NULL, N_("Snap To _Objects"), NULL, NULL, G_CALLBACK (view_snap_to_objects_callback) },
260     { "ViewShowrulers", NULL, N_("Show _Rulers"), NULL, NULL, G_CALLBACK (view_toggle_rulers_callback)  },
261     { "ViewShowconnectionpoints", NULL, N_("Show _Connection Points"), NULL, NULL, G_CALLBACK (view_show_cx_pts_callback) }
262 };
263 
264 /* Radio-Actions for the diagram window's "Select"-Menu */
265 static const GtkRadioActionEntry display_select_radio_entries[] =
266 {
267   { "SelectReplace", NULL, N_("Replace"), NULL, NULL, SELECT_REPLACE },
268   { "SelectUnion", NULL, N_("Union"), NULL, NULL, SELECT_UNION },
269   { "SelectIntersection", NULL, N_("Intersection"), NULL, NULL, SELECT_INTERSECTION },
270   { "SelectRemove", NULL, N_("Remove"), NULL, NULL, SELECT_REMOVE },
271   /* Cannot also be called Invert, duplicate names caused keybinding problems */
272   { "SelectInverse", NULL, N_("Inverse"), NULL, NULL, SELECT_INVERT }
273 };
274 
275 /* need initialisation? */
276 static gboolean initialise = TRUE;
277 
278 /* integrated ui */
279 static GtkUIManager *integrated_ui_manager = NULL;
280 static GtkActionGroup *integrated_ui_actions = NULL;
281 static GtkActionGroup *integrated_ui_tool_actions = NULL;
282 static GtkAccelGroup *integrated_ui_accels = NULL;
283 static GtkWidget *integrated_ui_menubar = NULL;
284 static GtkWidget *integrated_ui_toolbar = NULL;
285 
286 /* toolbox */
287 static GtkUIManager *toolbox_ui_manager = NULL;
288 static GtkActionGroup *toolbox_actions = NULL;
289 static GtkAccelGroup *toolbox_accels = NULL;
290 static GtkWidget *toolbox_menubar = NULL;
291 
292 GtkActionGroup *recent_actions = NULL;
293 static GSList *recent_merge_ids = NULL;
294 
295 /* diagram */
296 static GtkUIManager *display_ui_manager = NULL;
297 static GtkActionGroup *display_actions = NULL;
298 static GtkActionGroup *display_tool_actions = NULL;
299 static GtkAccelGroup *display_accels = NULL;
300 static GtkWidget *display_menubar = NULL;
301 
302 static gchar*
_dia_translate(const gchar * term,gpointer data)303 _dia_translate (const gchar* term, gpointer data)
304 {
305   gchar* trans = (gchar*) term;
306 
307   if (term && *term) {
308     /* first try our own ... */
309     trans = dgettext (GETTEXT_PACKAGE, term);
310     /* ... than gtk */
311     if (term == trans)
312       trans = dgettext ("gtk20", term);
313 #if 0
314     /* FIXME: final fallback */
315     if (term == trans) { /* FIXME: translation to be updated */
316       gchar* kludge = g_strdup_printf ("/%s", term);
317       trans = dgettext (GETTEXT_PACKAGE, kludge);
318       if (kludge == trans)
319 	trans = term;
320       else
321 	++trans;
322       g_free (kludge);
323     }
324     if (term == trans)
325       trans = g_strdup_printf ("XXX: %s", term);
326 #endif
327   }
328   return trans;
329 }
330 
331 static void
tool_menu_select(GtkWidget * w,gpointer data)332 tool_menu_select(GtkWidget *w, gpointer   data) {
333   ToolButtonData *tooldata = (ToolButtonData *) data;
334 
335   if (tooldata == NULL) {
336     g_warning(_("NULL tooldata in tool_menu_select"));
337     return;
338   }
339 
340   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tooldata->widget),TRUE);
341 }
342 
343 static gint
save_accels(gpointer data)344 save_accels(gpointer data)
345 {
346   gchar *accelfilename;
347 
348   accelfilename = dia_config_filename("menurc");
349   if (accelfilename) {
350     gtk_accel_map_save (accelfilename);
351     g_free (accelfilename);
352   }
353   return TRUE;
354 }
355 
356 /**
357  * Synchronized the Object snap property button with the display.
358  * @param param Display to synchronize to.
359  */
360 void
integrated_ui_toolbar_object_snap_synchronize_to_display(gpointer param)361 integrated_ui_toolbar_object_snap_synchronize_to_display(gpointer param)
362 {
363   DDisplay *ddisp = param;
364   if (ddisp && ddisp->common_toolbar)
365   {
366     GtkToggleButton *b = g_object_get_data (G_OBJECT (ddisp->common_toolbar),
367                                             DIA_INTEGRATED_TOOLBAR_OBJECT_SNAP);
368     gboolean active = ddisp->mainpoint_magnetism? TRUE : FALSE;
369     gtk_toggle_button_set_active (b, active);
370   }
371 }
372 
373 /**
374  * Sets the Object-snap property for the active display.
375  * @param b Object snap toggle button.
376  * @param not_used
377  */
378 static void
integrated_ui_toolbar_object_snap_toggle(GtkToggleButton * b,gpointer * not_used)379 integrated_ui_toolbar_object_snap_toggle(GtkToggleButton *b, gpointer *not_used)
380 {
381   DDisplay *ddisp = ddisplay_active ();
382   if (ddisp)
383   {
384     ddisplay_set_snap_to_objects (ddisp, gtk_toggle_button_get_active (b));
385   }
386 }
387 
388 /**
389  * Synchronizes the Snap-to-grid property button with the display.
390  * @param param Display to synchronize to.
391  */
392 void
integrated_ui_toolbar_grid_snap_synchronize_to_display(gpointer param)393 integrated_ui_toolbar_grid_snap_synchronize_to_display(gpointer param)
394 {
395   DDisplay *ddisp = param;
396   if (ddisp && ddisp->common_toolbar)
397   {
398     GtkToggleButton *b = g_object_get_data (G_OBJECT (ddisp->common_toolbar),
399                                             DIA_INTEGRATED_TOOLBAR_SNAP_GRID);
400     gboolean active = ddisp->grid.snap? TRUE : FALSE;
401     gtk_toggle_button_set_active (b, active);
402   }
403 }
404 
405 /**
406  * Sets the Snap-to-grid property for the active display.
407  * @param b Snap to grid toggle button.
408  * @param not_used
409  */
410 static void
integrated_ui_toolbar_grid_snap_toggle(GtkToggleButton * b,gpointer * not_used)411 integrated_ui_toolbar_grid_snap_toggle(GtkToggleButton *b, gpointer *not_used)
412 {
413   DDisplay *ddisp = ddisplay_active ();
414   if (ddisp)
415   {
416     ddisplay_set_snap_to_grid (ddisp, gtk_toggle_button_get_active (b));
417   }
418 }
419 
420 /**
421  * Sets the zoom text for the toolbar
422  * @param toolbar Integrated UI toolbar.
423  * @param text Current zoom percentage for the active window
424  */
integrated_ui_toolbar_set_zoom_text(GtkToolbar * toolbar,const gchar * text)425 void integrated_ui_toolbar_set_zoom_text (GtkToolbar *toolbar, const gchar * text)
426 {
427   if (toolbar)
428   {
429     GtkComboBoxEntry *combo_entry = g_object_get_data (G_OBJECT (toolbar),
430                                                        DIA_INTEGRATED_TOOLBAR_ZOOM_COMBO);
431 
432     if (combo_entry)
433     {
434         GtkWidget * entry = gtk_bin_get_child (GTK_BIN (combo_entry));
435 
436         gtk_entry_set_text (GTK_ENTRY (entry), text);
437     }
438   }
439 }
440 
441 /**
442  * Adds a widget to the toolbar making sure that it doesn't take any excess space, and
443  * vertically centers it.
444  * @param toolbar The toolbar to add the widget to.
445  * @param w       The widget to add to the toolbar.
446  */
integrated_ui_toolbar_add_custom_item(GtkToolbar * toolbar,GtkWidget * w)447 static void integrated_ui_toolbar_add_custom_item (GtkToolbar *toolbar, GtkWidget *w)
448 {
449     GtkToolItem *tool_item;
450     GtkWidget   *c; /* container */
451 
452     tool_item = gtk_tool_item_new ();
453     c = gtk_vbox_new (FALSE, 0);
454     gtk_container_add (GTK_CONTAINER (tool_item), c);
455     gtk_box_set_homogeneous (GTK_BOX (c), TRUE);            /* Centers the button */
456     gtk_box_pack_start (GTK_BOX (c), w, FALSE, FALSE, 0);
457     gtk_toolbar_insert (toolbar, tool_item, -1);
458     gtk_widget_show (GTK_WIDGET (tool_item));
459     gtk_widget_show (c);
460     gtk_widget_show (w);
461 }
462 
463 static void
integrated_ui_toolbar_zoom_activate(GtkWidget * item,gpointer user_data)464 integrated_ui_toolbar_zoom_activate (GtkWidget *item,
465                                      gpointer   user_data)
466 {
467     const gchar *text =  gtk_entry_get_text (GTK_ENTRY (item));
468     float        zoom_percent;
469 
470     if (sscanf (text, "%f", &zoom_percent) == 1)
471     {
472         view_zoom_set (10.0 * zoom_percent);
473     }
474 }
475 
476 static void
integrated_ui_toolbar_zoom_combo_selection_changed(GtkComboBox * combo,gpointer user_data)477 integrated_ui_toolbar_zoom_combo_selection_changed (GtkComboBox *combo,
478                                                     gpointer     user_data)
479 {
480     /*
481      * We call gtk_combo_get_get_active() so that typing in the combo entry
482      * doesn't get handled as a selection change
483      */
484     if (gtk_combo_box_get_active (combo) != -1)
485     {
486         float zoom_percent;
487         gchar * text = gtk_combo_box_get_active_text (combo);
488 
489         if (sscanf (text, "%f", &zoom_percent) == 1)
490         {
491             view_zoom_set (zoom_percent * 10.0);
492         }
493         else if (g_strcasecmp (text, ZOOM_FIT) == 0)
494         {
495             view_show_all_callback (NULL);
496         }
497 
498         g_free (text);
499     }
500 }
501 
502 static guint
ensure_menu_path(GtkUIManager * ui_manager,GtkActionGroup * actions,const gchar * path,gboolean end)503 ensure_menu_path (GtkUIManager *ui_manager, GtkActionGroup *actions, const gchar *path, gboolean end)
504 {
505   guint id = gtk_ui_manager_new_merge_id (ui_manager);
506 
507   if (!gtk_ui_manager_get_widget (ui_manager, path)) {
508     gchar *subpath = g_strdup (path);
509 
510     if (strrchr (subpath, '/')) {
511       const gchar *action_name;
512       gchar *sep;
513 
514       GtkAction *action;
515 
516       sep = strrchr (subpath, '/');
517       *sep = '\0'; /* cut subpath */
518       action_name = sep + 1;
519 
520       ensure_menu_path (ui_manager, actions, subpath, FALSE);
521 
522       action = gtk_action_new (action_name, sep + 1, NULL, NULL);
523       if (!gtk_action_group_get_action (actions, action_name))
524         gtk_action_group_add_action (actions, action);
525       g_object_unref (G_OBJECT (action));
526 
527       gtk_ui_manager_add_ui (ui_manager, id, subpath,
528 	                     action_name, action_name,
529 			     end ? GTK_UI_MANAGER_SEPARATOR : GTK_UI_MANAGER_MENU,
530 			     FALSE); /* FALSE=add-to-end */
531     } else {
532       g_warning ("ensure_menu_path() invalid menu path: %s.", subpath ? subpath : "NULL");
533     }
534     g_free (subpath);
535   }
536   return id;
537 }
538 
539 /**
540  * Create the toolbar for the integrated UI
541  * @return Main toolbar (GtkToolbar*) for the integrated UI main window
542  */
543 static GtkWidget *
create_integrated_ui_toolbar(void)544 create_integrated_ui_toolbar (void)
545 {
546   GtkToolbar  *toolbar;
547   GtkToolItem *sep;
548   GtkWidget   *w;
549   GError      *error = NULL;
550   gchar *uifile;
551 
552   uifile = build_ui_filename ("ui/toolbar-ui.xml");
553   if (!gtk_ui_manager_add_ui_from_file (integrated_ui_manager, uifile, &error)) {
554     g_warning ("building menus failed: %s", error->message);
555     g_error_free (error);
556     error = NULL;
557     toolbar = GTK_TOOLBAR (gtk_toolbar_new ());
558   }
559   else {
560     toolbar =  GTK_TOOLBAR(gtk_ui_manager_get_widget (integrated_ui_manager, "/Toolbar"));
561   }
562   g_free (uifile);
563 
564   /* Zoom Combo Box Entry */
565   w = gtk_combo_box_entry_new_text ();
566 
567   g_object_set_data (G_OBJECT (toolbar),
568                      DIA_INTEGRATED_TOOLBAR_ZOOM_COMBO,
569                      w);
570   integrated_ui_toolbar_add_custom_item (toolbar, w);
571 
572   gtk_combo_box_append_text (GTK_COMBO_BOX (w), ZOOM_FIT);
573   gtk_combo_box_append_text (GTK_COMBO_BOX (w), _("800%"));
574   gtk_combo_box_append_text (GTK_COMBO_BOX (w), _("400%"));
575   gtk_combo_box_append_text (GTK_COMBO_BOX (w), _("300%"));
576   gtk_combo_box_append_text (GTK_COMBO_BOX (w), _("200%"));
577   gtk_combo_box_append_text (GTK_COMBO_BOX (w), _("150%"));
578   gtk_combo_box_append_text (GTK_COMBO_BOX (w), _("100%"));
579   gtk_combo_box_append_text (GTK_COMBO_BOX (w), _("75%"));
580   gtk_combo_box_append_text (GTK_COMBO_BOX (w), _("50%"));
581   gtk_combo_box_append_text (GTK_COMBO_BOX (w), _("25%"));
582   gtk_combo_box_append_text (GTK_COMBO_BOX (w), _("10%"));
583 
584   g_signal_connect (G_OBJECT (w),
585                     "changed",
586 		            G_CALLBACK (integrated_ui_toolbar_zoom_combo_selection_changed),
587                     NULL);
588 
589   /* Get the combo's GtkEntry child to set the width for the widget */
590   w = gtk_bin_get_child (GTK_BIN (w));
591   gtk_entry_set_width_chars (GTK_ENTRY (w), 6);
592 
593   g_signal_connect (GTK_OBJECT (w), "activate",
594 		            G_CALLBACK(integrated_ui_toolbar_zoom_activate),
595 		            NULL);
596 
597   /* Seperator */
598   sep = gtk_separator_tool_item_new ();
599   gtk_toolbar_insert (toolbar, sep, -1);
600   gtk_widget_show (GTK_WIDGET (sep));
601 
602   /* Snap to grid */
603   w = dia_toggle_button_new_with_icons (dia_on_grid_icon,
604                                         dia_off_grid_icon);
605   g_signal_connect (G_OBJECT (w), "toggled",
606 		   G_CALLBACK (integrated_ui_toolbar_grid_snap_toggle), toolbar);
607   gtk_tooltips_set_tip (tool_tips, w,
608 		      _("Toggles snap-to-grid."), NULL);
609   g_object_set_data (G_OBJECT (toolbar),
610                      DIA_INTEGRATED_TOOLBAR_SNAP_GRID,
611                      w);
612   integrated_ui_toolbar_add_custom_item (toolbar, w);
613 
614   /* Object Snapping */
615   w = dia_toggle_button_new_with_icons (dia_mainpoints_on_icon,
616                                         dia_mainpoints_off_icon);
617   g_signal_connect (G_OBJECT (w), "toggled",
618 		   G_CALLBACK (integrated_ui_toolbar_object_snap_toggle), toolbar);
619   gtk_tooltips_set_tip (tool_tips, w,
620 		       _("Toggles object snapping."), NULL);
621   g_object_set_data (G_OBJECT (toolbar),
622                      DIA_INTEGRATED_TOOLBAR_OBJECT_SNAP,
623                      w);
624   integrated_ui_toolbar_add_custom_item (toolbar, w);
625 
626   sep = gtk_separator_tool_item_new ();
627   gtk_toolbar_insert (toolbar, sep, -1);
628   gtk_widget_show (GTK_WIDGET (sep));
629 
630   return GTK_WIDGET (toolbar);
631 }
632 
633 /*
634  * Initialise tool actions.
635  * The caller owns the return value.
636  */
637 static GtkActionGroup *
create_tool_actions(void)638 create_tool_actions (void)
639 {
640   GtkActionGroup *actions;
641   GtkAction      *action;
642   int           i;
643   gchar          *name;
644   static guint    cnt = 0;
645 
646   name = g_strdup_printf ("tool-actions-%d", cnt);
647   actions = gtk_action_group_new (name);
648   gtk_action_group_set_translation_domain (actions, NULL);
649   gtk_action_group_set_translate_func (actions, _dia_translate, NULL, NULL);
650   g_free (name);
651   name = NULL;
652   cnt++;
653 
654   gtk_action_group_add_actions (actions, tool_entries,
655 				G_N_ELEMENTS (tool_entries), NULL);
656 
657   for (i = 0; i < num_tools; i++) {
658     action = gtk_action_group_get_action (actions, tool_data[i].action_name);
659     if (action != NULL) {
660       g_signal_connect (G_OBJECT (action), "activate",
661 			G_CALLBACK (tool_menu_select),
662 			&tool_data[i].callback_data);
663     }
664     else {
665       g_warning ("couldn't find tool menu item %s", tool_data[i].action_name);
666     }
667   }
668   return actions;
669 }
670 
671 /* initialize callbacks from plug-ins */
672 static void
add_plugin_actions(GtkUIManager * ui_manager,const gchar * base_path)673 add_plugin_actions (GtkUIManager *ui_manager, const gchar *base_path)
674 {
675   GtkActionGroup    *actions;
676   GtkAction         *action;
677   GList             *cblist;
678   DiaCallbackFilter *cbf = NULL;
679   gchar             *name;
680   guint              id;
681   static guint       cnt = 0;
682 
683   name = g_strdup_printf ("plugin-actions-%d", cnt);
684   actions = gtk_action_group_new (name);
685   gtk_action_group_set_translation_domain (actions, NULL);
686   gtk_action_group_set_translate_func (actions, _dia_translate, NULL, NULL);
687   g_free (name);
688   name = NULL;
689   cnt++;
690 
691   gtk_ui_manager_insert_action_group (ui_manager, actions, 5 /* "back" */);
692   g_object_unref (actions);
693 
694   for (cblist = filter_get_callbacks(); cblist; cblist = cblist->next) {
695     gchar *menu_path = NULL;
696 
697     cbf = cblist->data;
698 
699     if (cbf == NULL) {
700       g_warning ("missing DiaCallbackFilter instance");
701       continue;
702     }
703 
704     if (cbf->action == NULL) {
705       g_warning ("Plugin '%s': doesn't specify action. Loading failed.",
706 		cbf->description);
707       continue;
708     }
709 
710     if (   base_path != NULL
711         && strncmp (cbf->menupath, base_path, strlen (base_path)) != 0) {
712       /* hook for wrong base path, skip */
713       continue;
714     } else if (!base_path) {
715       /* only replace what we know */
716       if (strncmp (cbf->menupath, DISPLAY_MENU, strlen (DISPLAY_MENU)) == 0)
717         menu_path = g_strdup_printf ("%s%s", INTEGRATED_MENU, cbf->menupath + strlen (DISPLAY_MENU));
718       else if (strncmp (cbf->menupath, TOOLBOX_MENU, strlen (TOOLBOX_MENU)) == 0)
719         menu_path = g_strdup_printf ("%s%s", INTEGRATED_MENU, cbf->menupath + strlen (TOOLBOX_MENU));
720     }
721 
722     action = gtk_action_new (cbf->action, cbf->description, NULL, NULL);
723     g_signal_connect (G_OBJECT (action), "activate",
724 		      G_CALLBACK (plugin_callback), (gpointer) cbf);
725 
726     gtk_action_group_add_action (actions, action);
727     g_object_unref (G_OBJECT (action));
728 
729     id = ensure_menu_path (ui_manager, actions, menu_path ? menu_path : cbf->menupath, TRUE);
730     gtk_ui_manager_add_ui (ui_manager, id,
731 			   menu_path ? menu_path : cbf->menupath,
732 			   cbf->description,
733 			   cbf->action,
734 			   GTK_UI_MANAGER_AUTO,
735 			   FALSE);
736     g_free (menu_path);
737   }
738 }
739 
740 static void
_add_stock_icon(GtkIconFactory * factory,const char * name,const guint8 * data,const size_t size)741 _add_stock_icon (GtkIconFactory *factory, const char *name, const guint8 *data, const size_t size)
742 {
743   GdkPixbuf      *pixbuf;
744   GtkIconSet     *set;
745   GError         *err = NULL;
746 
747   pixbuf = gdk_pixbuf_new_from_inline (size, data, FALSE, &err);
748   if (err) {
749     g_warning ("%s", err->message);
750     g_error_free (err);
751     err = NULL;
752   }
753   set = gtk_icon_set_new_from_pixbuf (pixbuf);
754   gtk_icon_factory_add (factory, name, set);
755   g_object_unref (pixbuf);
756   pixbuf = NULL;
757 }
758 
759 static void
register_stock_icons(void)760 register_stock_icons (void)
761 {
762   GtkIconFactory *factory;
763 
764   factory = gtk_icon_factory_new ();
765 
766   _add_stock_icon (factory, DIA_STOCK_GROUP, dia_group_icon, sizeof(dia_group_icon));
767   _add_stock_icon (factory, DIA_STOCK_UNGROUP, dia_ungroup_icon, sizeof(dia_ungroup_icon));
768 
769   _add_stock_icon (factory, DIA_STOCK_LAYER_ADD, dia_layer_add, sizeof(dia_layer_add));
770   _add_stock_icon (factory, DIA_STOCK_LAYER_RENAME, dia_layer_rename, sizeof(dia_layer_rename));
771   _add_stock_icon (factory, DIA_STOCK_OBJECTS_LAYER_ABOVE, dia_objects_layer_above, sizeof(dia_objects_layer_above));
772   _add_stock_icon (factory, DIA_STOCK_OBJECTS_LAYER_BELOW, dia_objects_layer_below, sizeof(dia_objects_layer_below));
773   _add_stock_icon (factory, DIA_STOCK_LAYERS, dia_layers, sizeof(dia_layers));
774 
775   gtk_icon_factory_add_default (factory);
776   g_object_unref (factory);
777   factory = NULL;
778 }
779 
780 static gchar*
build_ui_filename(const gchar * name)781 build_ui_filename (const gchar* name)
782 {
783   gchar* uifile;
784 
785   if (g_getenv ("DIA_BASE_PATH") != NULL) {
786     /* a small hack cause the final destination and the local path differ */
787     const gchar* p = strrchr (name, '/');
788     if (p != NULL)
789       name = p+1;
790     uifile = g_build_filename (g_getenv ("DIA_BASE_PATH"), "data", name, NULL);
791   } else
792     uifile = dia_get_data_directory (name);
793 
794   return uifile;
795 }
796 
797 /*!
798  * Not sure why this service is not provided by GTK+.
799  * We are passing tooltips into the actions (especially recent file menu).
800  * But they were not shown without explicit setting on connect.
801  */
802 static void
_ui_manager_connect_proxy(GtkUIManager * manager,GtkAction * action,GtkWidget * proxy)803 _ui_manager_connect_proxy (GtkUIManager *manager,
804                            GtkAction    *action,
805                            GtkWidget    *proxy)
806 {
807   if (GTK_IS_MENU_ITEM (proxy))
808     {
809       gchar *tooltip;
810 
811       g_object_get (action, "tooltip", &tooltip, NULL);
812 
813       if (tooltip)
814         {
815 	  gtk_tooltips_set_tip (tool_tips, proxy, tooltip, NULL);
816 	  g_free (tooltip);
817 	}
818     }
819 }
820 
821 GtkActionGroup *
create_or_ref_display_actions(void)822 create_or_ref_display_actions (void)
823 {
824   if (display_actions)
825     return g_object_ref (display_actions);
826   display_actions = gtk_action_group_new ("display-actions");
827   gtk_action_group_set_translation_domain (display_actions, NULL);
828   gtk_action_group_set_translate_func (display_actions, _dia_translate, NULL, NULL);
829   gtk_action_group_add_actions (display_actions, common_entries,
830                 G_N_ELEMENTS (common_entries), NULL);
831   gtk_action_group_add_actions (display_actions, display_entries,
832                 G_N_ELEMENTS (display_entries), NULL);
833   gtk_action_group_add_toggle_actions (display_actions, display_toggle_entries,
834                 G_N_ELEMENTS (display_toggle_entries),
835                 NULL);
836   gtk_action_group_add_radio_actions (display_actions,
837                 display_select_radio_entries,
838                 G_N_ELEMENTS (display_select_radio_entries),
839                 0, /* SELECT_REPLACE - first radio entry */
840                 G_CALLBACK (select_style_callback),
841                 NULL);
842   /* the initial reference */
843   return display_actions;
844 }
845 
846 /* Very minimal fallback menu info for ui-files missing
847  * as well as to register the InvisibleMenu */
848 static const gchar *ui_info =
849 "<ui>\n"
850 "  <popup name=\"InvisibleMenu\">\n"
851 "    <menu name=\"File\" action=\"File\">\n"
852 "       <menuitem name=\"FilePrint\" action=\"FilePrint\" />\n"
853 "       <menuitem name=\"FileQuit\" action=\"FileQuit\" />\n"
854 "    </menu>\n"
855 "  </popup>\n"
856 "</ui>";
857 
858 static void
menus_init(void)859 menus_init(void)
860 {
861   gchar                 *accelfilename;
862   GError 		*error = NULL;
863   gchar			*uifile;
864 
865   if (!initialise)
866     return;
867 
868   initialise = FALSE;
869 
870   register_stock_icons ();
871 
872   /* the toolbox menu */
873   toolbox_actions = gtk_action_group_new ("toolbox-actions");
874   gtk_action_group_set_translation_domain (toolbox_actions, NULL);
875   gtk_action_group_set_translate_func (toolbox_actions, _dia_translate, NULL, NULL);
876   gtk_action_group_add_actions (toolbox_actions, common_entries,
877                 G_N_ELEMENTS (common_entries), NULL);
878   gtk_action_group_add_actions (toolbox_actions, toolbox_entries,
879                 G_N_ELEMENTS (toolbox_entries), NULL);
880   gtk_action_group_add_toggle_actions (toolbox_actions, toolbox_toggle_entries,
881                 G_N_ELEMENTS (toolbox_toggle_entries),
882                 NULL);
883 
884   toolbox_ui_manager = gtk_ui_manager_new ();
885   g_signal_connect (G_OBJECT (toolbox_ui_manager),
886                     "connect_proxy",
887 		    G_CALLBACK (_ui_manager_connect_proxy),
888 		    NULL);
889   gtk_ui_manager_set_add_tearoffs (toolbox_ui_manager, DIA_SHOW_TEAROFFS);
890   gtk_ui_manager_insert_action_group (toolbox_ui_manager, toolbox_actions, 0);
891   uifile = build_ui_filename ("ui/toolbox-ui.xml");
892   if (!gtk_ui_manager_add_ui_from_file (toolbox_ui_manager, uifile, &error)) {
893     g_warning ("building menus failed: %s", error->message);
894     g_error_free (error);
895     error = NULL;
896   }
897   g_free (uifile);
898 
899   toolbox_accels = gtk_ui_manager_get_accel_group (toolbox_ui_manager);
900   toolbox_menubar = gtk_ui_manager_get_widget (toolbox_ui_manager, TOOLBOX_MENU);
901 
902   /* the display menu */
903   display_actions = create_or_ref_display_actions ();
904   display_tool_actions = create_tool_actions ();
905 
906   display_ui_manager = gtk_ui_manager_new ();
907   g_signal_connect (G_OBJECT (display_ui_manager),
908                     "connect_proxy",
909 		    G_CALLBACK (_ui_manager_connect_proxy),
910 		    NULL);
911   gtk_ui_manager_set_add_tearoffs (display_ui_manager, DIA_SHOW_TEAROFFS);
912   gtk_ui_manager_insert_action_group (display_ui_manager, display_actions, 0);
913   gtk_ui_manager_insert_action_group (display_ui_manager, display_tool_actions, 0);
914   if (!gtk_ui_manager_add_ui_from_string (display_ui_manager, ui_info, -1, &error)) {
915     g_warning ("built-in menus failed: %s", error->message);
916     g_error_free (error);
917     error = NULL;
918   }
919 
920   uifile = build_ui_filename ("ui/popup-ui.xml");
921   /* TODO it would be more elegant if we had only one definition of the
922    * menu hierarchy and merge it into a popup somehow. */
923   if (!gtk_ui_manager_add_ui_from_file (display_ui_manager, uifile, &error)) {
924     g_warning ("building menus failed: %s", error->message);
925     g_error_free (error);
926     error = NULL;
927   }
928   g_free (uifile);
929 
930   display_accels = gtk_ui_manager_get_accel_group (display_ui_manager);
931   display_menubar = gtk_ui_manager_get_widget (display_ui_manager, DISPLAY_MENU);
932   g_assert (display_menubar);
933 
934   add_plugin_actions (toolbox_ui_manager, TOOLBOX_MENU);
935   add_plugin_actions (display_ui_manager, DISPLAY_MENU);
936   add_plugin_actions (display_ui_manager, INVISIBLE_MENU);
937 
938   /* load accelerators and prepare to later save them */
939   accelfilename = dia_config_filename("menurc");
940 
941   if (accelfilename) {
942     gtk_accel_map_load(accelfilename);
943     g_free(accelfilename);
944   }
945   gtk_quit_add(1, save_accels, NULL);
946 }
947 
948 void
menus_get_integrated_ui_menubar(GtkWidget ** menubar,GtkWidget ** toolbar,GtkAccelGroup ** accel_group)949 menus_get_integrated_ui_menubar (GtkWidget     **menubar,
950                                  GtkWidget     **toolbar,
951 			         GtkAccelGroup **accel_group)
952 {
953   GError *error = NULL;
954   gchar  *uifile;
955 
956   if (initialise)
957     menus_init();
958 
959   /* the integrated ui menu */
960   integrated_ui_actions = gtk_action_group_new ("integrated-ui-actions");
961   gtk_action_group_set_translation_domain (integrated_ui_actions, NULL);
962   gtk_action_group_set_translate_func (integrated_ui_actions, _dia_translate, NULL, NULL);
963   gtk_action_group_add_actions (integrated_ui_actions, common_entries,
964                 G_N_ELEMENTS (common_entries), NULL);
965   gtk_action_group_add_actions (integrated_ui_actions, toolbox_entries,
966                 G_N_ELEMENTS (toolbox_entries), NULL);
967   gtk_action_group_add_actions (integrated_ui_actions, display_entries,
968                 G_N_ELEMENTS (display_entries), NULL);
969   gtk_action_group_add_toggle_actions (integrated_ui_actions, integrated_ui_view_toggle_entries,
970                 G_N_ELEMENTS (integrated_ui_view_toggle_entries), NULL);
971   gtk_action_group_add_toggle_actions (integrated_ui_actions, toolbox_toggle_entries,
972                 G_N_ELEMENTS (toolbox_toggle_entries),
973                 NULL);
974   gtk_action_group_add_toggle_actions (integrated_ui_actions, display_toggle_entries,
975                 G_N_ELEMENTS (display_toggle_entries),
976                 NULL);
977   gtk_action_group_add_radio_actions (integrated_ui_actions,
978                 display_select_radio_entries,
979                 G_N_ELEMENTS (display_select_radio_entries),
980                 1,
981                 G_CALLBACK (select_style_callback),
982                 NULL);
983 
984   integrated_ui_tool_actions = create_tool_actions ();
985 
986   integrated_ui_manager = gtk_ui_manager_new ();
987   gtk_ui_manager_set_add_tearoffs (integrated_ui_manager, DIA_SHOW_TEAROFFS);
988   gtk_ui_manager_insert_action_group (integrated_ui_manager, integrated_ui_actions, 0);
989   gtk_ui_manager_insert_action_group (integrated_ui_manager, integrated_ui_tool_actions, 0);
990 
991   uifile = build_ui_filename ("ui/integrated-ui.xml");
992   if (!gtk_ui_manager_add_ui_from_file (integrated_ui_manager, uifile, &error)) {
993     g_warning ("building integrated ui menus failed: %s", error->message);
994     g_error_free (error);
995     error = NULL;
996   }
997   g_free (uifile);
998   if (!gtk_ui_manager_add_ui_from_string (integrated_ui_manager, ui_info, -1, &error)) {
999     g_warning ("built-in menus failed: %s", error->message);
1000     g_error_free (error);
1001     error = NULL;
1002   }
1003 
1004   add_plugin_actions (integrated_ui_manager, NULL);
1005 
1006   integrated_ui_accels = gtk_ui_manager_get_accel_group (integrated_ui_manager);
1007   integrated_ui_menubar = gtk_ui_manager_get_widget (integrated_ui_manager, INTEGRATED_MENU);
1008   integrated_ui_toolbar = create_integrated_ui_toolbar ();
1009 
1010   if (menubar)
1011     *menubar = integrated_ui_menubar;
1012   if (toolbar)
1013     *toolbar = integrated_ui_toolbar;
1014   if (accel_group)
1015     *accel_group = integrated_ui_accels;
1016 }
1017 
1018 void
menus_get_toolbox_menubar(GtkWidget ** menubar,GtkAccelGroup ** accel_group)1019 menus_get_toolbox_menubar (GtkWidget     **menubar,
1020 			   GtkAccelGroup **accel_group)
1021 {
1022   if (initialise)
1023     menus_init();
1024 
1025   if (menubar)
1026     *menubar = toolbox_menubar;
1027   if (accel_group)
1028     *accel_group = toolbox_accels;
1029 }
1030 
1031 GtkWidget *
menus_get_display_popup(void)1032 menus_get_display_popup (void)
1033 {
1034   if (initialise)
1035     menus_init();
1036 
1037   return display_menubar;
1038 }
1039 
1040 GtkAccelGroup *
menus_get_display_accels(void)1041 menus_get_display_accels (void)
1042 {
1043   if (initialise)
1044     menus_init();
1045 
1046   if (is_integrated_ui ())
1047     return integrated_ui_accels;
1048 
1049   return display_accels;
1050 }
1051 
1052 GtkWidget *
menus_create_display_menubar(GtkUIManager ** ui_manager,GtkActionGroup ** actions)1053 menus_create_display_menubar (GtkUIManager   **ui_manager,
1054 			      GtkActionGroup **actions)
1055 {
1056   GtkActionGroup *tool_actions;
1057   GtkWidget      *menu_bar;
1058   GError         *error = NULL;
1059   gchar          *uifile;
1060 
1061 
1062   *actions = create_or_ref_display_actions ();
1063   tool_actions = create_tool_actions ();
1064 
1065   *ui_manager = gtk_ui_manager_new ();
1066   gtk_ui_manager_set_add_tearoffs (*ui_manager, DIA_SHOW_TEAROFFS);
1067   gtk_ui_manager_insert_action_group (*ui_manager, *actions, 0);
1068   gtk_ui_manager_insert_action_group (*ui_manager, tool_actions, 0);
1069   g_object_unref (G_OBJECT (tool_actions));
1070 
1071   uifile = build_ui_filename ("ui/display-ui.xml");
1072   if (!gtk_ui_manager_add_ui_from_file (*ui_manager, uifile, &error)) {
1073     g_warning ("building menus failed: %s", error->message);
1074     g_error_free (error);
1075     g_free (uifile);
1076     return NULL;
1077   }
1078   g_free (uifile);
1079 
1080   add_plugin_actions (*ui_manager, DISPLAY_MENU);
1081   menu_bar = gtk_ui_manager_get_widget (*ui_manager, DISPLAY_MENU);
1082   return menu_bar;
1083 }
1084 
1085 GtkAccelGroup *
menus_get_accel_group()1086 menus_get_accel_group ()
1087 {
1088   return is_integrated_ui ()? integrated_ui_accels : toolbox_accels;
1089 }
1090 
1091 GtkActionGroup *
menus_get_action_group()1092 menus_get_action_group ()
1093 {
1094   return is_integrated_ui ()? integrated_ui_actions : toolbox_actions;
1095 }
1096 
1097 GtkAction *
menus_get_action(const gchar * name)1098 menus_get_action (const gchar *name)
1099 {
1100   GtkAction *action;
1101 
1102   if (is_integrated_ui ())
1103   {
1104     action = gtk_action_group_get_action (integrated_ui_actions, name);
1105     if (action == NULL) {
1106       action = gtk_action_group_get_action (integrated_ui_tool_actions, name);
1107     }
1108   }
1109   else
1110   {
1111     action = gtk_action_group_get_action (toolbox_actions, name);
1112     if (action == NULL) {
1113       action = gtk_action_group_get_action (display_actions, name);
1114     }
1115     if (action == NULL) {
1116       action = gtk_action_group_get_action (display_tool_actions, name);
1117     }
1118   }
1119   if (!action) {
1120     GList *groups, *list;
1121 
1122     /* search everthing there is, could probably replace the above */
1123     groups = gtk_ui_manager_get_action_groups (display_ui_manager);
1124     for (list = groups; list != NULL; list = list->next) {
1125       action = gtk_action_group_get_action (GTK_ACTION_GROUP (list->data), name);
1126       if (action)
1127 	break;
1128     }
1129   }
1130 
1131   return action;
1132 }
1133 
1134 void
menus_set_recent(GtkActionGroup * actions)1135 menus_set_recent (GtkActionGroup *actions)
1136 {
1137   GList *list;
1138   guint id;
1139   GtkUIManager *ui_manager;
1140   const char   *recent_path;
1141 
1142   if (is_integrated_ui ())
1143   {
1144     ui_manager  = integrated_ui_manager;
1145     recent_path = INTEGRATED_MENU "/File/FileRecentEnd";
1146   }
1147   else
1148   {
1149     ui_manager  = toolbox_ui_manager;
1150     recent_path = TOOLBOX_MENU "/File/FileRecentEnd";
1151   }
1152 
1153   if (recent_actions) {
1154     menus_clear_recent ();
1155   }
1156 
1157   list = gtk_action_group_list_actions (actions);
1158   g_return_if_fail (list);
1159 
1160   recent_actions = actions;
1161   g_object_ref (G_OBJECT (recent_actions));
1162   gtk_ui_manager_insert_action_group (ui_manager,
1163                     recent_actions,
1164                     10 /* insert at back */ );
1165 
1166   do {
1167     id = gtk_ui_manager_new_merge_id (ui_manager);
1168     recent_merge_ids = g_slist_prepend (recent_merge_ids, (gpointer) id);
1169 
1170     gtk_ui_manager_add_ui (ui_manager, id,
1171                  recent_path,
1172                  gtk_action_get_name (GTK_ACTION (list->data)),
1173                  gtk_action_get_name (GTK_ACTION (list->data)),
1174                  GTK_UI_MANAGER_AUTO,
1175                  TRUE);
1176 
1177   } while (NULL != (list = list->next));
1178 }
1179 
1180 void
menus_clear_recent(void)1181 menus_clear_recent (void)
1182 {
1183   GSList *id;
1184   GtkUIManager *ui_manager;
1185 
1186   if (is_integrated_ui ())
1187     ui_manager  = integrated_ui_manager;
1188   else
1189     ui_manager  = toolbox_ui_manager;
1190 
1191   if (recent_merge_ids) {
1192     id = recent_merge_ids;
1193     do {
1194       gtk_ui_manager_remove_ui (ui_manager, (guint) id->data);
1195 
1196     } while (NULL != (id = id->next));
1197 
1198     g_slist_free (recent_merge_ids);
1199     recent_merge_ids = NULL;
1200   }
1201 
1202   if (recent_actions) {
1203     gtk_ui_manager_remove_action_group (ui_manager, recent_actions);
1204     g_object_unref (G_OBJECT (recent_actions));
1205     recent_actions = NULL;
1206   }
1207 }
1208 
1209 static void
plugin_callback(GtkWidget * widget,gpointer data)1210 plugin_callback (GtkWidget *widget, gpointer data)
1211 {
1212   DiaCallbackFilter *cbf = data;
1213 
1214   /* and finally invoke it */
1215   if (cbf->callback) {
1216     DDisplay *ddisp = NULL;
1217     DiagramData* diadata = NULL;
1218     /* stuff from the toolbox menu should never get a diagram to modify */
1219     if (strncmp (cbf->menupath, TOOLBOX_MENU, strlen (TOOLBOX_MENU)) != 0) {
1220       ddisp = ddisplay_active();
1221       diadata = ddisp ? ddisp->diagram->data : NULL;
1222     }
1223     cbf->callback (diadata, ddisp ? ddisp->diagram->filename : NULL, 0, cbf->user_data);
1224   }
1225 }
1226