diff --git a/app/display/gimpimagewindow.c b/app/display/gimpimagewindow.c index b44cce9be7..14ab14d5f4 100644 --- a/app/display/gimpimagewindow.c +++ b/app/display/gimpimagewindow.c @@ -50,6 +50,7 @@ #include "widgets/gimpdockcolumns.h" #include "widgets/gimpdockcontainer.h" #include "widgets/gimphelp-ids.h" +#include "widgets/gimpmenu.h" #include "widgets/gimpmenufactory.h" #include "widgets/gimpsessioninfo.h" #include "widgets/gimpsessioninfo-aux.h" @@ -116,6 +117,7 @@ struct _GimpImageWindowPrivate GimpDisplayShell *active_shell; GtkWidget *main_vbox; + GtkWidget *new_menubar; GtkWidget *menubar; GtkWidget *hbox; GtkWidget *left_hpane; @@ -347,6 +349,9 @@ gimp_image_window_constructed (GObject *object) GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window); GimpMenuFactory *menu_factory; GimpGuiConfig *config; + GtkBuilder *builder; + GMenuModel *model; + gchar *filename; G_OBJECT_CLASS (parent_class)->constructed (object); @@ -384,33 +389,71 @@ gimp_image_window_constructed (GObject *object) gtk_widget_show (private->main_vbox); /* Create the menubar */ -#ifndef GDK_WINDOWING_QUARTZ + filename = g_build_filename (gimp_data_directory (), "menus", + "image-menu.ui", NULL); + + builder = gtk_builder_new_from_file (filename); + model = G_MENU_MODEL (gtk_builder_get_object (builder, "/image-menubar")); + +#ifdef GDK_WINDOWING_QUARTZ + /* macOS has its native menubar system, and this should support it. It means + * that we won't have tooltips on macOS menu though. + * TODO: Since the .ui file has no title/labels, I should edit the model to + * extract titles from actions. + */ + gtk_application_set_menubar (private->gimp->app, G_MENU_MODEL (model)); +#else + /* TODO: this is the old menubar system. It should go away soon. */ private->menubar = gimp_ui_manager_get_widget (private->menubar_manager, "/image-menubar"); + + gtk_box_pack_start (GTK_BOX (private->main_vbox), + private->menubar, FALSE, FALSE, 0); + + /* make sure we can activate accels even if the menubar is invisible + * (see https://bugzilla.gnome.org/show_bug.cgi?id=137151) + */ + g_signal_connect (private->menubar, "can-activate-accel", + G_CALLBACK (gtk_true), + NULL); + + /* active display callback */ + g_signal_connect (private->menubar, "button-press-event", + G_CALLBACK (gimp_image_window_shell_events), + window); + g_signal_connect (private->menubar, "button-release-event", + G_CALLBACK (gimp_image_window_shell_events), + window); + g_signal_connect (private->menubar, "key-press-event", + G_CALLBACK (gimp_image_window_shell_events), + window); + + private->new_menubar = gimp_menu_new (model, private->gimp); + + gtk_box_pack_start (GTK_BOX (private->main_vbox), + private->new_menubar, FALSE, FALSE, 0); + + /* make sure we can activate accels even if the menubar is invisible + * (see https://bugzilla.gnome.org/show_bug.cgi?id=137151) + */ + g_signal_connect (private->new_menubar, "can-activate-accel", + G_CALLBACK (gtk_true), + NULL); + + /* active display callback */ + g_signal_connect (private->new_menubar, "button-press-event", + G_CALLBACK (gimp_image_window_shell_events), + window); + g_signal_connect (private->new_menubar, "button-release-event", + G_CALLBACK (gimp_image_window_shell_events), + window); + g_signal_connect (private->new_menubar, "key-press-event", + G_CALLBACK (gimp_image_window_shell_events), + window); #endif /* !GDK_WINDOWING_QUARTZ */ - if (private->menubar) - { - gtk_box_pack_start (GTK_BOX (private->main_vbox), - private->menubar, FALSE, FALSE, 0); - /* make sure we can activate accels even if the menubar is invisible - * (see https://bugzilla.gnome.org/show_bug.cgi?id=137151) - */ - g_signal_connect (private->menubar, "can-activate-accel", - G_CALLBACK (gtk_true), - NULL); - - /* active display callback */ - g_signal_connect (private->menubar, "button-press-event", - G_CALLBACK (gimp_image_window_shell_events), - window); - g_signal_connect (private->menubar, "button-release-event", - G_CALLBACK (gimp_image_window_shell_events), - window); - g_signal_connect (private->menubar, "key-press-event", - G_CALLBACK (gimp_image_window_shell_events), - window); - } + g_object_unref (builder); + g_free (filename); /* Create the hbox that contains docks and images */ private->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); @@ -1347,6 +1390,8 @@ gimp_image_window_set_show_menubar (GimpImageWindow *window, if (private->menubar) gtk_widget_set_visible (private->menubar, show); + if (private->new_menubar) + gtk_widget_set_visible (private->new_menubar, show); } gboolean diff --git a/app/widgets/Makefile.am b/app/widgets/Makefile.am index 9b7d9a758b..8c759d3762 100644 --- a/app/widgets/Makefile.am +++ b/app/widgets/Makefile.am @@ -272,6 +272,8 @@ libappwidgets_a_sources = \ gimplayermodecombobox.h \ gimplayertreeview.c \ gimplayertreeview.h \ + gimpmenu.c \ + gimpmenu.h \ gimpmenudock.c \ gimpmenudock.h \ gimpmenufactory.c \ diff --git a/app/widgets/gimpmenu.c b/app/widgets/gimpmenu.c new file mode 100644 index 0000000000..2528084945 --- /dev/null +++ b/app/widgets/gimpmenu.c @@ -0,0 +1,308 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpmenu.c + * Copyright (C) 2022 Jehan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include +#include + +#include "libgimpbase/gimpbase.h" + +#include "widgets-types.h" + +#include "core/gimp.h" + +#include "gimpaction.h" +#include "gimpmenu.h" +#include "gimpradioaction.h" +#include "gimptoggleaction.h" + + +/** + * GimpMenu: + * + * Our own menu widget. + * + * We cannot use the simpler gtk_menu_new_from_model() because it lacks + * tooltip support and unfortunately GTK does not plan to implement this: + * https://gitlab.gnome.org/GNOME/gtk/-/issues/785 + * This is why we need to implement our own GimpMenu subclass. + */ + +enum +{ + PROP_0, + PROP_GIMP, + PROP_MODEL +}; + + +struct _GimpMenuPrivate +{ + Gimp *gimp; + GMenuModel *model; +}; + + +/* local function prototypes */ + +static void gimp_menu_dispose (GObject *object); +static void gimp_menu_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_menu_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static void gimp_menu_update (GimpMenu *menu, + GtkContainer *container, + GMenuModel *model); +static void gimp_menu_radio_item_toggled (GtkWidget *item, + GAction *action); + + +G_DEFINE_TYPE_WITH_PRIVATE (GimpMenu, gimp_menu, GTK_TYPE_MENU_BAR) + +#define parent_class gimp_menu_parent_class + + +/* private functions */ + +static void +gimp_menu_class_init (GimpMenuClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gimp_menu_dispose; + object_class->get_property = gimp_menu_get_property; + object_class->set_property = gimp_menu_set_property; + + g_object_class_install_property (object_class, PROP_GIMP, + g_param_spec_object ("gimp", + NULL, NULL, + GIMP_TYPE_GIMP, + GIMP_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_MODEL, + g_param_spec_object ("model", + NULL, NULL, + G_TYPE_MENU_MODEL, + GIMP_PARAM_READWRITE)); +} + +static void +gimp_menu_init (GimpMenu *menu) +{ + menu->priv = gimp_menu_get_instance_private (menu); +} + +static void +gimp_menu_dispose (GObject *object) +{ + GimpMenu *menu = GIMP_MENU (object); + + g_clear_object (&menu->priv->model); + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gimp_menu_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpMenu *menu = GIMP_MENU (object); + + switch (property_id) + { + case PROP_MODEL: + menu->priv->model = g_value_dup_object (value); + gimp_menu_update (menu, NULL, NULL); + break; + case PROP_GIMP: + menu->priv->gimp = g_value_get_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_menu_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpMenu *menu = GIMP_MENU (object); + + switch (property_id) + { + case PROP_MODEL: + g_value_set_object (value, menu->priv->model); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +/* Public functions */ + +GtkWidget * +gimp_menu_new (GMenuModel *model, + Gimp *gimp) +{ + g_return_val_if_fail (GIMP_IS_GIMP (gimp) && G_IS_MENU_MODEL (model), NULL); + + return g_object_new (GIMP_TYPE_MENU, + "model", model, + "gimp", gimp, + NULL); +} + + +/* Private functions */ + +static void +gimp_menu_update (GimpMenu *menu, + GtkContainer *container, + GMenuModel *model) +{ + static GtkRadioMenuItem *group = NULL; + gint n_items; + + if (container == NULL) + { + container = GTK_CONTAINER (menu); + model = menu->priv->model; + } + + n_items = g_menu_model_get_n_items (model); + for (gint i = 0; i < n_items; i++) + { + GMenuModel *subsection; + GMenuModel *submenu; + GtkWidget *item; + gchar *label = NULL; + gchar *action_name = NULL; + + subsection = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION); + submenu = g_menu_model_get_item_link (model, i, G_MENU_LINK_SUBMENU); + g_menu_model_get_item_attribute (model, i, G_MENU_ATTRIBUTE_LABEL, "s", &label); + g_menu_model_get_item_attribute (model, i, G_MENU_ATTRIBUTE_ACTION, "s", &action_name); + + if (subsection != NULL) + { + group = NULL; + + item = gtk_separator_menu_item_new (); + gtk_container_add (container, item); + gtk_widget_show (item); + + gimp_menu_update (menu, container, subsection); + + item = gtk_separator_menu_item_new (); + gtk_container_add (container, item); + gtk_widget_show (item); + } + else if (submenu != NULL) + { + GtkWidget *subcontainer; + + group = NULL; + + item = gtk_menu_item_new_with_mnemonic (label); + gtk_container_add (container, item); + gtk_widget_show (item); + + subcontainer = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), subcontainer); + gtk_widget_show (subcontainer); + + gimp_menu_update (menu, GTK_CONTAINER (subcontainer), submenu); + } + else + { + GAction *action; + const gchar *action_label; + + g_return_if_fail (g_str_has_prefix (action_name, "app.")); + action = g_action_map_lookup_action (G_ACTION_MAP (menu->priv->gimp->app), action_name + 4); + g_return_if_fail (GIMP_IS_ACTION (action)); + + action_label = gimp_action_get_label (GIMP_ACTION (action)); + g_return_if_fail (action_label != NULL); + + if (GIMP_IS_TOGGLE_ACTION (action)) + { + item = gtk_check_menu_item_new_with_mnemonic (action_label); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + gimp_toggle_action_get_active (GIMP_TOGGLE_ACTION (action))); + group = NULL; + } + else if (GIMP_IS_RADIO_ACTION (action)) + { + item = gtk_radio_menu_item_new_with_mnemonic_from_widget (group, action_label); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + /* TODO: see comment in gimp_menu_radio_item_toggled(). */ + gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))); + group = GTK_RADIO_MENU_ITEM (item); + g_signal_connect (item, "toggled", + G_CALLBACK (gimp_menu_radio_item_toggled), + action); + } + else + { + item = gtk_menu_item_new_with_mnemonic (action_label); + group = NULL; + } + + gtk_actionable_set_action_name (GTK_ACTIONABLE (item), action_name); + + if (gimp_action_get_tooltip (GIMP_ACTION (action))) + gtk_widget_set_tooltip_text (item, + gimp_action_get_tooltip (GIMP_ACTION (action))); + + gtk_container_add (container, item); + gtk_widget_show (item); + } + g_free (label); + g_free (action_name); + } +} + +static void +gimp_menu_radio_item_toggled (GtkWidget *item, + GAction *action) +{ + gboolean active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item)); + + /* TODO: when we remove GtkAction dependency, GimpRadioAction should become a + * child of GimpToggleAction, and therefore, we'll be able to use + * gimp_toggle_action_set_active(). + */ + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active); +} diff --git a/app/widgets/gimpmenu.h b/app/widgets/gimpmenu.h new file mode 100644 index 0000000000..fdd246a84e --- /dev/null +++ b/app/widgets/gimpmenu.h @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpmenu.h + * Copyright (C) 2022 Jehan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __GIMP_MENU_H__ +#define __GIMP_MENU_H__ + + +#define GIMP_TYPE_MENU (gimp_menu_get_type ()) +#define GIMP_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_MENU, GimpMenu)) +#define GIMP_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_MENU, GimpMenuClass)) +#define GIMP_IS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GIMP_TYPE_MENU)) +#define GIMP_IS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_MENU)) +#define GIMP_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_MENU, GimpMenuClass)) + + +typedef struct _GimpMenuPrivate GimpMenuPrivate; +typedef struct _GimpMenuClass GimpMenuClass; + +struct _GimpMenu +{ + GtkMenuBar parent_instance; + + GimpMenuPrivate *priv; +}; + +struct _GimpMenuClass +{ + GtkMenuBarClass parent_class; +}; + + +GType gimp_menu_get_type (void) G_GNUC_CONST; + +GtkWidget * gimp_menu_new (GMenuModel *model, + Gimp *gimp); + + +#endif /* __GIMP_MENU_H__ */ diff --git a/app/widgets/meson.build b/app/widgets/meson.build index b8071376d2..1717069d65 100644 --- a/app/widgets/meson.build +++ b/app/widgets/meson.build @@ -137,6 +137,7 @@ libappwidgets_sources = [ 'gimplayermodebox.c', 'gimplayermodecombobox.c', 'gimplayertreeview.c', + 'gimpmenu.c', 'gimpmenudock.c', 'gimpmenufactory.c', 'gimpmessagebox.c', diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h index 18e28185da..5f4ede2d67 100644 --- a/app/widgets/widgets-types.h +++ b/app/widgets/widgets-types.h @@ -210,6 +210,7 @@ typedef struct _GimpLanguageStore GimpLanguageStore; typedef struct _GimpLayerModeBox GimpLayerModeBox; typedef struct _GimpLayerModeComboBox GimpLayerModeComboBox; typedef struct _GimpMessageBox GimpMessageBox; +typedef struct _GimpMenu GimpMenu; typedef struct _GimpMeter GimpMeter; typedef struct _GimpModifiersEditor GimpModifiersEditor; typedef struct _GimpOverlayBox GimpOverlayBox; diff --git a/menus/image-menu.ui b/menus/image-menu.ui new file mode 100644 index 0000000000..d585856338 --- /dev/null +++ b/menus/image-menu.ui @@ -0,0 +1,872 @@ + + + + + + + _File +
+ app.image-new + + Crea_te + app.edit-paste-as-new-image + + + app.file-open + app.file-open-as-layers + app.file-open-location + + Open _Recent +
+ +
+ app.dialogs-document-history +
+ + + + _Debug + app.debug-gtk-inspector +
+ app.debug-mem-profile + app.debug-benchmark-projection + app.debug-show-image-graph +
+
+ app.debug-dump-items + app.debug-dump-managers + app.debug-dump-keyboard-shortcuts + app.debug-dump-attached-data +
+
+
+
+ app.file-save + app.file-save-as + app.file-save-a-copy + app.file-revert +
+
+ + app.file-overwrite + app.file-export + app.file-export-as + app.file-create-template +
+ +
+ app.file-copy-location + app.file-show-in-file-manager +
+
+ app.view-close + app.file-close-all + app.file-quit +
+
+ + + + + _Edit +
+ app.edit-undo + app.edit-redo + app.dialogs-undo-history +
+
+ app.edit-cut + app.edit-copy + app.edit-copy-visible + app.edit-paste + app.edit-paste-in-place + + Paste _as + app.edit-paste-merged + app.edit-paste-merged-in-place + app.edit-paste-into + app.edit-paste-into-in-place + app.edit-paste-as-new-image-short + + + _Buffer + app.edit-named-cut + app.edit-named-copy + app.edit-named-copy-visible + app.edit-named-paste + +
+
+ app.edit-clear + app.edit-fill-fg + app.edit-fill-bg + app.edit-fill-pattern + app.select-fill + app.vectors-fill + app.select-stroke + app.vectors-stroke +
+
+ app.dialogs-preferences + app.dialogs-extensions + app.dialogs-input-devices + app.dialogs-keyboard-shortcuts + app.dialogs-module-dialog + +
+
+ + + + + _Select +
+ app.select-all + app.select-none + app.select-invert + app.select-float + app.tools-by-color-select-short + app.vectors-selection-from-vectors + app.dialogs-selection-editor + app.select-feather + app.select-sharpen + app.select-shrink + app.select-grow + app.select-border + app.select-flood + +
+
+ app.quick-mask-toggle + app.select-save + app.vectors-selection-to-vectors-short +
+
+ + + + + _View + app.view-new + app.view-show-all + app.view-dot-for-dot + + + _Zoom +
+ app.view-zoom-revert + app.view-zoom-out + app.view-zoom-in + app.view-zoom-fit-in + app.view-zoom-fill + app.view-zoom-selection +
+
+ app.view-zoom-16-1 + app.view-zoom-8-1 + app.view-zoom-4-1 + app.view-zoom-2-1 + app.view-zoom-1-1 + app.view-zoom-1-2 + app.view-zoom-1-4 + app.view-zoom-1-8 + app.view-zoom-1-16 +
+
+ app.view-zoom-other +
+
+ + + _Flip & Rotate +
+ app.view-reset +
+
+ app.view-flip-horizontally + app.view-flip-vertically +
+
+ app.view-rotate-15 + app.view-rotate-345 + app.view-rotate-90 + app.view-rotate-270 + app.view-rotate-180 +
+
+ app.view-rotate-other +
+
+ app.view-scroll-center +
+ app.view-shrink-wrap + app.view-fullscreen + + Move to Screen + app.view-open-display + + +
+
+ app.view-navigation-window + app.view-display-filters + + _Color Management +
+ app.view-color-management-enable + app.view-color-management-softproof +
+
+ + Display _Rendering Intent + app.view-display-intent-perceptual + app.view-display-intent-relative-colorimetric + app.view-display-intent-saturation + app.view-display-intent-absolute-colorimetric + + app.view-display-black-point-compensation +
+
+ app.view-softproof-gamut-check + app.view-color-management-reset +
+
+
+
+ app.view-show-selection + app.view-show-layer-boundary + app.view-show-canvas-boundary + app.view-show-guides + app.view-show-grid + app.view-show-sample-points +
+
+ app.view-snap-to-guides + app.view-snap-to-grid + app.view-snap-to-canvas + app.view-snap-to-vectors +
+
+ + _Padding color +
+ app.view-padding-color-theme + app.view-padding-color-light-check + app.view-padding-color-dark-check + app.view-padding-color-custom +
+
+ app.view-padding-color-in-show-all +
+
+ app.view-padding-color-prefs +
+
+ app.view-show-menubar + app.view-show-rulers + app.view-show-scrollbars + app.view-show-statusbar +
+
+ + + + + _Image +
+ app.image-duplicate +
+
+ + _Mode + app.image-convert-rgb + app.image-convert-grayscale + app.image-convert-indexed + + + _Encoding +
+ app.image-convert-u8 + app.image-convert-u16 + app.image-convert-u32 + app.image-convert-half + app.image-convert-float + + app.image-convert-double +
+
+ app.image-convert-linear + app.image-convert-non-linear + + app.image-convert-perceptual +
+
+ + Color Ma_nagement +
+ app.image-color-profile-use-srgb +
+
+ app.image-color-profile-assign + app.image-color-profile-convert + app.image-color-profile-discard +
+
+ app.image-color-profile-save +
+
+ app.image-softproof-profile +
+
+ + Soft-Proofing Re_ndering Intent + app.image-softproof-intent-perceptual + app.image-softproof-intent-relative-colorimetric + app.image-softproof-intent-saturation + app.image-softproof-intent-absolute-colorimetric + + app.image-softproof-black-point-compensation +
+
+
+
+ + _Transform +
+ app.image-flip-horizontal + app.image-flip-vertical +
+
+ app.image-rotate-90 + app.image-rotate-270 + app.image-rotate-180 + app.tools-rotate-image-arbitrary +
+
+ app.image-resize + app.image-resize-to-layers + app.image-resize-to-selection + app.image-print-size + app.image-scale +
+
+ app.image-crop-to-selection + app.image-crop-to-content +
+ +
+ app.image-merge-layers + app.image-flatten + +
+
+ + _Guides + + + app.image-configure-grid +
+
+ app.image-properties + +
+
+ + + + + _Layer +
+ app.layers-new + app.layers-new-from-visible + app.layers-new-group + app.layers-duplicate + + app.layers-anchor + app.layers-merge-down + + app.layers-merge-group + app.layers-delete +
+
+ + app.layers-text-discard + app.layers-text-to-vectors + app.layers-text-along-vectors +
+
+ + Stac_k +
+ app.layers-select-previous + app.layers-select-next + app.layers-select-top + app.layers-select-bottom +
+
+ app.layers-raise + app.layers-lower + app.layers-raise-to-top + app.layers-lower-to-bottom +
+ +
+ + _Mask +
+ app.layers-mask-add + app.layers-mask-apply + app.layers-mask-delete +
+
+ app.layers-mask-show + app.layers-mask-edit + app.layers-mask-disable +
+
+ app.layers-mask-selection-replace + app.layers-mask-selection-add + app.layers-mask-selection-subtract + app.layers-mask-selection-intersect +
+
+ + Tr_ansparency +
+ app.layers-alpha-add + app.layers-alpha-remove + app.filters-color-to-alpha + app.filters-semi-flatten + app.filters-threshold-alpha +
+
+ app.layers-alpha-selection-replace + app.layers-alpha-selection-add + app.layers-alpha-selection-subtract + app.layers-alpha-selection-intersect +
+
+ + _Transform +
+ app.drawable-flip-horizontal + app.drawable-flip-vertical +
+
+ app.drawable-rotate-90 + app.drawable-rotate-270 + app.drawable-rotate-180 + app.tools-rotate-arbitrary +
+ app.filters-offset +
+
+
+ app.layers-resize + app.layers-resize-to-image + app.layers-scale + app.layers-crop-to-selection + app.layers-crop-to-content +
+
+ + + + + _Colors +
+ app.filters-color-balance + app.filters-color-temperature + app.filters-hue-chroma + app.filters-hue-saturation + app.filters-saturation + app.filters-exposure + app.filters-shadows-highlights + app.filters-brightness-contrast + app.filters-levels + app.filters-curves +
+
+ app.filters-invert-perceptual + app.filters-invert-linear + app.filters-invert-value +
+
+ + _Auto + app.drawable-equalize + app.drawable-levels-stretch + app.filters-stretch-contrast + app.filters-stretch-contrast-hsv + app.filters-color-enhance + + + C_omponents + app.filters-channel-mixer + app.filters-component-extract + app.filters-mono-mixer + + + + D_esaturate + app.filters-c2g + app.filters-desaturate + app.filters-mono-mixer + app.filters-sepia + + + _Map + +
+ app.filters-alien-map + app.filters-color-exchange + app.filters-color-rotate +
+ +
+ + _Tone Mapping + app.filters-fattal-2002 + app.filters-mantiuk-2006 + app.filters-reinhard-2005 + app.filters-stress + + + + I_nfo + app.dialogs-histogram + + +
+
+ app.filters-threshold + app.filters-colorize + app.filters-posterize + app.filters-color-to-alpha + app.filters-dither + app.filters-rgb-clip + +
+
+ + + + + _Tools +
+ + _Selection Tools + app.tools-rect-select + app.tools-ellipse-select + app.tools-free-select + app.tools-foreground-select + app.tools-fuzzy-select + app.tools-by-color-select + app.tools-iscissors + + + + _Paint Tools + app.tools-bucket-fill + app.tools-gradient + app.tools-pencil + app.tools-paintbrush + app.tools-eraser + app.tools-airbrush + app.tools-ink + app.tools-mypaint-brush + app.tools-clone + app.tools-heal + app.tools-perspective-clone + app.tools-convolve + app.tools-smudge + app.tools-dodge-burn + + + _Transform Tools + app.tools-align + app.tools-move + app.tools-crop + app.tools-rotate + app.tools-scale + app.tools-shear + app.tools-perspective + app.tools-transform-3d + app.tools-unified-transform + app.tools-handle-transform + app.tools-flip + app.tools-cage + app.tools-warp + + + app.tools-vector + app.tools-text +
+
+ app.tools-color-picker + app.tools-measure + app.tools-zoom +
+
+ app.dialogs-toolbox + app.context-colors-default + app.context-colors-swap +
+
+ + + + + Filte_rs +
+ app.filters-repeat + app.filters-reshow + + Recently Used + + + app.plug-in-reset-all +
+
+ + _Blur + app.filters-focus-blur + app.filters-gaussian-blur + app.filters-lens-blur + app.filters-mean-curvature-blur + app.filters-median-blur + app.filters-pixelize + app.filters-gaussian-blur-selective + app.filters-variable-blur + app.filters-motion-blur-circular + app.filters-motion-blur-linear + app.filters-motion-blur-zoom + + + + En_hance + app.filters-antialias + app.filters-deinterlace + app.filters-high-pass + app.filters-noise-reduction + app.filters-red-eye-removal + app.filters-snn-mean + app.filters-unsharp-mask + + + + _Distorts + app.filters-apply-lens + app.filters-emboss + app.filters-engrave + app.filters-lens-distortion + app.filters-kaleidoscope + app.filters-mosaic + app.filters-newsprint + app.filters-polar-coordinates + app.filters-ripple + app.filters-shift + app.filters-spherize + app.filters-value-propagate + app.filters-video-degradation + app.filters-waves + app.filters-whirl-pinch + app.filters-wind + + + + _Light and Shadow +
+ app.filters-bloom + app.filters-supernova + app.filters-lens-flare + +
+
+ app.filters-dropshadow + app.filters-long-shadow + app.filters-vignette + +
+
+ + _Noise + app.filters-noise-cie-lch + app.filters-noise-hsv + app.filters-noise-hurl + app.filters-noise-pick + app.filters-noise-rgb + app.filters-noise-slur + app.filters-noise-spread + + + Edge-De_tect + app.filters-difference-of-gaussians + app.filters-edge + app.filters-edge-laplace + app.filters-edge-neon + app.filters-edge-sobel + app.filters-image-gradient + + + _Generic + app.filters-convolution-matrix + app.filters-distance-map + app.tools-gegl + app.filters-gegl-graph + app.filters-normal-map + app.filters-dilate + app.filters-erode + + + C_ombine + + + + _Artistic + app.filters-apply-canvas + app.filters-cartoon + app.filters-cubism + app.filters-tile-glass + app.filters-oilify + app.filters-photocopy + app.filters-slic + app.filters-softglow + app.filters-waterpixels + + + + _Decor + + + + _Map + app.filters-bump-map + app.filters-displace + app.filters-fractal-trace + app.filters-illusion + app.filters-little-planet + app.filters-panorama-projection + app.filters-recursive-transform + app.filters-tile-paper + app.filters-tile-seamless + + + + _Render + + + N_oise + app.filters-noise-cell + app.filters-noise-perlin + app.filters-plasma + app.filters-noise-simplex + app.filters-noise-solid + + + + _Pattern + app.filters-bayer-matrix + app.filters-checkerboard + app.filters-diffraction-patterns + app.filters-grid + app.filters-linear-sinusoid + app.filters-maze + app.filters-sinus + app.filters-spiral + + + + + + _Web + app.filters-semi-flatten + + + +
+
+ + + _Windows +
+ + _Recently Closed Dialogs + + + + _Dockable Dialogs +
+ app.dialogs-tool-options + app.dialogs-device-status +
+
+ app.dialogs-layers + app.dialogs-channels + app.dialogs-vectors + app.dialogs-indexed-palette + app.dialogs-histogram + app.dialogs-selection-editor + app.dialogs-navigation + app.dialogs-undo-history + app.dialogs-cursor + app.dialogs-sample-points + app.dialogs-symmetry +
+
+ app.dialogs-colors + app.dialogs-brushes + app.dialogs-dynamics + app.dialogs-mypaint-brushes + app.dialogs-patterns + app.dialogs-gradients + app.dialogs-palettes + app.dialogs-fonts + app.dialogs-tool-presets + app.dialogs-buffers +
+
+ app.dialogs-images + app.dialogs-document-history + app.dialogs-templates + app.dialogs-error-console + app.dialogs-dashboard +
+
+ app.dialogs-toolbox +
+ +
+ app.windows-hide-docks + app.windows-show-tabs + + _Tabs Position + app.windows-tabs-position-top + app.windows-tabs-position-bottom + app.windows-tabs-position-left + app.windows-tabs-position-right + + app.windows-use-single-window-mode +
+
+ + + _Help +
+ app.help-help + app.help-context-help + app.dialogs-tips + app.dialogs-about + app.dialogs-welcome +
+
+ app.dialogs-action-search +
+ +
+
+
diff --git a/menus/meson.build b/menus/meson.build index e7147a2d33..80b839dea0 100644 --- a/menus/meson.build +++ b/menus/meson.build @@ -39,6 +39,14 @@ install_data(menus_files, install_dir: menus_dir, ) +ui_menus_files = files( + 'image-menu.ui', +) + +install_data(ui_menus_files, + install_dir: menus_dir, +) + unstable_menus_args = stable ? [] : [ '--stringparam', 'unstable-menus', 'yes' ] menus_built_files = [] @@ -74,4 +82,20 @@ if xmllint.found() build_by_default: true, install: false ) + + # XXX: no DTD validation as GtkBuilder UI format does not have a DTD (as far as + # we could find). + custom_target('validate_ui_menus', + command: [ + xmllint, + '--output', '@OUTPUT@', + '--path', meson.current_source_dir(), + ui_menus_files, menus_built_files + ], + # The output file is only useful as a flag file, so that the command + # knows if it has been run already. + output: [ 'validate_ui_menus-output.xml' ], + build_by_default: true, + install: false + ) endif