home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / menus.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-25  |  65.4 KB  |  2,102 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  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. #include "config.h"
  20.  
  21. #include <stdlib.h>
  22. #include <string.h>
  23.  
  24. #include <gtk/gtk.h>
  25. #include <gdk/gdkkeysyms.h>
  26.  
  27. #include "apptypes.h"
  28.  
  29. #include "appenv.h"
  30. #include "channels_dialog.h"
  31. #include "commands.h"
  32. #include "dialog_handler.h"
  33. #include "fileops.h"
  34. #include "gimprc.h"
  35. #include "gimpui.h"
  36. #include "interface.h"
  37. #include "layers_dialog.h"
  38. #include "menus.h"
  39. #include "paths_dialog.h"
  40. #include "paint_funcs.h"
  41. #include "preferences_dialog.h"
  42. #include "procedural_db.h"
  43. #include "scale.h"
  44. #include "tools.h"
  45. #include "gdisplay.h"
  46.  
  47. #include "libgimp/gimpenv.h"
  48.  
  49. #include "libgimp/gimpintl.h"
  50.  
  51.  
  52. #define MRU_MENU_ENTRY_SIZE (strlen ("/File/MRU00 ") + 1)
  53. #define MRU_MENU_ACCEL_SIZE sizeof ("<control>0")
  54.  
  55. static void   menus_create_item     (GtkItemFactory       *item_factory,
  56.                      GimpItemFactoryEntry *entry,
  57.                      gpointer              callback_data,
  58.                      guint                 callback_type);
  59. static void   menus_create_items    (GtkItemFactory       *item_factory,
  60.                      guint                 n_entries,
  61.                      GimpItemFactoryEntry *entries,
  62.                      gpointer              callback_data,
  63.                      guint                 callback_type);
  64. static void   menus_create_branches (GtkItemFactory      *item_factory,
  65.                      GimpItemFactoryEntry *entry);
  66. static void   menus_init            (void);
  67.  
  68. #ifdef ENABLE_NLS
  69. static gchar *menu_translate        (const gchar          *path,
  70.                      gpointer              data);
  71. #else
  72. #define menu_translate NULL
  73. #endif
  74.  
  75. static void   tearoff_cmd_callback  (GtkWidget            *widget,
  76.                      gpointer              callback_data,
  77.                      guint                 callback_action);
  78. static gint   tearoff_delete_cb     (GtkWidget          *widget, 
  79.                          GdkEvent          *event,
  80.                      gpointer           data);
  81. #ifdef ENABLE_DEBUG_ENTRY
  82. static void   menus_debug_recurse_menu (GtkWidget *menu,
  83.                     gint       depth,
  84.                     gchar     *path);
  85. static void   menus_debug_cmd_callback (GtkWidget *widget,
  86.                     gpointer   callback_data,
  87.                     guint      callback_action);
  88. #endif  /*  ENABLE_DEBUG_ENTRY  */
  89.  
  90. static GSList *last_opened_raw_filenames = NULL;
  91.  
  92. /*****  <Toolbox>  *****/
  93.  
  94. static GimpItemFactoryEntry toolbox_entries[] =
  95. {
  96.   /*  <Toolbox>/File  */
  97.  
  98.   /* the underscore installs an accelerator using the character that follows */
  99.   { { N_("/_File"), NULL, NULL, 0, "<Branch>" },
  100.     NULL, NULL },
  101.   { { N_("/File/New..."), "<control>N", file_new_cmd_callback, 0 },
  102.     "file/dialogs/file_new.html", NULL },
  103.   { { N_("/File/Open..."), "<control>O", file_open_cmd_callback, 0 },
  104.     "file/dialogs/file_open.html", NULL },
  105.  
  106.   /*  <Toolbox>/File/Acquire  */
  107.  
  108.   { { "/File/---", NULL, NULL, 0, "<Separator>" },
  109.     NULL, NULL },
  110.   { { N_("/File/Acquire"), NULL, NULL, 0, "<Branch>" },
  111.     NULL, NULL },
  112.  
  113.   { { "/File/---", NULL, NULL, 0, "<Separator>" },
  114.     NULL, NULL },
  115.   { { N_("/File/Preferences..."), NULL, prefs_cmd_callback, 0 },
  116.     "file/dialogs/preferences/preferences.html", NULL },
  117.  
  118.   /*  <Toolbox>/File/Dialogs  */
  119.  
  120.   { { "/File/---", NULL, NULL, 0, "<Separator>" },
  121.     NULL, NULL },
  122.   { { N_("/File/Dialogs/Layers, Channels & Paths..."), "<control>L", dialogs_lc_cmd_callback, 0 },
  123.     "file/dialogs/layers_and_channels.html", NULL },
  124.   { { N_("/File/Dialogs/Tool Options..."), "<control><shift>T", dialogs_tool_options_cmd_callback, 0 },
  125.     "file/dialogs/tool_options.html", NULL },
  126.  
  127.   { { "/File/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  128.     NULL, NULL },
  129.   { { N_("/File/Dialogs/Brushes..."), "<control><shift>B", dialogs_brushes_cmd_callback, 0 },
  130.     "file/dialogs/brush_selection.html", NULL },
  131.   { { N_("/File/Dialogs/Patterns..."), "<control><shift>P", dialogs_patterns_cmd_callback, 0 },
  132.     "file/dialogs/pattern_selection.html", NULL },
  133.   { { N_("/File/Dialogs/Gradients..."), "<control>G", dialogs_gradients_cmd_callback, 0 },
  134.     "file/dialogs/gradient_selection.html", NULL },
  135.   { { N_("/File/Dialogs/Palette..."), "<control>P", dialogs_palette_cmd_callback, 0 },
  136.     "file/dialogs/palette_selection.html", NULL },
  137.   { { N_("/File/Dialogs/Indexed Palette..."), NULL, dialogs_indexed_palette_cmd_callback, 0 },
  138.     "file/dialogs/indexed_palette.html", NULL },
  139.  
  140.   { { "/File/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  141.     NULL, NULL },
  142.   { { N_("/File/Dialogs/Input Devices..."), NULL, dialogs_input_devices_cmd_callback, 0 },
  143.     "file/dialogs/input_devices.html", NULL },
  144.   { { N_("/File/Dialogs/Device Status..."), NULL, dialogs_device_status_cmd_callback, 0 },
  145.     "file/dialogs/device_status.html", NULL },
  146.  
  147.   { { "/File/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  148.     NULL, NULL },
  149.   { { N_("/File/Dialogs/Document Index..."), NULL, dialogs_document_index_cmd_callback, 0 },
  150.     "file/dialogs/document_index.html", NULL },
  151.   { { N_("/File/Dialogs/Error Console..."), NULL, dialogs_error_console_cmd_callback, 0 },
  152.     "file/dialogs/error_console.html", NULL },
  153. #ifdef DISPLAY_FILTERS
  154.   { { N_("/File/Dialogs/Display Filters..."), NULL, dialogs_display_filters_cmd_callback, 0 },
  155.     "file/dialogs/display_filters/display_filters.html", NULL },
  156. #endif /* DISPLAY_FILTERS */
  157.  
  158.   { { "/File/---", NULL, NULL, 0, "<Separator>" },
  159.     NULL, NULL },
  160.  
  161.   /*  MRU entries are inserted here  */
  162.  
  163.   { { "/File/---MRU", NULL, NULL, 0, "<Separator>" },
  164.     NULL, NULL },
  165.   { { N_("/File/Quit"), "<control>Q", file_quit_cmd_callback, 0 },
  166.     "file/quit.html", NULL },
  167.  
  168.   /*  <Toolbox>/Xtns  */
  169.  
  170.   /* the underscore installs an accelerator using the character that follows */
  171.   { { N_("/_Xtns"), NULL, NULL, 0, "<Branch>" },
  172.     NULL, NULL },
  173.   { { N_("/Xtns/Module Browser..."), NULL, dialogs_module_browser_cmd_callback, 0 },
  174.     "dialogs/module_browser.html", NULL },
  175.  
  176.   { { "/Xtns/---", NULL, NULL, 0, "<Separator>" },
  177.     NULL, NULL },
  178.  
  179.   /*  <Toolbox>/Help  */
  180.  
  181.   /* the underscore installs an accelerator using the character that follows */
  182.   { { N_("/_Help"), NULL, NULL, 0, "<Branch>" },
  183.     NULL, NULL },
  184.   { { N_("/Help/Help..."), "F1", help_help_cmd_callback, 0 },
  185.     "help/dialogs/help.html", NULL },
  186.   { { N_("/Help/Context Help..."), "<shift>F1", help_context_help_cmd_callback, 0 },
  187.     "help/context_help.html", NULL },
  188.   { { N_("/Help/Tip of the Day..."), NULL, help_tips_cmd_callback, 0 },
  189.     "help/dialogs/tip_of_the_day.html", NULL },
  190.   { { N_("/Help/About..."), NULL, help_about_cmd_callback, 0 },
  191.     "help/dialogs/about.html", NULL },
  192. #ifdef ENABLE_DEBUG_ENTRY
  193.   { { N_("/Help/Dump Items (Debug)"), NULL, menus_debug_cmd_callback, 0 },
  194.     NULL, NULL }
  195. #endif
  196. };
  197.  
  198. static guint n_toolbox_entries = (sizeof (toolbox_entries) /
  199.                   sizeof (toolbox_entries[0]));
  200. static GtkItemFactory *toolbox_factory = NULL;
  201.  
  202. /*****  <Image>  *****/
  203.  
  204. static GimpItemFactoryEntry image_entries[] =
  205. {
  206.   { { "/tearoff1", NULL, tearoff_cmd_callback, 0, "<Tearoff>" },
  207.     NULL, NULL },
  208.  
  209.   /*  <Image>/File  */
  210.  
  211.   { { N_("/File/New..."), "<control>N", file_new_cmd_callback, 1 },
  212.     "file/dialogs/file_new.html", NULL },
  213.   { { N_("/File/Open..."), "<control>O", file_open_cmd_callback, 0 },
  214.     "file/dialogs/file_open.html", NULL },
  215.   { { N_("/File/Save"), "<control>S", file_save_cmd_callback, 0 },
  216.     "file/dialogs/file_save.html", NULL },
  217.   { { N_("/File/Save As..."), NULL, file_save_as_cmd_callback, 0 },
  218.     "file/dialogs/file_save.html", NULL },
  219.   { { N_("/File/Revert..."), NULL, file_revert_cmd_callback, 0 },
  220.     "file/revert.html", NULL },
  221.  
  222.   { { "/File/---", NULL, NULL, 0, "<Separator>" },
  223.     NULL, NULL },
  224.   { { N_( "/File/Close"), "<control>W", file_close_cmd_callback, 0 },
  225.     "file/close.html", NULL },
  226.   { { N_("/File/Quit"), "<control>Q", file_quit_cmd_callback, 0 },
  227.     "file/quit.html", NULL },
  228.  
  229.   { { "/File/---moved", NULL, NULL, 0, "<Separator>" },
  230.     NULL, NULL },
  231.  
  232.   /*  <Image>/Edit  */
  233.  
  234.   { { N_("/Edit/Undo"), "<control>Z", edit_undo_cmd_callback, 0 },
  235.     "edit/undo.html", NULL },
  236.   { { N_("/Edit/Redo"), "<control>R", edit_redo_cmd_callback, 0 },
  237.     "edit/redo.html", NULL },
  238.  
  239.   { { "/Edit/---", NULL, NULL, 0, "<Separator>" },
  240.     NULL, NULL },
  241.   { { N_("/Edit/Cut"), "<control>X", edit_cut_cmd_callback, 0 },
  242.     "edit/cut.html", NULL },
  243.   { { N_("/Edit/Copy"), "<control>C", edit_copy_cmd_callback, 0 },
  244.     "edit/copy.html", NULL },
  245.   { { N_("/Edit/Paste"), "<control>V", edit_paste_cmd_callback, 0 },
  246.     "edit/paste.html", NULL },
  247.   { { N_("/Edit/Paste Into"), NULL, edit_paste_into_cmd_callback, 0 },
  248.     "edit/paste_into.html", NULL },
  249.   { { N_("/Edit/Paste as New"), NULL, edit_paste_as_new_cmd_callback, 0 },
  250.     "edit/paste_as_new.html", NULL },
  251.  
  252.   /*  <Image>/Edit/Buffer  */
  253.  
  254.   { { N_("/Edit/Buffer/Cut Named..."), "<control><shift>X", edit_named_cut_cmd_callback, 0 },
  255.     "edit/dialogs/cut_named.html", NULL },
  256.   { { N_("/Edit/Buffer/Copy Named..."), "<control><shift>C", edit_named_copy_cmd_callback, 0 },
  257.     "edit/dialogs/copy_named.html", NULL },
  258.   { { N_("/Edit/Buffer/Paste Named..."), "<control><shift>V", edit_named_paste_cmd_callback, 0 },
  259.     "edit/dialogs/paste_named.html", NULL },
  260.  
  261.   { { "/Edit/---", NULL, NULL, 0, "<Separator>" },
  262.     NULL, NULL },
  263.   { { N_("/Edit/Clear"), "<control>K", edit_clear_cmd_callback, 0 },
  264.     "edit/clear.html", NULL },
  265.   { { N_("/Edit/Fill with FG Color"), "<control>comma", edit_fill_cmd_callback, (guint)FOREGROUND_FILL },
  266.     "edit/fill.html", NULL },
  267.   { { N_("/Edit/Fill with BG Color"), "<control>period", edit_fill_cmd_callback, (guint)BACKGROUND_FILL },
  268.     "edit/fill.html", NULL },
  269.   { { N_("/Edit/Stroke"), NULL, edit_stroke_cmd_callback, 0 },
  270.     "edit/stroke.html", NULL },
  271.  
  272.   { { "/Edit/---", NULL, NULL, 0, "<Separator>" },
  273.     NULL, NULL },
  274.  
  275.   /*  <Image>/Select  */
  276.   
  277.   { { N_("/Select/Invert"), "<control>I", select_invert_cmd_callback, 0 },
  278.     "select/invert.html", NULL },
  279.   { { N_("/Select/All"), "<control>A", select_all_cmd_callback, 0 },
  280.     "select/all.html", NULL },
  281.   { { N_("/Select/None"), "<control><shift>A", select_none_cmd_callback, 0 },
  282.     "select/none.html", NULL },
  283.   { { N_("/Select/Float"), "<control><shift>L", select_float_cmd_callback, 0 },
  284.     "select/float.html", NULL },
  285.  
  286.   { { "/Select/---", NULL, NULL, 0, "<Separator>" },
  287.     NULL, NULL },
  288.   { { N_("/Select/Feather..."), "<control><shift>F", select_feather_cmd_callback, 0 },
  289.     "select/dialogs/feather_selection.html", NULL },
  290.   { { N_("/Select/Sharpen"), "<control><shift>H", select_sharpen_cmd_callback, 0 },
  291.     "select/sharpen.html", NULL },
  292.   { { N_("/Select/Shrink..."), NULL, select_shrink_cmd_callback, 0 },
  293.     "select/dialogs/shrink_selection.html", NULL },
  294.   { { N_("/Select/Grow..."), NULL, select_grow_cmd_callback, 0 },
  295.     "select/dialogs/grow_selection.html", NULL },
  296.   { { N_("/Select/Border..."), "<control><shift>B", select_border_cmd_callback, 0 },
  297.     "select/dialogs/border_selection.html", NULL },
  298.  
  299.   { { "/Select/---", NULL, NULL, 0, "<Separator>" },
  300.     NULL, NULL },
  301.   { { N_("/Select/Save to Channel"), NULL, select_save_cmd_callback, 0 },
  302.     "select/save_to_channel.html", NULL },
  303.  
  304.   /*  <Image>/View  */
  305.  
  306.   { { N_("/View/Zoom In"), "equal", view_zoomin_cmd_callback, 0 },
  307.     "view/zoom.html", NULL },
  308.   { { N_("/View/Zoom Out"), "minus", view_zoomout_cmd_callback, 0 },
  309.     "view/zoom.html", NULL },
  310.  
  311.   /*  <Image>/View/Zoom  */
  312.  
  313.   { { N_("/View/Zoom/16:1"), NULL, view_zoom_16_1_cmd_callback, 0 },
  314.     "view/zoom.html", NULL },
  315.   { { N_("/View/Zoom/8:1"), NULL, view_zoom_8_1_cmd_callback, 0 },
  316.     "view/zoom.html", NULL },
  317.   { { N_("/View/Zoom/4:1"), NULL, view_zoom_4_1_cmd_callback, 0 },
  318.     "view/zoom.html", NULL },
  319.   { { N_("/View/Zoom/2:1"), NULL, view_zoom_2_1_cmd_callback, 0 },
  320.     "view/zoom.html", NULL },
  321.   { { N_("/View/Zoom/1:1"), "1", view_zoom_1_1_cmd_callback, 0 },
  322.     "view/zoom.html", NULL },
  323.   { { N_("/View/Zoom/1:2"), NULL, view_zoom_1_2_cmd_callback, 0 },
  324.     "view/zoom.html", NULL },
  325.   { { N_("/View/Zoom/1:4"), NULL, view_zoom_1_4_cmd_callback, 0 },
  326.     "view/zoom.html", NULL },
  327.   { { N_("/View/Zoom/1:8"), NULL, view_zoom_1_8_cmd_callback, 0 },
  328.     "view/zoom.html", NULL },
  329.   { { N_("/View/Zoom/1:16"), NULL, view_zoom_1_16_cmd_callback, 0 },
  330.     "view/zoom.html", NULL },
  331.  
  332.   { { N_("/View/Dot for Dot"), NULL, view_dot_for_dot_cmd_callback, 0, "<ToggleItem>" },
  333.     "view/dot_for_dot.html", NULL },
  334.  
  335.   { { "/View/---", NULL, NULL, 0, "<Separator>" },
  336.     NULL, NULL },
  337.   { { N_("/View/Info Window..."), "<control><shift>I", view_info_window_cmd_callback, 0 },
  338.     "view/dialogs/info_window.html", NULL },
  339.   { { N_("/View/Nav. Window..."), "<control><shift>N", view_nav_window_cmd_callback, 0 },
  340.     "view/dialogs/navigation_window.html", NULL },
  341.  
  342.   { { "/View/---", NULL, NULL, 0, "<Separator>" },
  343.     NULL, NULL },
  344.   { { N_("/View/Toggle Selection"), "<control>T", view_toggle_selection_cmd_callback, 0, "<ToggleItem>" },
  345.     "view/toggle_selection.html", NULL },
  346.   { { N_("/View/Toggle Rulers"), "<control><shift>R", view_toggle_rulers_cmd_callback, 0, "<ToggleItem>" },
  347.     "view/toggle_rulers.html", NULL },
  348.   { { N_("/View/Toggle Statusbar"), "<control><shift>S", view_toggle_statusbar_cmd_callback, 0, "<ToggleItem>" },
  349.     "view/toggle_statusbar.html", NULL },
  350.   { { N_("/View/Toggle Guides"), "<control><shift>T", view_toggle_guides_cmd_callback, 0, "<ToggleItem>" },
  351.     "view/toggle_guides.html", NULL },
  352.   { { N_("/View/Snap to Guides"), NULL, view_snap_to_guides_cmd_callback, 0, "<ToggleItem>" },
  353.     "view/snap_to_guides.html", NULL },
  354.  
  355.   { { "/View/---", NULL, NULL, 0, "<Separator>" },
  356.     NULL, NULL },
  357.   { { N_("/View/New View"), NULL, view_new_view_cmd_callback, 0 },
  358.     "view/new_view.html", NULL },
  359.   { { N_("/View/Shrink Wrap"), "<control>E", view_shrink_wrap_cmd_callback, 0 },
  360.     "view/shrink_wrap.html", NULL },
  361.  
  362.   /*  <Image>/Image/Mode  */
  363.  
  364.   { { N_("/Image/Mode/RGB"), "<alt>R", image_convert_rgb_cmd_callback, 0 },
  365.     "image/mode/convert_to_rgb.html", NULL },
  366.   { { N_("/Image/Mode/Grayscale"), "<alt>G", image_convert_grayscale_cmd_callback, 0 },
  367.     "image/mode/convert_to_grayscale.html", NULL },
  368.   { { N_("/Image/Mode/Indexed..."), "<alt>I", image_convert_indexed_cmd_callback, 0 },
  369.     "image/mode/dialogs/convert_to_indexed.html", NULL },
  370.  
  371.   { { "/Image/Mode/---", NULL, NULL, 0, "<Separator>" },
  372.     NULL, NULL },
  373.  
  374.   /*  <Image>/Image/Colors  */
  375.  
  376.   { { N_("/Image/Colors/Desaturate"), NULL, image_desaturate_cmd_callback, 0 },
  377.     "image/colors/desaturate.html", NULL },
  378.   { { N_("/Image/Colors/Invert"), NULL, image_invert_cmd_callback, 0 },
  379.     "image/colors/invert.html", NULL },
  380.  
  381.   { { "/Image/Colors/---", NULL, NULL, 0, "<Separator>" },
  382.     NULL, NULL },
  383.  
  384.   /*  <Image>/Image/Colors/Auto  */
  385.  
  386.   { { N_("/Image/Colors/Auto/Equalize"), NULL, image_equalize_cmd_callback, 0 },
  387.     "image/colors/auto/equalize.html", NULL },
  388.  
  389.   { { "/Image/Colors/---", NULL, NULL, 0, "<Separator>" },
  390.     NULL, NULL },
  391.  
  392.   /*  <Image>/Image/Alpha  */
  393.  
  394.   { { N_("/Image/Alpha/Add Alpha Channel"), NULL, layers_add_alpha_channel_cmd_callback, 0 },
  395.     "layers/add_alpha_channel.html", NULL },
  396.  
  397.   /*  <Image>/Image/Transforms  */
  398.  
  399.   { { N_("/Image/Transforms/Offset..."), "<control><shift>O", image_offset_cmd_callback, 0 },
  400.     "image/transforms/dialogs/offset.html", NULL },
  401.   { { N_("/Image/Transforms/Rotate"), NULL, NULL, 0, "<Branch>" },
  402.     NULL, NULL },
  403.   { { "/Image/Transforms/---", NULL, NULL, 0, "<Separator>" },
  404.     NULL, NULL },
  405.  
  406.   { { "/Image/---", NULL, NULL, 0, "<Separator>" },
  407.     NULL, NULL },
  408.   { { N_("/Image/Canvas Size..."), NULL, image_resize_cmd_callback, 0 },
  409.     "image/dialogs/set_canvas_size.html", NULL },
  410.   { { N_("/Image/Scale Image..."), NULL, image_scale_cmd_callback, 0 },
  411.     "image/dialogs/scale_image.html", NULL },
  412.   { { N_("/Image/Duplicate"), "<control>D", image_duplicate_cmd_callback, 0 },
  413.     "image/duplicate.html", NULL },
  414.  
  415.   { { "/Image/---", NULL, NULL, 0, "<Separator>" },
  416.     NULL, NULL },
  417.  
  418.   /*  <Image>/Layers  */
  419.  
  420.   { { N_("/Layers/Layers, Channels & Paths..."), "<control>L", dialogs_lc_cmd_callback, 0 },
  421.     "dialogs/layers_and_channels.html", NULL },
  422.   { { "/Layers/---", NULL, NULL, 0, "<Separator>" },
  423.     NULL, NULL },
  424.   { { N_("/Layers/Layer to Imagesize"), NULL, layers_resize_to_image_cmd_callback, 0 },
  425.     "layers/layer_to_image_size.html", NULL },
  426.  
  427.   /*  <Image>/Layers/Stack  */
  428.  
  429.   { { N_("/Layers/Stack/Previous Layer"), "Prior", layers_previous_cmd_callback, 0 },
  430.     "layers/stack/stack.html#previous_layer", NULL },
  431.   { { N_("/Layers/Stack/Next Layer"), "Next", layers_next_cmd_callback, 0 },
  432.     "layers/stack/stack.html#next_layer", NULL },
  433.   { { N_("/Layers/Stack/Raise Layer"), "<shift>Prior", layers_raise_cmd_callback, 0 },
  434.     "layers/stack/stack.html#raise_layer", NULL },
  435.   { { N_("/Layers/Stack/Lower Layer"), "<shift>Next", layers_lower_cmd_callback, 0 },
  436.     "layers/stack/stack.html#lower_layer", NULL },
  437.   { { N_("/Layers/Stack/Layer to Top"), "<control>Prior", layers_raise_to_top_cmd_callback, 0 },
  438.     "layers/stack/stack.html#layer_to_top", NULL },
  439.   { { N_("/Layers/Stack/Layer to Bottom"), "<control>Next", layers_lower_to_bottom_cmd_callback, 0 },
  440.     "layers/stack/stack.html#layer_to_bottom", NULL },
  441.   { { "/Layers/Stack/---", NULL, NULL, 0, "<Separator>" },
  442.     NULL, NULL },
  443.  
  444.   /*  <Image>/Layers/Rotate  */
  445.  
  446.   { { N_("/Layers/Rotate"), NULL, NULL, 0, "<Branch>" },
  447.     NULL, NULL },
  448.  
  449.   { { "/Layers/---", NULL, NULL, 0, "<Separator>" },
  450.     NULL, NULL },
  451.   { { N_("/Layers/Anchor Layer"), "<control>H", layers_anchor_cmd_callback, 0 },
  452.     "layers/anchor_layer.html", NULL },
  453.   { { N_("/Layers/Merge Visible Layers..."), "<control>M", layers_merge_cmd_callback, 0 },
  454.     "layers/dialogs/merge_visible_layers.html", NULL },
  455.   { { N_("/Layers/Flatten Image"), NULL, layers_flatten_cmd_callback, 0 },
  456.     "layers/flatten_image.html", NULL },
  457.  
  458.   { { "/Layers/---", NULL, NULL, 0, "<Separator>" },
  459.     NULL, NULL },
  460.   { { N_("/Layers/Mask to Selection"), NULL, layers_mask_select_cmd_callback, 0 },
  461.     "layers/mask_to_selection.html", NULL },
  462.  
  463.   { { "/Layers/---", NULL, NULL, 0, "<Separator>" },
  464.     NULL, NULL },
  465.   { { N_("/Layers/Add Alpha Channel"), NULL, layers_add_alpha_channel_cmd_callback, 0 },
  466.     "layers/add_alpha_channel.html", NULL },
  467.   { { N_("/Layers/Alpha to Selection"), NULL, layers_alpha_select_cmd_callback, 0 },
  468.     "layers/alpha_to_selection.html", NULL },
  469.  
  470.   { { "/Layers/---", NULL, NULL, 0, "<Separator>" },
  471.     NULL, NULL },
  472.  
  473.   /*  <Image>/Tools  */
  474.  
  475.   { { N_("/Tools/Toolbox"), NULL, toolbox_raise_callback, 0 },
  476.     "toolbox/toolbox.html", NULL },
  477.   { { N_("/Tools/Default Colors"), "D", tools_default_colors_cmd_callback, 0 },
  478.     "toolbox/toolbox.html#default_colors", NULL },
  479.   { { N_("/Tools/Swap Colors"), "X", tools_swap_colors_cmd_callback, 0 },
  480.     "toolbox/toolbox.html#swap_colors", NULL },
  481.   { { "/Tools/---", NULL, NULL, 0, "<Separator>" },  
  482.     NULL, NULL },
  483.  
  484.   /*  <Image>/Dialogs  */
  485.  
  486.   { { N_("/Dialogs/Layers, Channels & Paths..."), "<control>L", dialogs_lc_cmd_callback, 0 },
  487.     "dialogs/layers_and_channels.html", NULL },
  488.   { { N_("/Dialogs/Tool Options..."), NULL, dialogs_tool_options_cmd_callback, 0 },
  489.     "dialogs/tool_options.html", NULL },
  490.  
  491.   { { "/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  492.     NULL, NULL },
  493.   { { N_("/Dialogs/Brushes..."), "<control><shift>B", dialogs_brushes_cmd_callback, 0 },
  494.     "dialogs/brush_selection.html", NULL },
  495.   { { N_("/Dialogs/Patterns..."), "<control><shift>P", dialogs_patterns_cmd_callback, 0 },
  496.     "dialogs/pattern_selection.html", NULL },
  497.   { { N_("/Dialogs/Gradients..."), "<control>G", dialogs_gradients_cmd_callback, 0 },
  498.     "dialogs/gradient_selection.html", NULL },
  499.   { { N_("/Dialogs/Palette..."), "<control>P", dialogs_palette_cmd_callback, 0 },
  500.     "dialogs/palette_selection.html", NULL },
  501.   { { N_("/Dialogs/Indexed Palette..."), NULL, dialogs_indexed_palette_cmd_callback, 0 },
  502.     "dialogs/indexed_palette.html", NULL },
  503.  
  504.   { { "/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  505.     NULL, NULL },
  506.   { { N_("/Dialogs/Input Devices..."), NULL, dialogs_input_devices_cmd_callback, 0 },
  507.     "dialogs/input_devices.html", NULL },
  508.   { { N_("/Dialogs/Device Status..."), NULL, dialogs_device_status_cmd_callback, 0 },
  509.     "dialogs/device_status.html", NULL },
  510.  
  511.   { { "/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  512.     NULL, NULL },
  513.   { { N_("/Dialogs/Document Index..."), NULL, dialogs_document_index_cmd_callback, 0 },
  514.     "dialogs/document_index.html", NULL },
  515.   { { N_("/Dialogs/Error Console..."), NULL, dialogs_error_console_cmd_callback, 0 },
  516.     "dialogs/error_console.html", NULL },
  517. #ifdef DISPLAY_FILTERS
  518.   { { N_("/Dialogs/Display Filters..."), NULL, dialogs_display_filters_cmd_callback, 0 },
  519.     "dialogs/display_filters/display_filters.html", NULL },
  520. #endif /* DISPLAY_FILTERS */
  521.   { { N_("/Dialogs/Undo History..."), NULL, dialogs_undo_history_cmd_callback, 0},
  522.     "dialogs/undo_history.html", NULL },
  523.  
  524.  
  525.   { { "/---", NULL, NULL, 0, "<Separator>" },
  526.     NULL, NULL },
  527.  
  528.   /*  <Image>/Filters  */
  529.  
  530.   { { N_("/Filters/Repeat Last"), "<alt>F", filters_repeat_cmd_callback, 0x0 },
  531.     "filters/repeat_last.html", NULL },
  532.   { { N_("/Filters/Re-Show Last"), "<alt><shift>F", filters_repeat_cmd_callback, 0x1 },
  533.     "filters/reshow_last.html", NULL },
  534.  
  535.   { { "/Filters/---", NULL, NULL, 0, "<Separator>" },
  536.     NULL, NULL },
  537.   { { N_("/Filters/Blur"), NULL, NULL, 0, "<Branch>" },
  538.     NULL, NULL },
  539.   { { N_("/Filters/Colors"), NULL, NULL, 0, "<Branch>" },
  540.     NULL, NULL },
  541.   { { N_("/Filters/Noise"), NULL, NULL, 0, "<Branch>" },
  542.     NULL, NULL },
  543.   { { N_("/Filters/Edge-Detect"), NULL, NULL, 0, "<Branch>" },
  544.     NULL, NULL },
  545.   { { N_("/Filters/Enhance"), NULL, NULL, 0, "<Branch>" },
  546.     NULL, NULL },
  547.   { { N_("/Filters/Generic"), NULL, NULL, 0, "<Branch>" },
  548.     NULL, NULL },
  549.  
  550.   { { "/Filters/---", NULL, NULL, 0, "<Separator>" },
  551.     NULL, NULL },
  552.   { { N_("/Filters/Glass Effects"), NULL, NULL, 0, "<Branch>" },
  553.     NULL, NULL },
  554.   { { N_("/Filters/Light Effects"), NULL, NULL, 0, "<Branch>" },
  555.     NULL, NULL },
  556.   { { N_("/Filters/Distorts"), NULL, NULL, 0, "<Branch>" },
  557.     NULL, NULL },
  558.   { { N_("/Filters/Artistic"), NULL, NULL, 0, "<Branch>" },
  559.     NULL, NULL },
  560.   { { N_("/Filters/Map"), NULL, NULL, 0, "<Branch>" },
  561.     NULL, NULL },
  562.   { { N_("/Filters/Render"), NULL, NULL, 0, "<Branch>" },
  563.     NULL, NULL },
  564.   { { N_("/Filters/Web"), NULL, NULL, 0, "<Branch>" },
  565.     NULL, NULL },
  566.  
  567.   { { "/Filters/---INSERT", NULL, NULL, 0, "<Separator>" },
  568.     NULL, NULL },
  569.   { { N_("/Filters/Animation"), NULL, NULL, 0, "<Branch>" },
  570.     NULL, NULL },
  571.   { { N_("/Filters/Combine"), NULL, NULL, 0, "<Branch>" },
  572.     NULL, NULL },
  573.  
  574.   { { "/Filters/---", NULL, NULL, 0, "<Separator>" },
  575.     NULL, NULL },
  576.   { { N_("/Filters/Toys"), NULL, NULL, 0, "<Branch>" },
  577.     NULL, NULL },
  578. };
  579. static guint n_image_entries = (sizeof (image_entries) /
  580.                 sizeof (image_entries[0]));
  581. static GtkItemFactory *image_factory = NULL;
  582.  
  583. /*****  <Load>  *****/
  584.  
  585. static GimpItemFactoryEntry load_entries[] =
  586. {
  587.   { { N_("/Automatic"), NULL, file_open_by_extension_callback, 0 },
  588.     "open_by_extension.html", NULL },
  589.  
  590.   { { "/---", NULL, NULL, 0, "<Separator>" },
  591.     NULL, NULL }
  592. };
  593. static guint n_load_entries = (sizeof (load_entries) /
  594.                    sizeof (load_entries[0]));
  595. static GtkItemFactory *load_factory = NULL;
  596.   
  597. /*****  <Save>  *****/
  598.  
  599. static GimpItemFactoryEntry save_entries[] =
  600. {
  601.   { { N_("/By Extension"), NULL, file_save_by_extension_callback, 0 },
  602.     "save_by_extension.html", NULL },
  603.  
  604.   { { "/---", NULL, NULL, 0, "<Separator>" },
  605.     NULL, NULL },
  606. };
  607. static guint n_save_entries = (sizeof (save_entries) /
  608.                    sizeof (save_entries[0]));
  609. static GtkItemFactory *save_factory = NULL;
  610.  
  611. /*****  <Layers>  *****/
  612.  
  613. static GimpItemFactoryEntry layers_entries[] =
  614. {
  615.   { { N_("/New Layer..."), "<control>N", layers_dialog_new_layer_callback, 0 },
  616.     "dialogs/new_layer.html", NULL },
  617.  
  618.   /*  <Layers>/Stack  */
  619.  
  620.   { { N_("/Stack/Raise Layer"), "<control>F", layers_dialog_raise_layer_callback, 0 },
  621.     "stack/stack.html#raise_layer", NULL },
  622.   { { N_("/Stack/Lower Layer"), "<control>B", layers_dialog_lower_layer_callback, 0 },
  623.     "stack/stack.html#lower_layer", NULL },
  624.   { { N_("/Stack/Layer to Top"), "<shift><control>F", layers_dialog_raise_layer_to_top_callback, 0 },
  625.     "stack/stack.html#later_to_top", NULL },
  626.   { { N_("/Stack/Layer to Bottom"), "<shift><control>B", layers_dialog_lower_layer_to_bottom_callback, 0 },
  627.     "stack/stack.html#layer_to_bottom", NULL },
  628.  
  629.   { { N_("/Duplicate Layer"), "<control>C", layers_dialog_duplicate_layer_callback, 0 },
  630.     "duplicate_layer.html", NULL },
  631.   { { N_("/Anchor Layer"), "<control>H", layers_dialog_anchor_layer_callback, 0 },
  632.     "anchor_layer.html", NULL },
  633.   { { N_("/Delete Layer"), "<control>X", layers_dialog_delete_layer_callback, 0 },
  634.     "delete_layer.html", NULL },
  635.  
  636.   { { "/---", NULL, NULL, 0, "<Separator>" },
  637.     NULL, NULL },
  638.   { { N_("/Layer Boundary Size..."), "<control>R", layers_dialog_resize_layer_callback, 0 },
  639.     "dialogs/layer_boundary_size.html", NULL },
  640.   { { N_("/Layer to Imagesize"), NULL, layers_dialog_resize_to_image_callback, 0 },
  641.     "layer_to_image_size.html", NULL },
  642.   { { N_("/Scale Layer..."), "<control>S", layers_dialog_scale_layer_callback, 0 },
  643.     "dialogs/scale_layer.html", NULL },
  644.       
  645.   { { "/---", NULL, NULL, 0, "<Separator>" },
  646.     NULL, NULL },
  647.   { { N_("/Merge Visible Layers..."), "<control>M", layers_dialog_merge_layers_callback, 0 },
  648.     "dialogs/merge_visible_layers.html", NULL },
  649.   { { N_("/Merge Down"), "<control><shift>M", layers_dialog_merge_down_callback, 0 },
  650.     "merge_down.html", NULL },
  651.   { { N_("/Flatten Image"), NULL, layers_dialog_flatten_image_callback, 0 },
  652.     "flatten_image.html", NULL },
  653.  
  654.   { { "/---", NULL, NULL, 0, "<Separator>" },
  655.     NULL, NULL },
  656.   { { N_("/Add Layer Mask..."), NULL, layers_dialog_add_layer_mask_callback, 0 },
  657.     "dialogs/add_layer_mask.html", NULL },
  658.   { { N_("/Apply Layer Mask"), NULL, layers_dialog_apply_layer_mask_callback, 0 },
  659.     "apply_mask.html", NULL },
  660.   { { N_("/Delete Layer Mask"), NULL, layers_dialog_delete_layer_mask_callback, 0 },
  661.     "delete_mask.html", NULL },
  662.   { { N_("/Mask to Selection"), NULL, layers_dialog_mask_select_callback, 0 },
  663.     "mask_to_selection.html", NULL },
  664.  
  665.   { { "/---", NULL, NULL, 0, "<Separator>" },
  666.     NULL, NULL },
  667.   { { N_("/Add Alpha Channel"), NULL, layers_dialog_add_alpha_channel_callback, 0 },
  668.     "add_alpha_channel.html", NULL },
  669.   { { N_("/Alpha to Selection"), NULL, layers_dialog_alpha_select_callback, 0 },
  670.     "alpha_to_selection.html", NULL },
  671.  
  672.   { { "/---", NULL, NULL, 0, "<Separator>" },
  673.     NULL, NULL },
  674.   { { N_("/Edit Layer Attributes..."), NULL, layers_dialog_edit_layer_attributes_callback, 0 },
  675.     "dialogs/edit_layer_attributes.html", NULL }
  676. };
  677. static guint n_layers_entries = (sizeof (layers_entries) /
  678.                  sizeof (layers_entries[0]));
  679. static GtkItemFactory *layers_factory = NULL;
  680.  
  681. /*****  <Channels>  *****/
  682.  
  683. static GimpItemFactoryEntry channels_entries[] =
  684. {
  685.   { { N_("/New Channel..."), "<control>N", channels_dialog_new_channel_callback, 0 },
  686.     "dialogs/new_channel.html", NULL },
  687.   { { N_("/Raise Channel"), "<control>F", channels_dialog_raise_channel_callback, 0 },
  688.     "raise_channel.html", NULL },
  689.   { { N_("/Lower Channel"), "<control>B", channels_dialog_lower_channel_callback, 0 },
  690.     "lower_channel.html", NULL },
  691.   { { N_("/Duplicate Channel"), "<control>C", channels_dialog_duplicate_channel_callback, 0 },
  692.     "duplicate_channel.html", NULL },
  693.  
  694.   { { "/---", NULL, NULL, 0, "<Separator>" },
  695.     NULL, NULL },
  696.   { { N_("/Channel to Selection"), "<control>S", channels_dialog_channel_to_sel_callback, 0 },
  697.     "channel_to_selection.html", NULL },
  698.   { { N_("/Add to Selection"), NULL, channels_dialog_add_channel_to_sel_callback, 0 },
  699.     "channel_to_selection.html#add", NULL },
  700.   { { N_("/Subtract from Selection"), NULL, channels_dialog_sub_channel_from_sel_callback, 0 },
  701.     "channel_to_selection.html#subtract", NULL },
  702.   { { N_("/Intersect with Selection"), NULL, channels_dialog_intersect_channel_with_sel_callback, 0 },
  703.     "channel_to_selection.html#intersect", NULL },
  704.  
  705.   { { "/---", NULL, NULL, 0, "<Separator>" },
  706.     NULL, NULL },
  707.   { { N_("/Delete Channel"), "<control>X", channels_dialog_delete_channel_callback, 0 },
  708.     "delete_channel.html", NULL },
  709.  
  710.   { { "/---", NULL, NULL, 0, "<Separator>" },
  711.     NULL, NULL },
  712.   { { N_("/Edit Channel Attributes..."), NULL, channels_dialog_edit_channel_attributes_callback, 0 },
  713.     "dialogs/edit_channel_attributes.html", NULL }
  714. };
  715. static guint n_channels_entries = (sizeof (channels_entries) /
  716.                    sizeof (channels_entries[0]));
  717. static GtkItemFactory *channels_factory = NULL;
  718.  
  719. /*****  <Paths>  *****/
  720.  
  721. static GimpItemFactoryEntry paths_entries[] =
  722. {
  723.   { { N_("/New Path"), "<control>N", paths_dialog_new_path_callback, 0 },
  724.     "new_path.html", NULL },
  725.   { { N_("/Duplicate Path"), "<control>U", paths_dialog_dup_path_callback, 0 },
  726.     "duplicate_path.html", NULL },
  727.   { { N_("/Path to Selection"), "<control>S", paths_dialog_path_to_sel_callback, 0 },
  728.     "path_to_selection.html", NULL },
  729.   { { N_("/Selection to Path"), "<control>P", paths_dialog_sel_to_path_callback, 0 },
  730.     "filters/sel2path.html", NULL },
  731.   { { N_("/Stroke Path"), "<control>T", paths_dialog_stroke_path_callback, 0 },
  732.     "stroke_path.html", NULL },
  733.   { { N_("/Delete Path"), "<control>X", paths_dialog_delete_path_callback, 0 },
  734.     "delete_path.html", NULL },
  735.  
  736.   { { "/---", NULL, NULL, 0, "<Separator>" },
  737.     NULL, NULL },
  738.   { { N_("/Copy Path"), "<control>C", paths_dialog_copy_path_callback, 0 },
  739.     "copy_path.html", NULL },
  740.   { { N_("/Paste Path"), "<control>V", paths_dialog_paste_path_callback, 0 },
  741.     "paste_path.html", NULL },
  742.   { { N_("/Import Path..."), "<control>I", paths_dialog_import_path_callback, 0 },
  743.     "dialogs/import_path.html", NULL },
  744.   { { N_("/Export Path..."), "<control>E", paths_dialog_export_path_callback, 0 },
  745.     "dialogs/export_path.html", NULL },
  746.  
  747.   { { "/---", NULL, NULL, 0, "<Separator>" },
  748.     NULL, NULL },
  749.   { { N_("/Edit Path Attributes..."), NULL, paths_dialog_edit_path_attributes_callback, 0 },
  750.     "dialogs/edit_path_attributes.html", NULL }
  751. };
  752. static guint n_paths_entries = (sizeof (paths_entries) /
  753.                 sizeof (paths_entries[0]));
  754. static GtkItemFactory *paths_factory = NULL;
  755.  
  756. static gboolean menus_initialized = FALSE;
  757.  
  758. void
  759. menus_get_toolbox_menubar (GtkWidget     **menubar,
  760.                GtkAccelGroup **accel_group)
  761. {
  762.   if (!menus_initialized)
  763.     menus_init ();
  764.   
  765.   if (menubar)
  766.     *menubar = toolbox_factory->widget;
  767.   if (accel_group)
  768.     *accel_group = toolbox_factory->accel_group;
  769. }
  770.  
  771. void
  772. menus_get_image_menu (GtkWidget     **menu,
  773.               GtkAccelGroup **accel_group)
  774. {
  775.   if (!menus_initialized)
  776.     menus_init ();
  777.  
  778.   if (menu)
  779.     *menu = image_factory->widget;
  780.   if (accel_group)
  781.     *accel_group = image_factory->accel_group;
  782. }
  783.  
  784. void
  785. menus_get_load_menu (GtkWidget     **menu,
  786.              GtkAccelGroup **accel_group)
  787. {
  788.   if (!menus_initialized)
  789.     menus_init ();
  790.  
  791.   if (menu)
  792.     *menu = load_factory->widget;
  793.   if (accel_group)
  794.     *accel_group = load_factory->accel_group;
  795. }
  796.  
  797. void
  798. menus_get_save_menu (GtkWidget     **menu,
  799.              GtkAccelGroup **accel_group)
  800. {
  801.   if (!menus_initialized)
  802.     menus_init ();
  803.  
  804.   if (menu)
  805.     *menu = save_factory->widget;
  806.   if (accel_group)
  807.     *accel_group = save_factory->accel_group;
  808. }
  809.  
  810. void
  811. menus_get_layers_menu (GtkWidget     **menu,
  812.                GtkAccelGroup **accel_group)
  813. {
  814.   if (!menus_initialized)
  815.     menus_init ();
  816.  
  817.   if (menu)
  818.     *menu = layers_factory->widget;
  819.   if (accel_group)
  820.     *accel_group = layers_factory->accel_group;
  821. }
  822.  
  823. void
  824. menus_get_channels_menu (GtkWidget     **menu,
  825.              GtkAccelGroup **accel_group)
  826. {
  827.   if (!menus_initialized)
  828.     menus_init ();
  829.  
  830.   if (menu)
  831.     *menu = channels_factory->widget;
  832.   if (accel_group)
  833.     *accel_group = channels_factory->accel_group;
  834. }
  835.  
  836. void
  837. menus_get_paths_menu (GtkWidget     **menu,
  838.               GtkAccelGroup **accel_group)
  839. {
  840.   if (!menus_initialized)
  841.     menus_init ();
  842.  
  843.   if (menu)
  844.     *menu = paths_factory->widget;
  845.   if (accel_group)
  846.     *accel_group = paths_factory->accel_group;
  847. }
  848.  
  849. void
  850. menus_create_item_from_full_path (GimpItemFactoryEntry *entry,
  851.                   gchar                *domain_name,
  852.                   gpointer              callback_data)
  853. {
  854.   GtkItemFactory *item_factory;
  855.   gchar *path;
  856.  
  857.   if (!menus_initialized)
  858.     menus_init ();
  859.  
  860.   path = entry->entry.path;
  861.   item_factory = gtk_item_factory_from_path (path);
  862.  
  863.   if (!item_factory)
  864.     {
  865.       g_warning ("entry refers to unknown item factory: \"%s\"", path);
  866.       return;
  867.     }
  868.  
  869.   gtk_object_set_data (GTK_OBJECT (item_factory), "textdomain", domain_name);
  870.  
  871.   while (*path != '>')
  872.     path++;
  873.   path++;
  874.  
  875.   entry->entry.path = path;
  876.  
  877.   menus_create_item (item_factory, entry, callback_data, 2);
  878. }
  879.  
  880. static void
  881. menus_create_branches (GtkItemFactory       *item_factory,
  882.                GimpItemFactoryEntry *entry)
  883. {
  884.   GString *tearoff_path;
  885.   gint factory_length;
  886.   gchar *p;
  887.   gchar *path;
  888.  
  889.   tearoff_path = g_string_new ("");
  890.  
  891.   path = entry->entry.path;
  892.   p = strchr (path, '/');
  893.   factory_length = p - path;
  894.  
  895.   /*  skip the first slash  */
  896.   if (p)
  897.     p = strchr (p + 1, '/');
  898.  
  899.   while (p)
  900.     {
  901.       g_string_assign (tearoff_path, path + factory_length);
  902.       g_string_truncate (tearoff_path, p - path - factory_length);
  903.  
  904.       if (!gtk_item_factory_get_widget (item_factory, tearoff_path->str))
  905.     {
  906.       GimpItemFactoryEntry branch_entry =
  907.       {
  908.         { NULL, NULL, NULL, 0, "<Branch>" },
  909.         NULL,
  910.         NULL
  911.       };
  912.  
  913.       branch_entry.entry.path = tearoff_path->str;
  914.       gtk_object_set_data (GTK_OBJECT (item_factory), "complete", path);
  915.       menus_create_item (item_factory, &branch_entry, NULL, 2);
  916.       gtk_object_remove_data (GTK_OBJECT (item_factory), "complete");
  917.     }
  918.  
  919.       g_string_append (tearoff_path, "/tearoff1");
  920.  
  921.       if (!gtk_item_factory_get_widget (item_factory, tearoff_path->str))
  922.     {
  923.       GimpItemFactoryEntry tearoff_entry =
  924.       {
  925.         { NULL, NULL, tearoff_cmd_callback, 0, "<Tearoff>" },
  926.         NULL,
  927.         NULL
  928.       };
  929.  
  930.       tearoff_entry.entry.path = tearoff_path->str;
  931.       menus_create_item (item_factory, &tearoff_entry, NULL, 2);
  932.     }
  933.  
  934.       p = strchr (p + 1, '/');
  935.     }
  936.  
  937.   g_string_free (tearoff_path, TRUE);
  938. }
  939.  
  940. static void
  941. menus_filters_subdirs_to_top (GtkMenu *menu)
  942. {
  943.   GtkMenuItem *menu_item;
  944.   GList *list;
  945.   gboolean submenus_passed = FALSE;
  946.   gint pos;
  947.   gint items;
  948.  
  949.   pos = 1;
  950.   items = 0;
  951.  
  952.   for (list = GTK_MENU_SHELL (menu)->children; list; list = g_list_next (list))
  953.     {
  954.       menu_item = GTK_MENU_ITEM (list->data);
  955.       items++;
  956.       
  957.       if (menu_item->submenu)
  958.     {
  959.       if (submenus_passed)
  960.         {
  961.           menus_filters_subdirs_to_top (GTK_MENU (menu_item->submenu));
  962.           gtk_menu_reorder_child (menu, GTK_WIDGET (menu_item), pos++);
  963.         }
  964.     }
  965.       else
  966.     {
  967.       submenus_passed = TRUE;
  968.     }
  969.     }
  970.  
  971.   if (pos > 1 && items > pos)
  972.     {
  973.       GtkWidget *separator;
  974.  
  975.       separator = gtk_menu_item_new ();
  976.       gtk_menu_insert (menu, separator, pos);
  977.       gtk_widget_show (separator);
  978.     }
  979. }
  980.  
  981. void
  982. menus_reorder_plugins (void)
  983. {
  984.   static gchar *rotate_plugins[] = { "90 degrees",
  985.                      "180 degrees",
  986.                                      "270 degrees" };
  987.   static gint n_rotate_plugins = (sizeof (rotate_plugins) /
  988.                   sizeof (rotate_plugins[0]));
  989.  
  990.   static gchar *image_file_entries[] = { "---moved",
  991.                      "Close",
  992.                      "Quit" };
  993.   static gint n_image_file_entries = (sizeof (image_file_entries) /
  994.                       sizeof (image_file_entries[0]));
  995.  
  996.   static gchar *reorder_submenus[] = { "<Image>/Video",
  997.                        "<Image>/Script-Fu" };
  998.   static gint n_reorder_submenus = (sizeof (reorder_submenus) /
  999.                     sizeof (reorder_submenus[0]));
  1000.  
  1001.   static gchar *reorder_subsubmenus[] = { "<Image>/Filters",
  1002.                       "<Toolbox>/Xtns" };
  1003.   static gint n_reorder_subsubmenus = (sizeof (reorder_subsubmenus) /
  1004.                        sizeof (reorder_subsubmenus[0]));
  1005.  
  1006.   GtkItemFactory *item_factory;
  1007.   GtkWidget *menu_item;
  1008.   GtkWidget *menu;
  1009.   GList *list;
  1010.   gchar *path;
  1011.   gint   i, pos;
  1012.  
  1013.   /*  Move all menu items under "<Toolbox>/Xtns" which are not submenus or
  1014.    *  separators to the top of the menu
  1015.    */
  1016.   pos = 1;
  1017.   menu_item = gtk_item_factory_get_widget (toolbox_factory,
  1018.                        "/Xtns/Module Browser...");
  1019.   if (menu_item && menu_item->parent && GTK_IS_MENU (menu_item->parent))
  1020.     {
  1021.       menu = menu_item->parent;
  1022.  
  1023.       for (list = g_list_nth (GTK_MENU_SHELL (menu)->children, pos); list;
  1024.        list = g_list_next (list))
  1025.     {
  1026.       menu_item = GTK_WIDGET (list->data);
  1027.  
  1028.       if (! GTK_MENU_ITEM (menu_item)->submenu &&
  1029.           GTK_IS_LABEL (GTK_BIN (menu_item)->child))
  1030.         {
  1031.           gtk_menu_reorder_child (GTK_MENU (menu_item->parent),
  1032.                       menu_item, pos);
  1033.           list = g_list_nth (GTK_MENU_SHELL (menu)->children, pos);
  1034.           pos++;
  1035.         }
  1036.     }
  1037.     }
  1038.  
  1039.   /*  Move all menu items under "<Image>/Filters" which are not submenus or
  1040.    *  separators to the top of the menu
  1041.    */
  1042.   pos = 3;
  1043.   menu_item = gtk_item_factory_get_widget (image_factory,
  1044.                        "/Filters/Filter all Layers...");
  1045.   if (menu_item && menu_item->parent && GTK_IS_MENU (menu_item->parent))
  1046.     {
  1047.       menu = menu_item->parent;
  1048.  
  1049.       for (list = g_list_nth (GTK_MENU_SHELL (menu)->children, pos); list;
  1050.        list = g_list_next (list))
  1051.     {
  1052.       menu_item = GTK_WIDGET (list->data);
  1053.  
  1054.       if (! GTK_MENU_ITEM (menu_item)->submenu &&
  1055.           GTK_IS_LABEL (GTK_BIN (menu_item)->child))
  1056.         {
  1057.           gtk_menu_reorder_child (GTK_MENU (menu_item->parent),
  1058.                       menu_item, pos);
  1059.           list = g_list_nth (GTK_MENU_SHELL (menu)->children, pos);
  1060.           pos++;
  1061.         }
  1062.     }
  1063.     }
  1064.  
  1065.   /*  Reorder Rotate plugin menu entries */
  1066.   pos = 2;
  1067.   for (i = 0; i < n_rotate_plugins; i++)
  1068.     {
  1069.       path = g_strconcat ("/Image/Transforms/Rotate/", rotate_plugins[i], NULL);
  1070.       menu_item = gtk_item_factory_get_widget (image_factory, path);
  1071.       g_free (path);
  1072.  
  1073.       if (menu_item && menu_item->parent)
  1074.         {
  1075.           gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, pos);
  1076.           pos++;
  1077.         }
  1078.     }
  1079.  
  1080.   pos = 2;
  1081.   for (i = 0; i < n_rotate_plugins; i++)
  1082.     {
  1083.       path = g_strconcat ("/Layers/Rotate/", rotate_plugins[i], NULL);
  1084.       menu_item = gtk_item_factory_get_widget (image_factory, path);
  1085.       g_free (path);
  1086.  
  1087.       if (menu_item && menu_item->parent)
  1088.         {
  1089.           gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, pos);
  1090.           pos++;
  1091.         }
  1092.     }
  1093.  
  1094.   /*  Reorder "<Image>/File"  */
  1095.   for (i = 0; i < n_image_file_entries; i++)
  1096.     {
  1097.       path = g_strconcat ("/File/", image_file_entries[i], NULL);
  1098.       menu_item = gtk_item_factory_get_widget (image_factory, path);
  1099.       g_free (path);
  1100.  
  1101.       if (menu_item && menu_item->parent)
  1102.     gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, -1);
  1103.     }
  1104.  
  1105.   /*  Reorder menus where plugins registered submenus  */
  1106.   for (i = 0; i < n_reorder_submenus; i++)
  1107.     {
  1108.       item_factory = gtk_item_factory_from_path (reorder_submenus[i]);
  1109.       menu = gtk_item_factory_get_widget (item_factory,
  1110.                       reorder_submenus[i]);
  1111.  
  1112.       if (menu && GTK_IS_MENU (menu))
  1113.     {
  1114.       menus_filters_subdirs_to_top (GTK_MENU (menu));
  1115.     }
  1116.     }
  1117.  
  1118.   for (i = 0; i < n_reorder_subsubmenus; i++)
  1119.     {
  1120.       item_factory = gtk_item_factory_from_path (reorder_subsubmenus[i]);
  1121.       menu = gtk_item_factory_get_widget (item_factory,
  1122.                       reorder_subsubmenus[i]);
  1123.  
  1124.       if (menu && GTK_IS_MENU (menu))
  1125.     {
  1126.       for (list = GTK_MENU_SHELL (menu)->children; list;
  1127.            list = g_list_next (list))
  1128.         {
  1129.           GtkMenuItem *menu_item;
  1130.  
  1131.           menu_item = GTK_MENU_ITEM (list->data);
  1132.  
  1133.           if (menu_item->submenu)
  1134.         menus_filters_subdirs_to_top (GTK_MENU (menu_item->submenu));
  1135.         }
  1136.     }
  1137.     }
  1138.  
  1139.   /*  Move all submenus which registered after "<Image>/Filters/Toys"
  1140.    *  before the separator after "<Image>/Filters/Web"
  1141.    */
  1142.   menu_item = gtk_item_factory_get_widget (image_factory,
  1143.                        "/Filters/---INSERT");
  1144.  
  1145.   if (menu_item && menu_item->parent && GTK_IS_MENU (menu_item->parent))
  1146.     {
  1147.       menu = menu_item->parent;
  1148.       pos = g_list_index (GTK_MENU_SHELL (menu)->children, menu_item);
  1149.  
  1150.       menu_item = gtk_item_factory_get_widget (image_factory,
  1151.                            "/Filters/Toys");
  1152.  
  1153.       if (menu_item && GTK_IS_MENU (menu_item))
  1154.     {
  1155.       GList *list;
  1156.       gint index = 1;
  1157.  
  1158.       for (list = GTK_MENU_SHELL (menu)->children; list;
  1159.            list = g_list_next (list))
  1160.         {
  1161.           if (GTK_MENU_ITEM (list->data)->submenu == menu_item)
  1162.         break;
  1163.  
  1164.           index++;
  1165.         }
  1166.  
  1167.       while ((menu_item = g_list_nth_data (GTK_MENU_SHELL (menu)->children,
  1168.                            index)))
  1169.         {
  1170.           gtk_menu_reorder_child (GTK_MENU (menu), menu_item, pos);
  1171.  
  1172.           pos++;
  1173.           index++;
  1174.         }
  1175.     }
  1176.     }
  1177. }
  1178.  
  1179. static void
  1180. menus_tools_create (ToolInfo *tool_info)
  1181. {
  1182.   GimpItemFactoryEntry entry;
  1183.  
  1184.   if (tool_info->menu_path == NULL)
  1185.     return;
  1186.  
  1187.   entry.entry.path            = tool_info->menu_path;
  1188.   entry.entry.accelerator     = tool_info->menu_accel;
  1189.   entry.entry.callback        = tools_select_cmd_callback;
  1190.   entry.entry.callback_action = tool_info->tool_id;
  1191.   entry.entry.item_type       = NULL;
  1192.   entry.help_page             = tool_info->private_tip;
  1193.   entry.description           = NULL;
  1194.  
  1195.   menus_create_item (image_factory, &entry, (gpointer) tool_info, 2);
  1196. }
  1197.  
  1198. void
  1199. menus_set_sensitive (gchar    *path,
  1200.              gboolean  sensitive)
  1201. {
  1202.   GtkItemFactory *ifactory;
  1203.   GtkWidget *widget = NULL;
  1204.  
  1205.   if (!menus_initialized)
  1206.     menus_init ();
  1207.  
  1208.   ifactory = gtk_item_factory_from_path (path);
  1209.  
  1210.   if (ifactory)
  1211.     {
  1212.       widget = gtk_item_factory_get_widget (ifactory, path);
  1213.  
  1214.       if (widget)
  1215.     gtk_widget_set_sensitive (widget, sensitive);
  1216.     }
  1217.  
  1218.   if ((!ifactory || !widget) && ! strstr (path, "Script-Fu"))
  1219.     g_warning ("Unable to set sensitivity for menu which doesn't exist:\n%s",
  1220.            path);
  1221. }
  1222.  
  1223. void
  1224. menus_set_state (gchar    *path,
  1225.          gboolean  state)
  1226. {
  1227.   GtkItemFactory *ifactory;
  1228.   GtkWidget *widget = NULL;
  1229.  
  1230.   if (!menus_initialized)
  1231.     menus_init ();
  1232.  
  1233.   ifactory = gtk_item_factory_from_path (path);
  1234.  
  1235.   if (ifactory)
  1236.     {
  1237.       widget = gtk_item_factory_get_widget (ifactory, path);
  1238.  
  1239.       if (widget && GTK_IS_CHECK_MENU_ITEM (widget))
  1240.     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), state);
  1241.       else
  1242.     widget = NULL;
  1243.     }
  1244.  
  1245.   if ((!ifactory || !widget) && ! strstr (path, "Script-Fu"))
  1246.     g_warning ("Unable to set state for menu which doesn't exist:\n%s\n",
  1247.            path);
  1248. }
  1249.  
  1250. void
  1251. menus_destroy (gchar *path)
  1252. {
  1253.   if (!menus_initialized)
  1254.     menus_init ();
  1255.  
  1256.   gtk_item_factories_path_delete (NULL, path);
  1257. }
  1258.  
  1259. void
  1260. menus_quit (void)
  1261. {
  1262.   gchar *filename;
  1263.  
  1264.   filename = gimp_personal_rc_file ("menurc");
  1265.   gtk_item_factory_dump_rc (filename, NULL, TRUE);
  1266.   g_free (filename);
  1267.  
  1268.   if (menus_initialized)
  1269.     {
  1270.       gtk_object_unref (GTK_OBJECT (toolbox_factory));
  1271.       gtk_object_unref (GTK_OBJECT (image_factory));
  1272.       gtk_object_unref (GTK_OBJECT (load_factory));
  1273.       gtk_object_unref (GTK_OBJECT (save_factory));
  1274.       gtk_object_unref (GTK_OBJECT (layers_factory));
  1275.       gtk_object_unref (GTK_OBJECT (channels_factory));
  1276.       gtk_object_unref (GTK_OBJECT (paths_factory));
  1277.     }
  1278. }
  1279.  
  1280. static void
  1281. menus_last_opened_cmd_callback (GtkWidget *widget,
  1282.                                 gpointer   callback_data,
  1283.                                 guint      num)
  1284. {
  1285.   gchar *filename, *raw_filename;
  1286.   guint num_entries;
  1287.   gint  status;
  1288.  
  1289.   num_entries = g_slist_length (last_opened_raw_filenames); 
  1290.   if (num >= num_entries)
  1291.     return;
  1292.  
  1293.   raw_filename =
  1294.     ((GString *) g_slist_nth_data (last_opened_raw_filenames, num))->str;
  1295.   filename = g_basename (raw_filename);
  1296.  
  1297.   status = file_open (raw_filename, raw_filename);
  1298.  
  1299.   if (status != PDB_SUCCESS &&
  1300.       status != PDB_CANCEL)
  1301.     {
  1302.       g_message (_("Error opening file: %s\n"), raw_filename);
  1303.     }
  1304. }
  1305.  
  1306. static void
  1307. menus_last_opened_update_labels (void)
  1308. {
  1309.   GSList    *filename_slist;
  1310.   GString   *entry_filename;
  1311.   GString   *path;
  1312.   GtkWidget *widget;
  1313.   gint         i;
  1314.   guint      num_entries;
  1315.  
  1316.   entry_filename = g_string_new ("");
  1317.   path = g_string_new ("");
  1318.  
  1319.   filename_slist = last_opened_raw_filenames;
  1320.   num_entries = g_slist_length (last_opened_raw_filenames); 
  1321.  
  1322.   for (i = 1; i <= num_entries; i++)
  1323.     {
  1324.       g_string_sprintf (entry_filename, "%d. %s", i,
  1325.             g_basename (((GString *) filename_slist->data)->str));
  1326.  
  1327.       g_string_sprintf (path, "/File/MRU%02d", i);
  1328.  
  1329.       widget = gtk_item_factory_get_widget (toolbox_factory, path->str);
  1330.       if (widget)
  1331.     {
  1332.       gtk_widget_show (widget);
  1333.  
  1334.       gtk_label_set_text (GTK_LABEL (GTK_BIN (widget)->child),
  1335.                   entry_filename->str);
  1336.       gimp_help_set_help_data (widget, 
  1337.                    ((GString *) filename_slist->data)->str, NULL);
  1338.     }
  1339.       filename_slist = filename_slist->next;
  1340.     }
  1341.  
  1342.   g_string_free (entry_filename, TRUE);
  1343.   g_string_free (path, TRUE);
  1344. }
  1345.  
  1346. void
  1347. menus_last_opened_add (gchar *filename)
  1348. {
  1349.   GString   *raw_filename;
  1350.   GSList    *list;
  1351.   GtkWidget *menu_item;
  1352.   guint      num_entries;
  1353.  
  1354.   /*  do nothing if we've already got the filename on the list  */
  1355.   for (list = last_opened_raw_filenames; list; list = g_slist_next (list))
  1356.     {
  1357.       raw_filename = list->data;
  1358.  
  1359.       if (strcmp (raw_filename->str, filename) == 0)
  1360.     {
  1361.       /* the following lines would move the entry to the top
  1362.            *
  1363.        * last_opened_raw_filenames = g_slist_remove_link (last_opened_raw_filenames, list);
  1364.        * last_opened_raw_filenames = g_slist_concat (list, last_opened_raw_filenames);
  1365.        * menus_last_opened_update_labels ();
  1366.        */
  1367.       return;
  1368.     }
  1369.     }
  1370.  
  1371.   num_entries = g_slist_length (last_opened_raw_filenames);
  1372.  
  1373.   if (num_entries == last_opened_size)
  1374.     {
  1375.       list = g_slist_last (last_opened_raw_filenames);
  1376.       if (list)
  1377.     {
  1378.       g_string_free ((GString *)list->data, TRUE);
  1379.       last_opened_raw_filenames = 
  1380.         g_slist_remove (last_opened_raw_filenames, list);
  1381.     }
  1382.     }
  1383.  
  1384.   raw_filename = g_string_new (filename);
  1385.   last_opened_raw_filenames = g_slist_prepend (last_opened_raw_filenames,
  1386.                            raw_filename);
  1387.  
  1388.   if (num_entries == 0)
  1389.     {
  1390.       menu_item = gtk_item_factory_get_widget (toolbox_factory, 
  1391.                            "/File/---MRU");
  1392.       gtk_widget_show (menu_item);
  1393.     }
  1394.  
  1395.   menus_last_opened_update_labels ();
  1396. }
  1397.  
  1398. static void
  1399. menus_init_mru (void)
  1400. {
  1401.   GimpItemFactoryEntry *last_opened_entries;
  1402.   GtkWidget           *menu_item;
  1403.   gchar    *paths;
  1404.   gchar *accelerators;
  1405.   gint     i;
  1406.   
  1407.   last_opened_entries = g_new (GimpItemFactoryEntry, last_opened_size);
  1408.  
  1409.   paths = g_new (gchar, last_opened_size * MRU_MENU_ENTRY_SIZE);
  1410.   accelerators = g_new (gchar, 9 * MRU_MENU_ACCEL_SIZE);
  1411.  
  1412.   for (i = 0; i < last_opened_size; i++)
  1413.     {
  1414.       gchar *path, *accelerator;
  1415.  
  1416.       path = &paths[i * MRU_MENU_ENTRY_SIZE];
  1417.       if (i < 9)
  1418.         accelerator = &accelerators[i * MRU_MENU_ACCEL_SIZE];
  1419.       else
  1420.         accelerator = NULL;
  1421.     
  1422.       last_opened_entries[i].entry.path = path;
  1423.       last_opened_entries[i].entry.accelerator = accelerator;
  1424.       last_opened_entries[i].entry.callback =
  1425.     (GtkItemFactoryCallback) menus_last_opened_cmd_callback;
  1426.       last_opened_entries[i].entry.callback_action = i;
  1427.       last_opened_entries[i].entry.item_type = NULL;
  1428.       last_opened_entries[i].help_page = "file/last_opened.html";
  1429.       last_opened_entries[i].description = NULL;
  1430.  
  1431.       g_snprintf (path, MRU_MENU_ENTRY_SIZE, "/File/MRU%02d", i + 1);
  1432.       if (accelerator != NULL)
  1433.     g_snprintf (accelerator, MRU_MENU_ACCEL_SIZE, "<control>%d", i + 1);
  1434.     }
  1435.  
  1436.   menus_create_items (toolbox_factory, last_opened_size,
  1437.               last_opened_entries, NULL, 2);
  1438.   
  1439.   for (i=0; i < last_opened_size; i++)
  1440.     {
  1441.       menu_item =
  1442.     gtk_item_factory_get_widget (toolbox_factory,
  1443.                      last_opened_entries[i].entry.path);
  1444.       gtk_widget_hide (menu_item);
  1445.     }
  1446.  
  1447.   menu_item = gtk_item_factory_get_widget (toolbox_factory, "/File/---MRU");
  1448.   if (menu_item && menu_item->parent)
  1449.     gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, -1);
  1450.   gtk_widget_hide (menu_item);
  1451.  
  1452.   menu_item = gtk_item_factory_get_widget (toolbox_factory, "/File/Quit");
  1453.   if (menu_item && menu_item->parent)
  1454.     gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, -1);
  1455.  
  1456.   g_free (paths);
  1457.   g_free (accelerators);
  1458.   g_free (last_opened_entries);
  1459. }
  1460.  
  1461. /*  This function gets called while browsing a menu created
  1462.  *  by a GtkItemFactory
  1463.  */
  1464. static gint
  1465. menus_item_key_press (GtkWidget   *widget,
  1466.               GdkEventKey *kevent,
  1467.               gpointer     data)
  1468. {
  1469.   GtkItemFactory *item_factory     = NULL;
  1470.   GtkWidget      *active_menu_item = NULL;
  1471.   gchar *factory_path = NULL;
  1472.   gchar *help_path    = NULL;
  1473.   gchar *help_page    = NULL;
  1474.  
  1475.   item_factory = (GtkItemFactory *) data;
  1476.   active_menu_item = GTK_MENU_SHELL (widget)->active_menu_item;
  1477.  
  1478.   /*  first, get the help page from the item
  1479.    */
  1480.   if (active_menu_item)
  1481.     {
  1482.       help_page = (gchar *) gtk_object_get_data (GTK_OBJECT (active_menu_item),
  1483.                          "help_page");
  1484.     }
  1485.  
  1486.   /*  For any key except F1, continue with the standard
  1487.    *  GtkItemFactory callback and assign a new shortcut, but don't
  1488.    *  assign a shortcut to the help menu entries...
  1489.    */
  1490.   if (kevent->keyval != GDK_F1)
  1491.     {
  1492.       if (help_page &&
  1493.       *help_page &&
  1494.       item_factory == toolbox_factory &&
  1495.       (strcmp (help_page, "help/dialogs/help.html") == 0 ||
  1496.        strcmp (help_page, "help/context_help.html") == 0))
  1497.     {
  1498.       gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), 
  1499.                     "key_press_event");
  1500.       return TRUE;
  1501.     }
  1502.       else
  1503.     {
  1504.       return FALSE;
  1505.     }
  1506.     }
  1507.  
  1508.   /*  ...finally, if F1 was pressed over any menu, show it's help page...
  1509.    */
  1510.   gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
  1511.  
  1512.   factory_path = (gchar *) gtk_object_get_data (GTK_OBJECT (item_factory),
  1513.                         "factory_path");
  1514.  
  1515.   if (! help_page ||
  1516.       ! *help_page)
  1517.     help_page = "index.html";
  1518.  
  1519.   if (factory_path && help_page)
  1520.     {
  1521.       gchar *help_string;
  1522.       gchar *at;
  1523.  
  1524.       help_page = g_strdup (help_page);
  1525.  
  1526.       at = strchr (help_page, '@');  /* HACK: locale subdir */
  1527.  
  1528.       if (at)
  1529.     {
  1530.       *at = '\0';
  1531.       help_path   = g_strdup (help_page);
  1532.       help_string = g_strdup (at + 1);
  1533.     }
  1534.       else
  1535.     {
  1536.       help_string = g_strdup_printf ("%s/%s", factory_path, help_page);
  1537.     }
  1538.  
  1539.       gimp_help (help_path, help_string);
  1540.  
  1541.       g_free (help_string);
  1542.       g_free (help_page);
  1543.     }
  1544.   else
  1545.     {
  1546.       gimp_standard_help_func (NULL);
  1547.     }
  1548.  
  1549.   return TRUE;
  1550. }
  1551.  
  1552. /*  set up the callback to catch the "F1" key  */
  1553. static void
  1554. menus_item_realize (GtkWidget *widget,
  1555.             gpointer   data)
  1556. {
  1557.   if (GTK_IS_MENU_SHELL (widget->parent))
  1558.     {
  1559.       if (! gtk_object_get_data (GTK_OBJECT (widget->parent),
  1560.                  "menus_key_press_connected"))
  1561.     {
  1562.       gtk_signal_connect (GTK_OBJECT (widget->parent), "key_press_event",
  1563.                   GTK_SIGNAL_FUNC (menus_item_key_press),
  1564.                   (gpointer) data);
  1565.  
  1566.       gtk_object_set_data (GTK_OBJECT (widget->parent),
  1567.                    "menus_key_press_connected",
  1568.                    (gpointer) TRUE);
  1569.     }
  1570.     }
  1571. }
  1572.  
  1573. static void
  1574. menus_create_item (GtkItemFactory       *item_factory,
  1575.            GimpItemFactoryEntry *entry,
  1576.            gpointer              callback_data,
  1577.            guint                 callback_type)
  1578. {
  1579.   GtkWidget *menu_item;
  1580.  
  1581.   if (!(strstr (entry->entry.path, "tearoff1")))
  1582.     menus_create_branches (item_factory, entry);
  1583.  
  1584.   gtk_item_factory_create_item (item_factory,
  1585.                 (GtkItemFactoryEntry *) entry,
  1586.                 callback_data,
  1587.                 callback_type);
  1588.  
  1589.   menu_item = gtk_item_factory_get_item (item_factory,
  1590.                      ((GtkItemFactoryEntry *) entry)->path);
  1591.  
  1592.   if (menu_item)
  1593.     {
  1594.       gtk_signal_connect_after (GTK_OBJECT (menu_item), "realize",
  1595.                 GTK_SIGNAL_FUNC (menus_item_realize),
  1596.                 (gpointer) item_factory);
  1597.  
  1598.       gtk_object_set_data (GTK_OBJECT (menu_item), "help_page",
  1599.                (gpointer) entry->help_page);
  1600.     }
  1601. }
  1602.  
  1603. static void
  1604. menus_create_items (GtkItemFactory       *item_factory,
  1605.             guint                 n_entries,
  1606.             GimpItemFactoryEntry *entries,
  1607.             gpointer              callback_data,
  1608.             guint                 callback_type)
  1609. {
  1610.   gint i;
  1611.  
  1612.   for (i = 0; i < n_entries; i++)
  1613.     {
  1614.       menus_create_item (item_factory,
  1615.              entries + i,
  1616.              callback_data,
  1617.              callback_type);
  1618.     }
  1619. }
  1620.  
  1621. static void
  1622. menus_init (void)
  1623. {
  1624.   GtkWidget *menu_item;
  1625.   gchar     *filename;
  1626.   gint       i;
  1627.  
  1628.   if (menus_initialized)
  1629.     return;
  1630.  
  1631.   menus_initialized = TRUE;
  1632.  
  1633.   toolbox_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<Toolbox>",
  1634.                       NULL);
  1635.   gtk_object_set_data (GTK_OBJECT (toolbox_factory), "factory_path",
  1636.                (gpointer) "toolbox");
  1637.   gtk_item_factory_set_translate_func (toolbox_factory, menu_translate,
  1638.                        "<Toolbox>", NULL);
  1639.   menus_create_items (toolbox_factory,
  1640.               n_toolbox_entries,
  1641.               toolbox_entries,
  1642.               NULL, 2);
  1643.  
  1644.   menus_init_mru ();
  1645.  
  1646.   image_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Image>", NULL);
  1647.   gtk_object_set_data (GTK_OBJECT (image_factory), "factory_path",
  1648.                (gpointer) "image");
  1649.   gtk_item_factory_set_translate_func (image_factory, menu_translate,
  1650.                        "<Image>", NULL);
  1651.   menus_create_items (image_factory,
  1652.               n_image_entries,
  1653.               image_entries,
  1654.               NULL, 2);
  1655.  
  1656.   load_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Load>", NULL);
  1657.   gtk_object_set_data (GTK_OBJECT (load_factory), "factory_path",
  1658.                (gpointer) "open");
  1659.   gtk_item_factory_set_translate_func (load_factory, menu_translate,
  1660.                        "<Load>", NULL);
  1661.   menus_create_items (load_factory,
  1662.               n_load_entries,
  1663.               load_entries,
  1664.               NULL, 2);
  1665.  
  1666.   save_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Save>", NULL);
  1667.   gtk_object_set_data (GTK_OBJECT (save_factory), "factory_path",
  1668.                (gpointer) "save");
  1669.   gtk_item_factory_set_translate_func (save_factory, menu_translate,
  1670.                        "<Save>", NULL);
  1671.   menus_create_items (save_factory,
  1672.               n_save_entries,
  1673.               save_entries,
  1674.               NULL, 2);
  1675.  
  1676.   layers_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Layers>", NULL);
  1677.   gtk_object_set_data (GTK_OBJECT (layers_factory), "factory_path",
  1678.                (gpointer) "layers");
  1679.   gtk_item_factory_set_translate_func (layers_factory, menu_translate,
  1680.                        "<Layers>", NULL);
  1681.   menus_create_items (layers_factory,
  1682.               n_layers_entries,
  1683.               layers_entries,
  1684.               NULL, 2);
  1685.  
  1686.   channels_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Channels>", NULL);
  1687.   gtk_object_set_data (GTK_OBJECT (channels_factory), "factory_path",
  1688.                (gpointer) "channels");
  1689.   gtk_item_factory_set_translate_func (channels_factory, menu_translate,
  1690.                        "<Channels>", NULL);
  1691.   menus_create_items (channels_factory,
  1692.               n_channels_entries,
  1693.               channels_entries,
  1694.               NULL, 2);
  1695.  
  1696.   paths_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Paths>", NULL);
  1697.   gtk_object_set_data (GTK_OBJECT (paths_factory), "factory_path",
  1698.                (gpointer) "paths");
  1699.   gtk_item_factory_set_translate_func (paths_factory, menu_translate,
  1700.                        "<Paths>", NULL);
  1701.   menus_create_items (paths_factory,
  1702.               n_paths_entries,
  1703.               paths_entries,
  1704.               NULL, 2);
  1705.  
  1706.   for (i = 0; i < num_tools; i++)
  1707.     {
  1708.       menus_tools_create (&tool_info[i]);
  1709.     }
  1710.  
  1711.   /*  reorder <Image>/Image/Colors  */
  1712.   menu_item = gtk_item_factory_get_widget (image_factory,
  1713.                        tool_info[POSTERIZE].menu_path);
  1714.   if (menu_item && menu_item->parent)
  1715.     gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, 3);
  1716.  
  1717.   {
  1718.     static ToolType color_tools[] = { COLOR_BALANCE,
  1719.                       HUE_SATURATION,
  1720.                       BRIGHTNESS_CONTRAST,
  1721.                       THRESHOLD,
  1722.                       LEVELS,
  1723.                       CURVES };
  1724.     static gint n_color_tools = (sizeof (color_tools) /
  1725.                  sizeof (color_tools[0]));
  1726.     GtkWidget *separator;
  1727.     gint i, pos;
  1728.  
  1729.     pos = 1;
  1730.  
  1731.     for (i = 0; i < n_color_tools; i++)
  1732.       {
  1733.     menu_item =
  1734.       gtk_item_factory_get_widget (image_factory,
  1735.                        tool_info[color_tools[i]].menu_path);
  1736.     if (menu_item && menu_item->parent)
  1737.       {
  1738.         gtk_menu_reorder_child (GTK_MENU (menu_item->parent),
  1739.                     menu_item, pos);
  1740.         pos++;
  1741.       }
  1742.       }
  1743.  
  1744.     if (menu_item && menu_item->parent)
  1745.       {
  1746.     separator = gtk_menu_item_new ();
  1747.     gtk_menu_insert (GTK_MENU (menu_item->parent), separator, pos);
  1748.     gtk_widget_show (separator);
  1749.       }
  1750.   }
  1751.  
  1752.   filename = gimp_personal_rc_file ("menurc");
  1753.   gtk_item_factory_parse_rc (filename);
  1754.   g_free (filename);
  1755. }
  1756.  
  1757. #ifdef ENABLE_NLS
  1758.  
  1759. static gchar *
  1760. menu_translate (const gchar *path,
  1761.             gpointer     data)
  1762. {
  1763.   static gchar *menupath = NULL;
  1764.  
  1765.   GtkItemFactory *item_factory = NULL;
  1766.   gchar *retval;
  1767.   gchar *factory;
  1768.   gchar *translation;
  1769.   gchar *domain = NULL;
  1770.   gchar *complete = NULL;
  1771.   gchar *p, *t;
  1772.  
  1773.   factory = (gchar *) data;
  1774.  
  1775.   if (menupath)
  1776.     g_free (menupath);
  1777.  
  1778.   retval = menupath = g_strdup (path);
  1779.  
  1780.   if ((strstr (path, "/tearoff1") != NULL) ||
  1781.       (strstr (path, "/---") != NULL) ||
  1782.       (strstr (path, "/MRU") != NULL))
  1783.     return retval;
  1784.  
  1785.   if (factory)
  1786.     item_factory = gtk_item_factory_from_path (factory);
  1787.   if (item_factory)
  1788.     {
  1789.       domain = gtk_object_get_data (GTK_OBJECT (item_factory), "textdomain");
  1790.       complete = gtk_object_get_data (GTK_OBJECT (item_factory), "complete");
  1791.     }
  1792.   
  1793.   if (domain)   /*  use the plugin textdomain  */
  1794.     {
  1795.       g_free (menupath);
  1796.       menupath = g_strconcat (factory, path, NULL);
  1797.  
  1798.       if (complete)
  1799.     {
  1800.       /*  
  1801.            *  This is a branch, use the complete path for translation, 
  1802.        *  then strip off entries from the end until it matches. 
  1803.        */
  1804.       complete = g_strconcat (factory, complete, NULL);
  1805.       translation = g_strdup (dgettext (domain, complete));
  1806.  
  1807.       while (*complete && *translation && strcmp (complete, menupath))
  1808.         {
  1809.           p = strrchr (complete, '/');
  1810.           t = strrchr (translation, '/');
  1811.           if (p && t)
  1812.         {
  1813.           *p = '\0';
  1814.           *t = '\0';
  1815.         }
  1816.           else
  1817.         break;
  1818.         }
  1819.  
  1820.       g_free (complete);
  1821.     }
  1822.       else
  1823.     {
  1824.       translation = dgettext (domain, menupath);
  1825.     }
  1826.  
  1827.       /* 
  1828.        * Work around a bug in GTK+ prior to 1.2.7 (similar workaround below)
  1829.        */
  1830.       if (strncmp (factory, translation, strlen (factory)) == 0)
  1831.     {
  1832.       retval = translation + strlen (factory);
  1833.       if (complete)
  1834.         {
  1835.           g_free (menupath);
  1836.           menupath = translation;
  1837.         }
  1838.     }
  1839.       else
  1840.     {
  1841.       g_warning ("bad translation for menupath: %s", menupath);
  1842.       retval = menupath + strlen (factory);
  1843.       if (complete)
  1844.         g_free (translation);
  1845.     }
  1846.     }
  1847.   else   /*  use the gimp textdomain  */
  1848.     {
  1849.       if (complete)
  1850.     {
  1851.       /*  
  1852.            *  This is a branch, use the complete path for translation, 
  1853.        *  then strip off entries from the end until it matches. 
  1854.        */
  1855.       complete = g_strdup (complete);
  1856.       translation = g_strdup (gettext (complete));
  1857.       
  1858.       while (*complete && *translation && strcmp (complete, menupath))
  1859.         {
  1860.           p = strrchr (complete, '/');
  1861.           t = strrchr (translation, '/');
  1862.           if (p && t)
  1863.         {
  1864.           *p = '\0';
  1865.           *t = '\0';
  1866.         }
  1867.           else
  1868.         break;
  1869.         }
  1870.       g_free (complete);
  1871.     }
  1872.       else
  1873.     translation = gettext (menupath);
  1874.  
  1875.       if (*translation == '/')
  1876.     {
  1877.       retval = translation;
  1878.       if (complete)
  1879.         {
  1880.           g_free (menupath);
  1881.           menupath = translation;
  1882.         }
  1883.     }
  1884.       else
  1885.     {
  1886.       g_warning ("bad translation for menupath: %s", menupath);
  1887.       if (complete)
  1888.         g_free (translation);
  1889.     }
  1890.     }
  1891.   
  1892.   return retval;
  1893. }
  1894.  
  1895. #endif  /*  ENABLE_NLS  */
  1896.  
  1897. static gint
  1898. tearoff_delete_cb (GtkWidget *widget, 
  1899.            GdkEvent  *event,
  1900.            gpointer   data)
  1901. {
  1902.   /* Unregister if dialog is deleted as well */
  1903.   dialog_unregister (widget);
  1904.  
  1905.   return TRUE; 
  1906. }
  1907.  
  1908. static void   
  1909. tearoff_cmd_callback (GtkWidget *widget,
  1910.               gpointer   callback_data,
  1911.               guint      callback_action)
  1912. {
  1913.   if (GTK_IS_TEAROFF_MENU_ITEM (widget))
  1914.     {
  1915.       GtkTearoffMenuItem *tomi = (GtkTearoffMenuItem *) widget;
  1916.  
  1917.       if (tomi->torn_off)
  1918.     {
  1919.       GtkWidget *top = gtk_widget_get_toplevel (widget);
  1920.  
  1921.       /* This should be a window */
  1922.       if (!GTK_IS_WINDOW (top))
  1923.         {
  1924.           g_message ("tearoff menu not in top level window");
  1925.         }
  1926.       else
  1927.         {
  1928.           dialog_register (top);
  1929.           gtk_signal_connect (GTK_OBJECT (top), "delete_event",
  1930.                   GTK_SIGNAL_FUNC (tearoff_delete_cb),
  1931.                   NULL);
  1932.  
  1933.           gtk_object_set_data (GTK_OBJECT (widget), "tearoff_menu_top",
  1934.                    top);
  1935.  
  1936.           gimp_dialog_set_icon (GTK_WINDOW (top));
  1937.         }
  1938.     }
  1939.       else
  1940.     {
  1941.       GtkWidget *top;
  1942.  
  1943.       top = (GtkWidget *) gtk_object_get_data (GTK_OBJECT (widget),
  1944.                            "tearoff_menu_top");
  1945.  
  1946.       if (!top)
  1947.         g_message ("can't unregister tearoff menu top level window");
  1948.       else
  1949.         dialog_unregister (top);
  1950.     }
  1951.     }
  1952. }
  1953.  
  1954. #ifdef ENABLE_DEBUG_ENTRY
  1955.  
  1956. #include <unistd.h>
  1957.  
  1958. static void
  1959. menus_debug_recurse_menu (GtkWidget *menu,
  1960.               gint       depth,
  1961.               gchar     *path)
  1962. {
  1963.   GtkItemFactory      *item_factory;
  1964.   GtkItemFactoryItem  *item;
  1965.   GtkItemFactoryClass *class;
  1966.   GtkWidget           *menu_item;
  1967.   GList   *list;
  1968.   gchar   *label;
  1969.   gchar   *help_page;
  1970.   gchar   *help_path;
  1971.   gchar   *factory_path;
  1972.   gchar   *hash;
  1973.   gchar   *full_path;
  1974.   gchar   *accel;
  1975.   gchar   *format_str;
  1976.  
  1977.   for (list = GTK_MENU_SHELL (menu)->children; list; list = g_list_next (list))
  1978.     {
  1979.       menu_item = GTK_WIDGET (list->data);
  1980.       
  1981.       if (GTK_IS_LABEL (GTK_BIN (menu_item)->child))
  1982.     {
  1983.       gtk_label_get (GTK_LABEL (GTK_BIN (menu_item)->child), &label);
  1984.       full_path = g_strconcat (path, "/", label, NULL);
  1985.       class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
  1986.       item = g_hash_table_lookup (class->item_ht, full_path);
  1987.       if (item)
  1988.         {
  1989.           accel = gtk_accelerator_name (item->accelerator_key, 
  1990.                         item->accelerator_mods);
  1991.         }
  1992.       else
  1993.         {
  1994.           accel = NULL;
  1995.         }
  1996.  
  1997.       item_factory = gtk_item_factory_from_path (path);
  1998.       if (item_factory)
  1999.         {
  2000.           factory_path = (gchar *) gtk_object_get_data (GTK_OBJECT (item_factory),
  2001.                                 "factory_path");
  2002.           help_page = g_strconcat (factory_path ? factory_path : "",
  2003.                        factory_path ? G_DIR_SEPARATOR_S : "",
  2004.                        (gchar *) gtk_object_get_data (GTK_OBJECT (menu_item), 
  2005.                                       "help_page"),
  2006.                        NULL);
  2007.         }
  2008.       else
  2009.         {
  2010.           help_page = g_strdup ((gchar *) gtk_object_get_data (GTK_OBJECT (menu_item), 
  2011.                                    "help_page"));
  2012.         } 
  2013.  
  2014.       if (help_page)
  2015.         {
  2016.           help_path = g_strconcat (gimp_data_directory (), G_DIR_SEPARATOR_S, 
  2017.                        "help", G_DIR_SEPARATOR_S, 
  2018.                        "C", G_DIR_SEPARATOR_S,
  2019.                        help_page, NULL);
  2020.  
  2021.           if ((hash = strchr (help_path, '#')) != NULL)
  2022.         *hash = '\0';
  2023.  
  2024.           if (access (help_path, R_OK))
  2025.         {
  2026.           g_free (help_path);
  2027.           help_path = g_strconcat ("! ", help_page, NULL);
  2028.           g_free (help_page);
  2029.           help_page = help_path;
  2030.         }
  2031.           else
  2032.         {
  2033.           g_free (help_path);
  2034.         }
  2035.         }
  2036.  
  2037.       format_str = g_strdup_printf ("%%%ds%%%ds %%-20s %%s\n", 
  2038.                     depth * 2, depth * 2 - 40);
  2039.       g_print (format_str, 
  2040.            "", label, accel ? accel : "", help_page ? help_page : "");
  2041.       g_free (format_str);
  2042.       g_free (help_page);
  2043.  
  2044.       if (GTK_MENU_ITEM (menu_item)->submenu)
  2045.         menus_debug_recurse_menu (GTK_MENU_ITEM (menu_item)->submenu, 
  2046.                       depth + 1, full_path);
  2047.  
  2048.       g_free (full_path);
  2049.     }                  
  2050.     }
  2051. }
  2052.  
  2053. static void
  2054. menus_debug_cmd_callback (GtkWidget *widget,
  2055.               gpointer   callback_data,
  2056.               guint      callback_action)
  2057. {
  2058.   gint  n_factories = 7;
  2059.   GtkItemFactory       *factories[7];
  2060.   GimpItemFactoryEntry *entries[7];
  2061.  
  2062.   GtkWidget *menu_item;
  2063.   gint       i;
  2064.  
  2065.   factories[0] = toolbox_factory;
  2066.   factories[1] = image_factory;
  2067.   factories[2] = layers_factory;
  2068.   factories[3] = channels_factory;
  2069.   factories[4] = paths_factory;
  2070.   factories[5] = load_factory;
  2071.   factories[6] = save_factory;
  2072.  
  2073.   entries[0] = toolbox_entries;
  2074.   entries[1] = image_entries;
  2075.   entries[2] = layers_entries;
  2076.   entries[3] = channels_entries;
  2077.   entries[4] = paths_entries;
  2078.   entries[5] = load_entries;
  2079.   entries[6] = save_entries;
  2080.   
  2081.   /*  toolbox needs special treatment  */
  2082.   g_print ("%s\n", factories[0]->path);
  2083.  
  2084.   menu_item = gtk_item_factory_get_item (factories[0], "/File");
  2085.   if (menu_item && menu_item->parent && GTK_IS_MENU_BAR (menu_item->parent))
  2086.     menus_debug_recurse_menu (menu_item->parent, 1, factories[0]->path);
  2087.  
  2088.   g_print ("\n");
  2089.  
  2090.   for (i = 1; i < n_factories; i++)
  2091.     {
  2092.       g_print ("%s\n", factories[i]->path);
  2093.  
  2094.       menu_item = gtk_item_factory_get_item (factories[i], entries[i][0].entry.path);
  2095.       if (menu_item && menu_item->parent && GTK_IS_MENU (menu_item->parent))
  2096.     menus_debug_recurse_menu (menu_item->parent, 1, factories[i]->path);
  2097.  
  2098.       g_print ("\n");
  2099.     }
  2100. }
  2101. #endif  /*  ENABLE_DEBUG_ENTRY  */
  2102.