[gimp] app, menus: add "show canvas boundary" display option



commit e2f31852fbe75ad4c6a0c5d03025a157d872c0c1
Author: Ell <ell_se yahoo com>
Date:   Wed Sep 4 16:33:09 2019 +0300

    app, menus: add "show canvas boundary" display option
    
    Add a "show canvas boundary" display option, and a corresponding
    "View" menu item and default-apperance preferences option.  When
    enabled (the default), the canvas boundary is shown as an orange/
    black dashed line in "show all" mode.

 app/actions/view-actions.c                |  47 +++---
 app/actions/view-commands.c               |  17 ++
 app/actions/view-commands.h               |   3 +
 app/config/gimpdisplayoptions.c           |  28 ++++
 app/config/gimpdisplayoptions.h           |   1 +
 app/config/gimprc-blurbs.h                |   4 +
 app/dialogs/preferences-dialog.c          |   3 +
 app/display/Makefile.am                   |   2 +
 app/display/gimpcanvas-style.c            |  26 +++
 app/display/gimpcanvas-style.h            |   4 +
 app/display/gimpcanvascanvasboundary.c    | 270 ++++++++++++++++++++++++++++++
 app/display/gimpcanvascanvasboundary.h    |  58 +++++++
 app/display/gimpdisplayshell-appearance.c |  42 +++++
 app/display/gimpdisplayshell-appearance.h |   5 +
 app/display/gimpdisplayshell-handlers.c   |   7 +
 app/display/gimpdisplayshell-items.c      |  23 ++-
 app/display/gimpdisplayshell.c            |   6 +
 app/display/gimpdisplayshell.h            |   1 +
 app/widgets/gimphelp-ids.h                |   1 +
 menus/image-menu.xml.in                   |   1 +
 20 files changed, 522 insertions(+), 27 deletions(-)
---
diff --git a/app/actions/view-actions.c b/app/actions/view-actions.c
index 852e2df542..e34440d4a2 100644
--- a/app/actions/view-actions.c
+++ b/app/actions/view-actions.c
@@ -237,6 +237,13 @@ static const GimpToggleActionEntry view_toggle_actions[] =
     TRUE,
     GIMP_HELP_VIEW_SHOW_LAYER_BOUNDARY },
 
+  { "view-show-canvas-boundary", NULL,
+    NC_("view-action", "Show Canvas Bounda_ry"), NULL,
+    NC_("view-action", "Draw a border around the canvas"),
+    view_toggle_canvas_boundary_cmd_callback,
+    TRUE,
+    GIMP_HELP_VIEW_SHOW_CANVAS_BOUNDARY },
+
   { "view-show-guides", NULL,
     NC_("view-action", "Show _Guides"), "<primary><shift>T",
     NC_("view-action", "Display the image's guides"),
@@ -1004,25 +1011,27 @@ view_actions_update (GimpActionGroup *group,
   SET_ACTIVE    ("view-softproof-gamut-check",                  gammut);
   SET_SENSITIVE ("view-color-management-reset",                 image);
 
-  SET_SENSITIVE ("view-show-selection",      image);
-  SET_ACTIVE    ("view-show-selection",      display && options->show_selection);
-  SET_SENSITIVE ("view-show-layer-boundary", image);
-  SET_ACTIVE    ("view-show-layer-boundary", display && options->show_layer_boundary);
-  SET_SENSITIVE ("view-show-guides",         image);
-  SET_ACTIVE    ("view-show-guides",         display && options->show_guides);
-  SET_SENSITIVE ("view-show-grid",           image);
-  SET_ACTIVE    ("view-show-grid",           display && options->show_grid);
-  SET_SENSITIVE ("view-show-sample-points",  image);
-  SET_ACTIVE    ("view-show-sample-points",  display && options->show_sample_points);
-
-  SET_SENSITIVE ("view-snap-to-guides",      image);
-  SET_ACTIVE    ("view-snap-to-guides",      display && options->snap_to_guides);
-  SET_SENSITIVE ("view-snap-to-grid",        image);
-  SET_ACTIVE    ("view-snap-to-grid",        display && options->snap_to_grid);
-  SET_SENSITIVE ("view-snap-to-canvas",      image);
-  SET_ACTIVE    ("view-snap-to-canvas",      display && options->snap_to_canvas);
-  SET_SENSITIVE ("view-snap-to-vectors",     image);
-  SET_ACTIVE    ("view-snap-to-vectors",     display && options->snap_to_path);
+  SET_SENSITIVE ("view-show-selection",       image);
+  SET_ACTIVE    ("view-show-selection",       display && options->show_selection);
+  SET_SENSITIVE ("view-show-layer-boundary",  image);
+  SET_ACTIVE    ("view-show-layer-boundary",  display && options->show_layer_boundary);
+  SET_SENSITIVE ("view-show-canvas-boundary", image);
+  SET_ACTIVE    ("view-show-canvas-boundary", display && options->show_canvas_boundary);
+  SET_SENSITIVE ("view-show-guides",          image);
+  SET_ACTIVE    ("view-show-guides",          display && options->show_guides);
+  SET_SENSITIVE ("view-show-grid",            image);
+  SET_ACTIVE    ("view-show-grid",            display && options->show_grid);
+  SET_SENSITIVE ("view-show-sample-points",   image);
+  SET_ACTIVE    ("view-show-sample-points",   display && options->show_sample_points);
+
+  SET_SENSITIVE ("view-snap-to-guides",       image);
+  SET_ACTIVE    ("view-snap-to-guides",       display && options->snap_to_guides);
+  SET_SENSITIVE ("view-snap-to-grid",         image);
+  SET_ACTIVE    ("view-snap-to-grid",         display && options->snap_to_grid);
+  SET_SENSITIVE ("view-snap-to-canvas",       image);
+  SET_ACTIVE    ("view-snap-to-canvas",       display && options->snap_to_canvas);
+  SET_SENSITIVE ("view-snap-to-vectors",      image);
+  SET_ACTIVE    ("view-snap-to-vectors",      display && options->snap_to_path);
 
   if (display && options->padding_mode != GIMP_CANVAS_PADDING_MODE_DEFAULT)
     SET_COLOR ("view-padding-color-menu", &options->padding_color);
diff --git a/app/actions/view-commands.c b/app/actions/view-commands.c
index 71026c527d..695eb515fe 100644
--- a/app/actions/view-commands.c
+++ b/app/actions/view-commands.c
@@ -856,6 +856,23 @@ view_toggle_layer_boundary_cmd_callback (GimpAction *action,
     }
 }
 
+void
+view_toggle_canvas_boundary_cmd_callback (GimpAction *action,
+                                          GVariant   *value,
+                                          gpointer    data)
+{
+  GimpDisplayShell *shell;
+  gboolean          active;
+  return_if_no_shell (shell, data);
+
+  active = g_variant_get_boolean (value);
+
+  if (active != gimp_display_shell_get_show_canvas (shell))
+    {
+      gimp_display_shell_set_show_canvas (shell, active);
+    }
+}
+
 void
 view_toggle_menubar_cmd_callback (GimpAction *action,
                                   GVariant   *value,
diff --git a/app/actions/view-commands.h b/app/actions/view-commands.h
index c28a24ef2e..8afbba7527 100644
--- a/app/actions/view-commands.h
+++ b/app/actions/view-commands.h
@@ -126,6 +126,9 @@ void   view_toggle_selection_cmd_callback           (GimpAction *action,
 void   view_toggle_layer_boundary_cmd_callback      (GimpAction *action,
                                                      GVariant   *value,
                                                      gpointer    data);
+void   view_toggle_canvas_boundary_cmd_callback     (GimpAction *action,
+                                                     GVariant   *value,
+                                                     gpointer    data);
 void   view_toggle_menubar_cmd_callback             (GimpAction *action,
                                                      GVariant   *value,
                                                      gpointer    data);
diff --git a/app/config/gimpdisplayoptions.c b/app/config/gimpdisplayoptions.c
index 9e5a316c16..201ff0bf0c 100644
--- a/app/config/gimpdisplayoptions.c
+++ b/app/config/gimpdisplayoptions.c
@@ -47,6 +47,7 @@ enum
   PROP_SHOW_SCROLLBARS,
   PROP_SHOW_SELECTION,
   PROP_SHOW_LAYER_BOUNDARY,
+  PROP_SHOW_CANVAS_BOUNDARY,
   PROP_SHOW_GUIDES,
   PROP_SHOW_GRID,
   PROP_SHOW_SAMPLE_POINTS,
@@ -148,6 +149,13 @@ gimp_display_options_class_init (GimpDisplayOptionsClass *klass)
                             TRUE,
                             GIMP_PARAM_STATIC_STRINGS);
 
+  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_SHOW_CANVAS_BOUNDARY,
+                            "show-canvas-boundary",
+                            "Show canvas boundary",
+                            SHOW_CANVAS_BOUNDARY_BLURB,
+                            TRUE,
+                            GIMP_PARAM_STATIC_STRINGS);
+
   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_SHOW_GUIDES,
                             "show-guides",
                             "Show guides",
@@ -266,6 +274,13 @@ gimp_display_options_fullscreen_class_init (GimpDisplayOptionsFullscreenClass *k
                             FALSE,
                             GIMP_PARAM_STATIC_STRINGS);
 
+  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_SHOW_CANVAS_BOUNDARY,
+                            "show-canvas-boundary",
+                            "Show canvas boundary",
+                            SHOW_CANVAS_BOUNDARY_BLURB,
+                            FALSE,
+                            GIMP_PARAM_STATIC_STRINGS);
+
   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_SHOW_GUIDES,
                             "show-guides",
                             "Show guides",
@@ -367,6 +382,13 @@ gimp_display_options_no_image_class_init (GimpDisplayOptionsNoImageClass *klass)
                             FALSE,
                             GIMP_PARAM_STATIC_STRINGS);
 
+  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_SHOW_CANVAS_BOUNDARY,
+                            "show-canvas-boundary",
+                            "Show canvas boundary",
+                            SHOW_CANVAS_BOUNDARY_BLURB,
+                            FALSE,
+                            GIMP_PARAM_STATIC_STRINGS);
+
   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_SHOW_GUIDES,
                             "show-guides",
                             "Show guides",
@@ -451,6 +473,9 @@ gimp_display_options_set_property (GObject      *object,
     case PROP_SHOW_LAYER_BOUNDARY:
       options->show_layer_boundary = g_value_get_boolean (value);
       break;
+    case PROP_SHOW_CANVAS_BOUNDARY:
+      options->show_canvas_boundary = g_value_get_boolean (value);
+      break;
     case PROP_SHOW_GUIDES:
       options->show_guides = g_value_get_boolean (value);
       break;
@@ -513,6 +538,9 @@ gimp_display_options_get_property (GObject    *object,
     case PROP_SHOW_LAYER_BOUNDARY:
       g_value_set_boolean (value, options->show_layer_boundary);
       break;
+    case PROP_SHOW_CANVAS_BOUNDARY:
+      g_value_set_boolean (value, options->show_canvas_boundary);
+      break;
     case PROP_SHOW_GUIDES:
       g_value_set_boolean (value, options->show_guides);
       break;
diff --git a/app/config/gimpdisplayoptions.h b/app/config/gimpdisplayoptions.h
index d04baa7bd1..5d666f7891 100644
--- a/app/config/gimpdisplayoptions.h
+++ b/app/config/gimpdisplayoptions.h
@@ -48,6 +48,7 @@ struct _GimpDisplayOptions
   gboolean               show_scrollbars;
   gboolean               show_selection;
   gboolean               show_layer_boundary;
+  gboolean               show_canvas_boundary;
   gboolean               show_guides;
   gboolean               show_grid;
   gboolean               show_sample_points;
diff --git a/app/config/gimprc-blurbs.h b/app/config/gimprc-blurbs.h
index e710fd6021..a68e6acc24 100644
--- a/app/config/gimprc-blurbs.h
+++ b/app/config/gimprc-blurbs.h
@@ -406,6 +406,10 @@ _("When enabled, the selection is visible by default. This can also be " \
 _("When enabled, the layer boundary is visible by default. This can also " \
   "be toggled with the \"View->Show Layer Boundary\" command.")
 
+#define SHOW_CANVAS_BOUNDARY_BLURB \
+_("When enabled, the canvas boundary is visible by default. This can also " \
+  "be toggled with the \"View->Show Canvas Boundary\" command.")
+
 #define SHOW_GUIDES_BLURB \
 _("When enabled, the guides are visible by default. This can also be " \
   "toggled with the \"View->Show Guides\" command.")
diff --git a/app/dialogs/preferences-dialog.c b/app/dialogs/preferences-dialog.c
index af827c335b..eb33c98d16 100644
--- a/app/dialogs/preferences-dialog.c
+++ b/app/dialogs/preferences-dialog.c
@@ -962,6 +962,9 @@ prefs_display_options_frame_add (Gimp         *gimp,
   prefs_check_button_add (object, "show-layer-boundary",
                           _("Show _layer boundary"),
                           GTK_BOX (checks_vbox));
+  prefs_check_button_add (object, "show-canvas-boundary",
+                          _("Show can_vas boundary"),
+                          GTK_BOX (checks_vbox));
   prefs_check_button_add (object, "show-guides",
                           _("Show _guides"),
                           GTK_BOX (checks_vbox));
diff --git a/app/display/Makefile.am b/app/display/Makefile.am
index 4429f84478..c8d111e1a0 100644
--- a/app/display/Makefile.am
+++ b/app/display/Makefile.am
@@ -40,6 +40,8 @@ libappdisplay_a_sources = \
        gimpcanvasboundary.h                    \
        gimpcanvasbufferpreview.c               \
        gimpcanvasbufferpreview.h               \
+       gimpcanvascanvasboundary.c              \
+       gimpcanvascanvasboundary.h              \
        gimpcanvascorner.c                      \
        gimpcanvascorner.h                      \
        gimpcanvascursor.c                      \
diff --git a/app/display/gimpcanvas-style.c b/app/display/gimpcanvas-style.c
index 3baed36c82..8d479618fd 100644
--- a/app/display/gimpcanvas-style.c
+++ b/app/display/gimpcanvas-style.c
@@ -68,6 +68,9 @@ static const GimpRGB layer_group_bg      = { 0.0, 1.0, 1.0, 1.0 };
 static const GimpRGB layer_mask_fg       = { 0.0, 0.0, 0.0, 1.0 };
 static const GimpRGB layer_mask_bg       = { 0.0, 1.0, 0.0, 1.0 };
 
+static const GimpRGB canvas_fg           = { 0.0, 0.0, 0.0, 1.0 };
+static const GimpRGB canvas_bg           = { 1.0, 0.5, 0.0, 1.0 };
+
 static const GimpRGB selection_out_fg    = { 1.0, 1.0, 1.0, 1.0 };
 static const GimpRGB selection_out_bg    = { 0.5, 0.5, 0.5, 1.0 };
 
@@ -290,6 +293,29 @@ gimp_canvas_set_layer_style (GtkWidget *canvas,
   cairo_pattern_destroy (pattern);
 }
 
+void
+gimp_canvas_set_canvas_style (GtkWidget *canvas,
+                              cairo_t   *cr,
+                              gdouble    offset_x,
+                              gdouble    offset_y)
+{
+  cairo_pattern_t *pattern;
+
+  g_return_if_fail (GTK_IS_WIDGET (canvas));
+  g_return_if_fail (cr != NULL);
+
+  cairo_set_line_width (cr, 1.0);
+  cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
+
+  pattern = gimp_cairo_pattern_create_stipple (&canvas_fg,
+                                               &canvas_bg,
+                                               0,
+                                               offset_x, offset_y);
+
+  cairo_set_source (cr, pattern);
+  cairo_pattern_destroy (pattern);
+}
+
 void
 gimp_canvas_set_selection_out_style (GtkWidget *canvas,
                                      cairo_t   *cr,
diff --git a/app/display/gimpcanvas-style.h b/app/display/gimpcanvas-style.h
index 85d35078b9..3a37b988b8 100644
--- a/app/display/gimpcanvas-style.h
+++ b/app/display/gimpcanvas-style.h
@@ -45,6 +45,10 @@ void   gimp_canvas_set_layer_style         (GtkWidget     *canvas,
                                             GimpLayer     *layer,
                                             gdouble        offset_x,
                                             gdouble        offset_y);
+void   gimp_canvas_set_canvas_style        (GtkWidget     *canvas,
+                                            cairo_t       *cr,
+                                            gdouble        offset_x,
+                                            gdouble        offset_y);
 void   gimp_canvas_set_selection_out_style (GtkWidget     *canvas,
                                             cairo_t       *cr,
                                             gdouble        offset_x,
diff --git a/app/display/gimpcanvascanvasboundary.c b/app/display/gimpcanvascanvasboundary.c
new file mode 100644
index 0000000000..01ac5a35f1
--- /dev/null
+++ b/app/display/gimpcanvascanvasboundary.c
@@ -0,0 +1,270 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpcanvascanvasboundary.c
+ * Copyright (C) 2019 Ell
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpmath/gimpmath.h"
+
+#include "display-types.h"
+
+#include "core/gimpimage.h"
+
+#include "gimpcanvas-style.h"
+#include "gimpcanvascanvasboundary.h"
+#include "gimpdisplayshell.h"
+
+
+enum
+{
+  PROP_0,
+  PROP_IMAGE
+};
+
+
+typedef struct _GimpCanvasCanvasBoundaryPrivate GimpCanvasCanvasBoundaryPrivate;
+
+struct _GimpCanvasCanvasBoundaryPrivate
+{
+  GimpImage *image;
+};
+
+#define GET_PRIVATE(canvas_boundary) \
+        ((GimpCanvasCanvasBoundaryPrivate *) gimp_canvas_canvas_boundary_get_instance_private 
((GimpCanvasCanvasBoundary *) (canvas_boundary)))
+
+
+/*  local function prototypes  */
+
+static void             gimp_canvas_canvas_boundary_set_property (GObject        *object,
+                                                                  guint           property_id,
+                                                                  const GValue   *value,
+                                                                  GParamSpec     *pspec);
+static void             gimp_canvas_canvas_boundary_get_property (GObject        *object,
+                                                                  guint           property_id,
+                                                                  GValue         *value,
+                                                                  GParamSpec     *pspec);
+static void             gimp_canvas_canvas_boundary_finalize     (GObject        *object);
+static void             gimp_canvas_canvas_boundary_draw         (GimpCanvasItem *item,
+                                                                  cairo_t        *cr);
+static cairo_region_t * gimp_canvas_canvas_boundary_get_extents  (GimpCanvasItem *item);
+static void             gimp_canvas_canvas_boundary_stroke       (GimpCanvasItem *item,
+                                                                  cairo_t        *cr);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpCanvasCanvasBoundary, gimp_canvas_canvas_boundary,
+                            GIMP_TYPE_CANVAS_RECTANGLE)
+
+#define parent_class gimp_canvas_canvas_boundary_parent_class
+
+
+static void
+gimp_canvas_canvas_boundary_class_init (GimpCanvasCanvasBoundaryClass *klass)
+{
+  GObjectClass        *object_class = G_OBJECT_CLASS (klass);
+  GimpCanvasItemClass *item_class   = GIMP_CANVAS_ITEM_CLASS (klass);
+
+  object_class->set_property = gimp_canvas_canvas_boundary_set_property;
+  object_class->get_property = gimp_canvas_canvas_boundary_get_property;
+  object_class->finalize     = gimp_canvas_canvas_boundary_finalize;
+
+  item_class->draw           = gimp_canvas_canvas_boundary_draw;
+  item_class->get_extents    = gimp_canvas_canvas_boundary_get_extents;
+  item_class->stroke         = gimp_canvas_canvas_boundary_stroke;
+
+  g_object_class_install_property (object_class, PROP_IMAGE,
+                                   g_param_spec_object ("image", NULL, NULL,
+                                                        GIMP_TYPE_IMAGE,
+                                                        GIMP_PARAM_READWRITE));
+}
+
+static void
+gimp_canvas_canvas_boundary_init (GimpCanvasCanvasBoundary *canvas_boundary)
+{
+}
+
+static void
+gimp_canvas_canvas_boundary_finalize (GObject *object)
+{
+  GimpCanvasCanvasBoundaryPrivate *private = GET_PRIVATE (object);
+
+  if (private->image)
+    g_object_remove_weak_pointer (G_OBJECT (private->image),
+                                  (gpointer) &private->image);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_canvas_canvas_boundary_set_property (GObject      *object,
+                                          guint         property_id,
+                                          const GValue *value,
+                                          GParamSpec   *pspec)
+{
+  GimpCanvasCanvasBoundaryPrivate *private = GET_PRIVATE (object);
+
+  switch (property_id)
+    {
+    case PROP_IMAGE:
+      if (private->image)
+        g_object_remove_weak_pointer (G_OBJECT (private->image),
+                                      (gpointer) &private->image);
+      private->image = g_value_get_object (value); /* don't ref */
+      if (private->image)
+        g_object_add_weak_pointer (G_OBJECT (private->image),
+                                   (gpointer) &private->image);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_canvas_canvas_boundary_get_property (GObject    *object,
+                                          guint       property_id,
+                                          GValue     *value,
+                                          GParamSpec *pspec)
+{
+  GimpCanvasCanvasBoundaryPrivate *private = GET_PRIVATE (object);
+
+  switch (property_id)
+    {
+    case PROP_IMAGE:
+      g_value_set_object (value, private->image);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_canvas_canvas_boundary_draw (GimpCanvasItem *item,
+                                  cairo_t        *cr)
+{
+  GimpCanvasCanvasBoundaryPrivate *private = GET_PRIVATE (item);
+
+  if (private->image)
+    GIMP_CANVAS_ITEM_CLASS (parent_class)->draw (item, cr);
+}
+
+static cairo_region_t *
+gimp_canvas_canvas_boundary_get_extents (GimpCanvasItem *item)
+{
+  GimpCanvasCanvasBoundaryPrivate *private = GET_PRIVATE (item);
+
+  if (private->image)
+    return GIMP_CANVAS_ITEM_CLASS (parent_class)->get_extents (item);
+
+  return NULL;
+}
+
+static void
+gimp_canvas_canvas_boundary_stroke (GimpCanvasItem *item,
+                                    cairo_t        *cr)
+{
+  GimpDisplayShell *shell = gimp_canvas_item_get_shell (item);
+
+  gimp_canvas_set_canvas_style (gimp_canvas_item_get_canvas (item), cr,
+                                shell->offset_x, shell->offset_y);
+  cairo_stroke (cr);
+}
+
+GimpCanvasItem *
+gimp_canvas_canvas_boundary_new (GimpDisplayShell *shell)
+{
+  g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL);
+
+  return g_object_new (GIMP_TYPE_CANVAS_CANVAS_BOUNDARY,
+                       "shell", shell,
+                       NULL);
+}
+
+void
+gimp_canvas_canvas_boundary_set_image (GimpCanvasCanvasBoundary *boundary,
+                                       GimpImage                *image)
+{
+  GimpCanvasCanvasBoundaryPrivate *private;
+
+  g_return_if_fail (GIMP_IS_CANVAS_CANVAS_BOUNDARY (boundary));
+  g_return_if_fail (image == NULL || GIMP_IS_IMAGE (image));
+
+  private = GET_PRIVATE (boundary);
+
+  if (image != private->image)
+    {
+      gimp_canvas_item_begin_change (GIMP_CANVAS_ITEM (boundary));
+
+      if (image)
+        {
+          g_object_set (boundary,
+                        "x",      (gdouble) 0,
+                        "y",      (gdouble) 0,
+                        "width",  (gdouble) gimp_image_get_width  (image),
+                        "height", (gdouble) gimp_image_get_height (image),
+                        NULL);
+        }
+
+      g_object_set (boundary,
+                    "image", image,
+                    NULL);
+
+      gimp_canvas_item_end_change (GIMP_CANVAS_ITEM (boundary));
+    }
+  else if (image && image == private->image)
+    {
+      gint    lx, ly, lw, lh;
+      gdouble x, y, w ,h;
+
+      lx = 0;
+      ly = 0;
+      lw = gimp_image_get_width  (image);
+      lh = gimp_image_get_height (image);
+
+      g_object_get (boundary,
+                    "x",      &x,
+                    "y",      &y,
+                    "width",  &w,
+                    "height", &h,
+                    NULL);
+
+      if (lx != (gint) x ||
+          ly != (gint) y ||
+          lw != (gint) w ||
+          lh != (gint) h)
+        {
+          gimp_canvas_item_begin_change (GIMP_CANVAS_ITEM (boundary));
+
+          g_object_set (boundary,
+                        "x",      (gdouble) lx,
+                        "y",      (gdouble) ly,
+                        "width",  (gdouble) lw,
+                        "height", (gdouble) lh,
+                        NULL);
+
+          gimp_canvas_item_end_change (GIMP_CANVAS_ITEM (boundary));
+        }
+    }
+}
diff --git a/app/display/gimpcanvascanvasboundary.h b/app/display/gimpcanvascanvasboundary.h
new file mode 100644
index 0000000000..c8fe16f79f
--- /dev/null
+++ b/app/display/gimpcanvascanvasboundary.h
@@ -0,0 +1,58 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpcanvascanvasvboundary.h
+ * Copyright (C) 2019 Ell
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_CANVAS_CANVAS_BOUNDARY_H__
+#define __GIMP_CANVAS_CANVAS_BOUNDARY_H__
+
+
+#include "gimpcanvasrectangle.h"
+
+
+#define GIMP_TYPE_CANVAS_CANVAS_BOUNDARY            (gimp_canvas_canvas_boundary_get_type ())
+#define GIMP_CANVAS_CANVAS_BOUNDARY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GIMP_TYPE_CANVAS_CANVAS_BOUNDARY, GimpCanvasCanvasBoundary))
+#define GIMP_CANVAS_CANVAS_BOUNDARY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), 
GIMP_TYPE_CANVAS_CANVAS_BOUNDARY, GimpCanvasCanvasBoundaryClass))
+#define GIMP_IS_CANVAS_CANVAS_BOUNDARY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GIMP_TYPE_CANVAS_CANVAS_BOUNDARY))
+#define GIMP_IS_CANVAS_CANVAS_BOUNDARY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GIMP_TYPE_CANVAS_CANVAS_BOUNDARY))
+#define GIMP_CANVAS_CANVAS_BOUNDARY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GIMP_TYPE_CANVAS_CANVAS_BOUNDARY, GimpCanvasCanvasBoundaryClass))
+
+
+typedef struct _GimpCanvasCanvasBoundary      GimpCanvasCanvasBoundary;
+typedef struct _GimpCanvasCanvasBoundaryClass GimpCanvasCanvasBoundaryClass;
+
+struct _GimpCanvasCanvasBoundary
+{
+  GimpCanvasRectangle  parent_instance;
+};
+
+struct _GimpCanvasCanvasBoundaryClass
+{
+  GimpCanvasRectangleClass  parent_class;
+};
+
+
+GType            gimp_canvas_canvas_boundary_get_type  (void) G_GNUC_CONST;
+
+GimpCanvasItem * gimp_canvas_canvas_boundary_new       (GimpDisplayShell        *shell);
+
+void             gimp_canvas_canvas_boundary_set_image (GimpCanvasCanvasBoundary *boundary,
+                                                        GimpImage                *image);
+
+
+#endif /* __GIMP_CANVAS_CANVAS_BOUNDARY_H__ */
diff --git a/app/display/gimpdisplayshell-appearance.c b/app/display/gimpdisplayshell-appearance.c
index 21b4aafc40..e2a606378a 100644
--- a/app/display/gimpdisplayshell-appearance.c
+++ b/app/display/gimpdisplayshell-appearance.c
@@ -80,6 +80,8 @@ gimp_display_shell_appearance_update (GimpDisplayShell *shell)
                                              options->show_selection);
   gimp_display_shell_set_show_layer         (shell,
                                              options->show_layer_boundary);
+  gimp_display_shell_set_show_canvas        (shell,
+                                             options->show_canvas_boundary);
   gimp_display_shell_set_show_guides        (shell,
                                              options->show_guides);
   gimp_display_shell_set_show_grid          (shell,
@@ -256,6 +258,46 @@ gimp_display_shell_get_show_layer (GimpDisplayShell *shell)
   return appearance_get_options (shell)->show_layer_boundary;
 }
 
+void
+gimp_display_shell_set_show_canvas (GimpDisplayShell *shell,
+                                    gboolean          show)
+{
+  GimpDisplayOptions *options;
+
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+
+  options = appearance_get_options (shell);
+
+  g_object_set (options, "show-canvas-boundary", show, NULL);
+
+  gimp_canvas_item_set_visible (shell->canvas_boundary,
+                                show && shell->show_all);
+
+  gimp_display_shell_set_action_active (shell, "view-show-canvas-boundary", show);
+}
+
+gboolean
+gimp_display_shell_get_show_canvas (GimpDisplayShell *shell)
+{
+  g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
+
+  return appearance_get_options (shell)->show_canvas_boundary;
+}
+
+void
+gimp_display_shell_update_show_canvas (GimpDisplayShell *shell)
+{
+  GimpDisplayOptions *options;
+
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+
+  options = appearance_get_options (shell);
+
+  gimp_canvas_item_set_visible (shell->canvas_boundary,
+                                options->show_canvas_boundary &&
+                                shell->show_all);
+}
+
 void
 gimp_display_shell_set_show_guides (GimpDisplayShell *shell,
                                     gboolean          show)
diff --git a/app/display/gimpdisplayshell-appearance.h b/app/display/gimpdisplayshell-appearance.h
index b9ab81e548..80ceb2c945 100644
--- a/app/display/gimpdisplayshell-appearance.h
+++ b/app/display/gimpdisplayshell-appearance.h
@@ -45,6 +45,11 @@ void       gimp_display_shell_set_show_layer         (GimpDisplayShell       *sh
                                                       gboolean                show);
 gboolean   gimp_display_shell_get_show_layer         (GimpDisplayShell       *shell);
 
+void       gimp_display_shell_set_show_canvas        (GimpDisplayShell       *shell,
+                                                      gboolean                show);
+gboolean   gimp_display_shell_get_show_canvas        (GimpDisplayShell       *shell);
+void       gimp_display_shell_update_show_canvas     (GimpDisplayShell       *shell);
+
 void       gimp_display_shell_set_show_grid          (GimpDisplayShell       *shell,
                                                       gboolean                show);
 gboolean   gimp_display_shell_get_show_grid          (GimpDisplayShell       *shell);
diff --git a/app/display/gimpdisplayshell-handlers.c b/app/display/gimpdisplayshell-handlers.c
index 432c444cc1..fbd86ebfc4 100644
--- a/app/display/gimpdisplayshell-handlers.c
+++ b/app/display/gimpdisplayshell-handlers.c
@@ -48,6 +48,7 @@
 
 #include "widgets/gimpwidgets-utils.h"
 
+#include "gimpcanvascanvasboundary.h"
 #include "gimpcanvasguide.h"
 #include "gimpcanvaslayerboundary.h"
 #include "gimpcanvaspath.h"
@@ -388,6 +389,9 @@ gimp_display_shell_connect (GimpDisplayShell *shell)
   gimp_canvas_layer_boundary_set_layer (GIMP_CANVAS_LAYER_BOUNDARY (shell->layer_boundary),
                                         gimp_image_get_active_layer (image));
 
+  gimp_canvas_canvas_boundary_set_image (GIMP_CANVAS_CANVAS_BOUNDARY (shell->canvas_boundary),
+                                         image);
+
   if (shell->show_all)
     {
       gimp_image_inc_show_all_count (image);
@@ -422,6 +426,9 @@ gimp_display_shell_disconnect (GimpDisplayShell *shell)
   gimp_canvas_layer_boundary_set_layer (GIMP_CANVAS_LAYER_BOUNDARY (shell->layer_boundary),
                                         NULL);
 
+  gimp_canvas_canvas_boundary_set_image (GIMP_CANVAS_CANVAS_BOUNDARY (shell->canvas_boundary),
+                                         NULL);
+
   g_signal_handlers_disconnect_by_func (color_config,
                                         gimp_display_shell_color_config_notify_handler,
                                         shell);
diff --git a/app/display/gimpdisplayshell-items.c b/app/display/gimpdisplayshell-items.c
index d4f5b1fa5b..caa381adde 100644
--- a/app/display/gimpdisplayshell-items.c
+++ b/app/display/gimpdisplayshell-items.c
@@ -27,6 +27,7 @@
 
 #include "display-types.h"
 
+#include "gimpcanvascanvasboundary.h"
 #include "gimpcanvascursor.h"
 #include "gimpcanvasgrid.h"
 #include "gimpcanvaslayerboundary.h"
@@ -84,6 +85,11 @@ gimp_display_shell_items_init (GimpDisplayShell *shell)
   gimp_display_shell_add_item (shell, shell->sample_points);
   g_object_unref (shell->sample_points);
 
+  shell->canvas_boundary = gimp_canvas_canvas_boundary_new (shell);
+  gimp_canvas_item_set_visible (shell->canvas_boundary, FALSE);
+  gimp_display_shell_add_item (shell, shell->canvas_boundary);
+  g_object_unref (shell->canvas_boundary);
+
   shell->layer_boundary = gimp_canvas_layer_boundary_new (shell);
   gimp_canvas_item_set_visible (shell->layer_boundary, FALSE);
   gimp_display_shell_add_item (shell, shell->layer_boundary);
@@ -122,14 +128,15 @@ gimp_display_shell_items_free (GimpDisplayShell *shell)
 
       g_clear_object (&shell->canvas_item);
 
-      shell->passe_partout  = NULL;
-      shell->preview_items  = NULL;
-      shell->vectors        = NULL;
-      shell->grid           = NULL;
-      shell->guides         = NULL;
-      shell->sample_points  = NULL;
-      shell->layer_boundary = NULL;
-      shell->tool_items     = NULL;
+      shell->passe_partout   = NULL;
+      shell->preview_items   = NULL;
+      shell->vectors         = NULL;
+      shell->grid            = NULL;
+      shell->guides          = NULL;
+      shell->sample_points   = NULL;
+      shell->canvas_boundary = NULL;
+      shell->layer_boundary  = NULL;
+      shell->tool_items      = NULL;
     }
 
   if (shell->unrotated_item)
diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c
index 1064bca66c..a24722672a 100644
--- a/app/display/gimpdisplayshell.c
+++ b/app/display/gimpdisplayshell.c
@@ -59,6 +59,7 @@
 #include "tools/tool_manager.h"
 
 #include "gimpcanvas.h"
+#include "gimpcanvascanvasboundary.h"
 #include "gimpcanvaslayerboundary.h"
 #include "gimpdisplay.h"
 #include "gimpdisplayshell.h"
@@ -1790,6 +1791,8 @@ gimp_display_shell_set_show_all (GimpDisplayShell *shell,
 
       gimp_display_update_bounding_box (shell->display);
 
+      gimp_display_shell_update_show_canvas (shell);
+
       gimp_display_shell_scroll_clamp_and_update (shell);
       gimp_display_shell_scrollbars_update (shell);
 
@@ -1864,6 +1867,9 @@ gimp_display_shell_flush (GimpDisplayShell *shell)
   gimp_canvas_layer_boundary_set_layer (GIMP_CANVAS_LAYER_BOUNDARY (shell->layer_boundary),
                                         gimp_image_get_active_layer (gimp_display_get_image 
(shell->display)));
 
+  gimp_canvas_canvas_boundary_set_image (GIMP_CANVAS_CANVAS_BOUNDARY (shell->canvas_boundary),
+                                         gimp_display_get_image (shell->display));
+
   if (window && gimp_image_window_get_active_shell (window) == shell)
     {
       GimpUIManager *manager = gimp_image_window_get_ui_manager (window);
diff --git a/app/display/gimpdisplayshell.h b/app/display/gimpdisplayshell.h
index fb4261eaf7..20280da050 100644
--- a/app/display/gimpdisplayshell.h
+++ b/app/display/gimpdisplayshell.h
@@ -123,6 +123,7 @@ struct _GimpDisplayShell
   GimpCanvasItem    *grid;             /*  item proxy of the grid             */
   GimpCanvasItem    *guides;           /*  item proxies of guides             */
   GimpCanvasItem    *sample_points;    /*  item proxies of sample points      */
+  GimpCanvasItem    *canvas_boundary;  /*  item for the cabvas boundary       */
   GimpCanvasItem    *layer_boundary;   /*  item for the layer boundary        */
   GimpCanvasItem    *tool_items;       /*  tools items, below the cursor      */
   GimpCanvasItem    *cursor;           /*  item for the software cursor       */
diff --git a/app/widgets/gimphelp-ids.h b/app/widgets/gimphelp-ids.h
index 720d47dc0f..b8023d61dd 100644
--- a/app/widgets/gimphelp-ids.h
+++ b/app/widgets/gimphelp-ids.h
@@ -105,6 +105,7 @@
 #define GIMP_HELP_VIEW_COLOR_MANAGEMENT           "gimp-view-color-management"
 #define GIMP_HELP_VIEW_SHOW_SELECTION             "gimp-view-show-selection"
 #define GIMP_HELP_VIEW_SHOW_LAYER_BOUNDARY        "gimp-view-show-layer-boundary"
+#define GIMP_HELP_VIEW_SHOW_CANVAS_BOUNDARY       "gimp-view-show-canvas-boundary"
 #define GIMP_HELP_VIEW_SHOW_GUIDES                "gimp-view-show-guides"
 #define GIMP_HELP_VIEW_SHOW_GRID                  "gimp-view-show-grid"
 #define GIMP_HELP_VIEW_SHOW_SAMPLE_POINTS         "gimp-view-show-sample-points"
diff --git a/menus/image-menu.xml.in b/menus/image-menu.xml.in
index 35291ff120..cd65e65f7a 100644
--- a/menus/image-menu.xml.in
+++ b/menus/image-menu.xml.in
@@ -335,6 +335,7 @@
       <separator />
       <menuitem action="view-show-selection" />
       <menuitem action="view-show-layer-boundary" />
+      <menuitem action="view-show-canvas-boundary" />
       <menuitem action="view-show-guides" />
       <menuitem action="view-show-grid" />
       <menuitem action="view-show-sample-points" />


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]