2006-12-09 21:33:38 +00:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
1997-11-24 22:05:25 +00:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2009-01-17 22:28:01 +00:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
1997-11-24 22:05:25 +00:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-17 22:28:01 +00:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
1997-11-24 22:05:25 +00:00
|
|
|
* (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
|
2018-07-11 23:27:07 +02:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
1997-11-24 22:05:25 +00:00
|
|
|
*/
|
2000-12-29 15:22:01 +00:00
|
|
|
|
1999-09-06 00:07:03 +00:00
|
|
|
#include "config.h"
|
2005-01-02 20:42:31 +00:00
|
|
|
|
2008-01-23 09:51:43 +00:00
|
|
|
#include <gegl.h>
|
2000-12-29 15:22:01 +00:00
|
|
|
#include <gtk/gtk.h>
|
2000-04-27 17:27:28 +00:00
|
|
|
|
2007-03-09 13:00:01 +00:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2001-11-16 15:08:59 +00:00
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
|
2001-09-25 23:23:09 +00:00
|
|
|
#include "display-types.h"
|
2002-11-18 20:50:31 +00:00
|
|
|
|
2001-07-07 12:17:23 +00:00
|
|
|
#include "core/gimp.h"
|
2001-05-09 02:32:03 +00:00
|
|
|
#include "core/gimpimage.h"
|
2005-09-19 12:44:06 +00:00
|
|
|
#include "core/gimpimage-quick-mask.h"
|
2001-02-21 12:18:09 +00:00
|
|
|
|
2023-03-07 18:23:38 +01:00
|
|
|
#include "menus/menus.h"
|
|
|
|
|
2012-04-10 12:09:37 +02:00
|
|
|
#include "widgets/gimpcairo-wilber.h"
|
2023-06-09 17:20:11 +02:00
|
|
|
#include "widgets/gimpmenufactory.h"
|
2004-04-29 12:52:29 +00:00
|
|
|
#include "widgets/gimpuimanager.h"
|
2001-05-25 16:04:54 +00:00
|
|
|
|
2010-09-29 22:12:01 +02:00
|
|
|
#include "gimpcanvasitem.h"
|
2001-09-25 23:23:09 +00:00
|
|
|
#include "gimpdisplay.h"
|
2001-10-31 21:20:09 +00:00
|
|
|
#include "gimpdisplayshell.h"
|
2003-03-11 16:49:36 +00:00
|
|
|
#include "gimpdisplayshell-appearance.h"
|
2001-11-02 09:31:21 +00:00
|
|
|
#include "gimpdisplayshell-callbacks.h"
|
2004-02-07 00:16:52 +00:00
|
|
|
#include "gimpdisplayshell-draw.h"
|
2019-07-15 23:24:35 +02:00
|
|
|
#include "gimpdisplayshell-render.h"
|
2013-04-18 19:06:17 +02:00
|
|
|
#include "gimpdisplayshell-scale.h"
|
2001-11-02 09:31:21 +00:00
|
|
|
#include "gimpdisplayshell-scroll.h"
|
2016-01-05 18:02:59 +01:00
|
|
|
#include "gimpdisplayshell-scrollbars.h"
|
2001-11-10 23:03:22 +00:00
|
|
|
#include "gimpdisplayshell-selection.h"
|
2003-01-03 18:01:30 +00:00
|
|
|
#include "gimpdisplayshell-title.h"
|
2019-09-04 15:50:29 +03:00
|
|
|
#include "gimpdisplayshell-transform.h"
|
2009-09-26 01:19:27 +02:00
|
|
|
#include "gimpimagewindow.h"
|
2004-08-25 16:02:10 +00:00
|
|
|
#include "gimpnavigationeditor.h"
|
2001-09-25 23:23:09 +00:00
|
|
|
|
2015-03-12 12:07:32 +05:30
|
|
|
#include "git-version.h"
|
|
|
|
|
2014-03-07 11:32:24 +01:00
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
2000-12-29 15:22:01 +00:00
|
|
|
|
2001-11-30 16:39:40 +00:00
|
|
|
/* local function prototypes */
|
|
|
|
|
2011-02-23 07:13:45 +01:00
|
|
|
static void gimp_display_shell_vadjustment_changed (GtkAdjustment *adjustment,
|
2009-01-10 00:48:30 +00:00
|
|
|
GimpDisplayShell *shell);
|
2011-02-23 07:13:45 +01:00
|
|
|
static void gimp_display_shell_hadjustment_changed (GtkAdjustment *adjustment,
|
2009-01-10 00:48:30 +00:00
|
|
|
GimpDisplayShell *shell);
|
2011-02-23 07:13:45 +01:00
|
|
|
static gboolean gimp_display_shell_vscrollbar_change_value (GtkRange *range,
|
2009-01-10 00:48:30 +00:00
|
|
|
GtkScrollType scroll,
|
|
|
|
gdouble value,
|
|
|
|
GimpDisplayShell *shell);
|
|
|
|
|
2011-02-23 07:13:45 +01:00
|
|
|
static gboolean gimp_display_shell_hscrollbar_change_value (GtkRange *range,
|
2009-01-10 00:48:30 +00:00
|
|
|
GtkScrollType scroll,
|
|
|
|
gdouble value,
|
|
|
|
GimpDisplayShell *shell);
|
2008-03-19 19:19:37 +00:00
|
|
|
|
2013-04-18 11:56:43 +02:00
|
|
|
static void gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell,
|
2010-08-28 00:09:31 +02:00
|
|
|
cairo_t *cr);
|
2013-04-18 11:56:43 +02:00
|
|
|
static void gimp_display_shell_canvas_draw_drop_zone (GimpDisplayShell *shell,
|
2010-08-28 00:09:31 +02:00
|
|
|
cairo_t *cr);
|
2002-03-19 13:14:25 +00:00
|
|
|
|
|
|
|
|
2001-11-30 16:39:40 +00:00
|
|
|
/* public functions */
|
2001-02-24 19:29:47 +00:00
|
|
|
|
2001-11-02 09:31:21 +00:00
|
|
|
void
|
|
|
|
gimp_display_shell_canvas_realize (GtkWidget *canvas,
|
|
|
|
GimpDisplayShell *shell)
|
|
|
|
{
|
2019-07-15 23:24:35 +02:00
|
|
|
GimpCanvasPaddingMode padding_mode;
|
2023-11-20 00:20:03 +01:00
|
|
|
GeglColor *padding_color;
|
2019-07-15 23:24:35 +02:00
|
|
|
GtkAllocation allocation;
|
2001-11-02 09:31:21 +00:00
|
|
|
|
2010-03-02 00:11:47 +01:00
|
|
|
gtk_widget_grab_focus (canvas);
|
2001-11-09 16:54:56 +00:00
|
|
|
|
2003-07-17 22:30:13 +00:00
|
|
|
gimp_display_shell_get_padding (shell, &padding_mode, &padding_color);
|
2023-11-20 00:20:03 +01:00
|
|
|
gimp_display_shell_set_padding (shell, padding_mode, padding_color);
|
2023-11-20 21:38:11 +01:00
|
|
|
g_clear_object (&padding_color);
|
2001-11-16 15:08:59 +00:00
|
|
|
|
2009-10-17 19:51:33 +02:00
|
|
|
gtk_widget_get_allocation (canvas, &allocation);
|
|
|
|
|
2004-07-14 16:37:13 +00:00
|
|
|
gimp_display_shell_title_update (shell);
|
2001-11-09 16:54:56 +00:00
|
|
|
|
2009-10-17 19:51:33 +02:00
|
|
|
shell->disp_width = allocation.width;
|
|
|
|
shell->disp_height = allocation.height;
|
2001-11-02 09:31:21 +00:00
|
|
|
|
2019-09-11 21:00:32 +03:00
|
|
|
gimp_display_shell_render_set_scale (
|
|
|
|
shell,
|
|
|
|
gdk_window_get_scale_factor (
|
|
|
|
gtk_widget_get_window (gtk_widget_get_toplevel (canvas))));
|
|
|
|
|
2001-11-02 09:31:21 +00:00
|
|
|
/* set up the scrollbar observers */
|
2010-06-18 23:00:11 +02:00
|
|
|
g_signal_connect (shell->hsbdata, "value-changed",
|
2011-02-23 07:13:45 +01:00
|
|
|
G_CALLBACK (gimp_display_shell_hadjustment_changed),
|
2001-11-02 09:31:21 +00:00
|
|
|
shell);
|
2010-06-18 23:00:11 +02:00
|
|
|
g_signal_connect (shell->vsbdata, "value-changed",
|
2011-02-23 07:13:45 +01:00
|
|
|
G_CALLBACK (gimp_display_shell_vadjustment_changed),
|
2001-11-02 09:31:21 +00:00
|
|
|
shell);
|
|
|
|
|
2008-07-12 14:48:09 +00:00
|
|
|
g_signal_connect (shell->hsb, "change-value",
|
2011-02-23 07:13:45 +01:00
|
|
|
G_CALLBACK (gimp_display_shell_hscrollbar_change_value),
|
2008-07-12 14:48:09 +00:00
|
|
|
shell);
|
|
|
|
|
|
|
|
g_signal_connect (shell->vsb, "change-value",
|
2011-02-23 07:13:45 +01:00
|
|
|
G_CALLBACK (gimp_display_shell_vscrollbar_change_value),
|
2008-07-12 14:48:09 +00:00
|
|
|
shell);
|
|
|
|
|
2002-01-25 18:34:33 +00:00
|
|
|
/* allow shrinking */
|
|
|
|
gtk_widget_set_size_request (GTK_WIDGET (shell), 0, 0);
|
2001-11-02 09:31:21 +00:00
|
|
|
}
|
|
|
|
|
2019-07-21 18:13:53 +02:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
GimpDisplayShell *shell;
|
|
|
|
gint prev_width;
|
|
|
|
gint prev_height;
|
|
|
|
} TickClosure;
|
|
|
|
|
2018-06-28 00:52:08 +02:00
|
|
|
static gboolean
|
2019-07-21 18:13:53 +02:00
|
|
|
gimp_display_shell_canvas_tick (GtkWidget *widget,
|
|
|
|
GdkFrameClock *frame_clock,
|
|
|
|
TickClosure *tick)
|
2001-11-08 19:14:51 +00:00
|
|
|
{
|
2019-07-21 18:13:53 +02:00
|
|
|
GimpDisplayShell *shell = tick->shell;
|
|
|
|
GtkAllocation allocation;
|
2018-06-28 00:52:08 +02:00
|
|
|
|
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
2003-10-06 11:25:59 +00:00
|
|
|
|
2019-07-21 18:13:53 +02:00
|
|
|
if ((tick->prev_width != allocation.width) ||
|
|
|
|
(tick->prev_height != allocation.height))
|
2001-11-30 16:39:40 +00:00
|
|
|
{
|
2025-05-15 13:06:36 +00:00
|
|
|
if (shell->zoom_on_resize &&
|
2019-07-21 18:13:53 +02:00
|
|
|
tick->prev_width > 64 &&
|
|
|
|
tick->prev_height > 64 &&
|
|
|
|
allocation.width > 64 &&
|
|
|
|
allocation.height > 64)
|
2004-06-22 16:31:27 +00:00
|
|
|
{
|
2005-09-25 17:03:03 +00:00
|
|
|
gdouble scale = gimp_zoom_model_get_factor (shell->zoom);
|
2004-06-22 16:31:27 +00:00
|
|
|
gint offset_x;
|
|
|
|
gint offset_y;
|
|
|
|
|
2010-01-19 23:15:37 +01:00
|
|
|
/* FIXME: The code is a bit of a mess */
|
2008-08-17 07:29:48 +00:00
|
|
|
|
2004-06-22 16:31:27 +00:00
|
|
|
/* multiply the zoom_factor with the ratio of the new and
|
|
|
|
* old canvas diagonals
|
|
|
|
*/
|
2018-06-28 00:52:08 +02:00
|
|
|
scale *= (sqrt (SQR (allocation.width) +
|
|
|
|
SQR (allocation.height)) /
|
2019-07-21 18:13:53 +02:00
|
|
|
sqrt (SQR (tick->prev_width) +
|
|
|
|
SQR (tick->prev_height)));
|
2004-06-22 16:31:27 +00:00
|
|
|
|
|
|
|
offset_x = UNSCALEX (shell, shell->offset_x);
|
2025-05-15 13:06:36 +00:00
|
|
|
offset_y = UNSCALEY (shell, shell->offset_y);
|
2004-06-22 16:31:27 +00:00
|
|
|
|
2005-09-25 17:03:03 +00:00
|
|
|
gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, scale);
|
|
|
|
|
2004-06-22 16:31:27 +00:00
|
|
|
shell->offset_x = SCALEX (shell, offset_x);
|
|
|
|
shell->offset_y = SCALEY (shell, offset_y);
|
|
|
|
}
|
|
|
|
|
2008-08-17 07:21:41 +00:00
|
|
|
/* When we size-allocate due to resize of the top level window,
|
2008-08-17 07:29:48 +00:00
|
|
|
* we want some additional logic. Don't apply it on
|
|
|
|
* zoom_on_resize though.
|
2008-08-17 07:21:41 +00:00
|
|
|
*/
|
2008-08-17 10:48:49 +00:00
|
|
|
if (shell->size_allocate_from_configure_event &&
|
|
|
|
! shell->zoom_on_resize)
|
2008-08-17 07:21:41 +00:00
|
|
|
{
|
2008-08-17 10:48:49 +00:00
|
|
|
gboolean center_horizontally;
|
|
|
|
gboolean center_vertically;
|
|
|
|
gint target_offset_x;
|
|
|
|
gint target_offset_y;
|
|
|
|
gint sw;
|
|
|
|
gint sh;
|
|
|
|
|
2013-04-18 19:06:17 +02:00
|
|
|
gimp_display_shell_scale_get_image_size (shell, &sw, &sh);
|
2008-08-17 10:48:49 +00:00
|
|
|
|
|
|
|
center_horizontally = sw <= shell->disp_width;
|
|
|
|
center_vertically = sh <= shell->disp_height;
|
|
|
|
|
2019-09-15 16:22:06 +03:00
|
|
|
if (! gimp_display_shell_get_infinite_canvas (shell))
|
app: improve display scroll/zoom-related behavior in "show all" mode
In "show all" mode, the image is thought to be "infinite"; this
commit improves the overall scrolling/zooming behavior in this mode
according to this assumption. In cases where a specific image size
is needed (e.g., for the scrollbar bounds, fit-image-in-window,
etc.), the image's full bounding box is used; however, in cases
where a center point is needed (e.g., for the zoomed-out scrollbar
bounds, center-image-in-window), the canvas center, rather than the
bounding-box center, is still used.
2019-09-04 16:11:54 +03:00
|
|
|
{
|
|
|
|
gimp_display_shell_scroll_center_image (shell,
|
|
|
|
center_horizontally,
|
|
|
|
center_vertically);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_display_shell_scroll_center_content (shell,
|
|
|
|
center_horizontally,
|
|
|
|
center_vertically);
|
|
|
|
}
|
2008-08-17 10:48:49 +00:00
|
|
|
|
|
|
|
/* This is basically the best we can do before we get an
|
|
|
|
* API for storing the image offset at the start of an
|
|
|
|
* image window resize using the mouse
|
|
|
|
*/
|
|
|
|
target_offset_x = shell->offset_x;
|
|
|
|
target_offset_y = shell->offset_y;
|
2008-09-04 08:37:32 +00:00
|
|
|
|
2008-08-17 10:48:49 +00:00
|
|
|
if (! center_horizontally)
|
|
|
|
{
|
|
|
|
target_offset_x = MAX (shell->offset_x, 0);
|
|
|
|
}
|
2008-09-04 08:37:32 +00:00
|
|
|
|
2008-08-17 10:48:49 +00:00
|
|
|
if (! center_vertically)
|
|
|
|
{
|
|
|
|
target_offset_y = MAX (shell->offset_y, 0);
|
2008-08-17 07:29:48 +00:00
|
|
|
}
|
2008-09-04 08:37:32 +00:00
|
|
|
|
2008-08-17 10:48:49 +00:00
|
|
|
gimp_display_shell_scroll_set_offset (shell,
|
|
|
|
target_offset_x,
|
|
|
|
target_offset_y);
|
2008-08-17 07:21:41 +00:00
|
|
|
}
|
|
|
|
|
2008-08-14 14:41:29 +00:00
|
|
|
gimp_display_shell_scroll_clamp_and_update (shell);
|
2008-10-29 22:28:48 +00:00
|
|
|
gimp_display_shell_scaled (shell);
|
2008-08-14 14:41:29 +00:00
|
|
|
|
2008-08-17 10:48:49 +00:00
|
|
|
shell->size_allocate_from_configure_event = FALSE;
|
2001-11-30 16:39:40 +00:00
|
|
|
}
|
2018-05-29 21:09:44 +02:00
|
|
|
|
2018-06-28 00:52:08 +02:00
|
|
|
if (shell->size_allocate_center_image)
|
|
|
|
{
|
|
|
|
gimp_display_shell_scroll_center_image (shell, TRUE, TRUE);
|
|
|
|
|
|
|
|
shell->size_allocate_center_image = FALSE;
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:09:44 +02:00
|
|
|
/* undo size request from gimp_display_shell_constructed() */
|
|
|
|
gtk_widget_set_size_request (widget, -1, -1);
|
2018-06-28 00:52:08 +02:00
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_display_shell_canvas_size_allocate (GtkWidget *widget,
|
|
|
|
GtkAllocation *allocation,
|
|
|
|
GimpDisplayShell *shell)
|
|
|
|
{
|
2019-07-21 18:13:53 +02:00
|
|
|
TickClosure *tick;
|
|
|
|
|
2018-06-28 00:52:08 +02:00
|
|
|
/* are we in destruction? */
|
2023-12-16 22:30:02 +09:00
|
|
|
if (! shell->display || ! gimp_display_get_shell (shell->display) || ! gimp_display_get_image (shell->display))
|
2018-06-28 00:52:08 +02:00
|
|
|
return;
|
|
|
|
|
2019-07-21 18:13:53 +02:00
|
|
|
tick = g_new0 (TickClosure, 1);
|
|
|
|
|
|
|
|
tick->shell = shell;
|
|
|
|
tick->prev_width = shell->disp_width;
|
|
|
|
tick->prev_height = shell->disp_height;
|
|
|
|
|
|
|
|
if (shell->disp_width != allocation->width ||
|
|
|
|
shell->disp_height != allocation->height)
|
|
|
|
{
|
|
|
|
g_clear_pointer (&shell->render_cache, cairo_surface_destroy);
|
|
|
|
gimp_display_shell_render_invalidate_full (shell);
|
|
|
|
|
|
|
|
shell->disp_width = allocation->width;
|
|
|
|
shell->disp_height = allocation->height;
|
|
|
|
}
|
|
|
|
|
2018-06-28 00:52:08 +02:00
|
|
|
gtk_widget_add_tick_callback (widget,
|
|
|
|
(GtkTickCallback) gimp_display_shell_canvas_tick,
|
2023-05-23 00:11:23 +02:00
|
|
|
tick, (GDestroyNotify) g_free);
|
2001-11-08 19:14:51 +00:00
|
|
|
}
|
|
|
|
|
2001-11-30 16:39:40 +00:00
|
|
|
gboolean
|
2010-10-19 20:00:10 +02:00
|
|
|
gimp_display_shell_canvas_draw (GtkWidget *widget,
|
|
|
|
cairo_t *cr,
|
|
|
|
GimpDisplayShell *shell)
|
2001-11-08 19:14:51 +00:00
|
|
|
{
|
2003-10-06 11:25:59 +00:00
|
|
|
/* are we in destruction? */
|
2009-10-05 19:58:03 +02:00
|
|
|
if (! shell->display || ! gimp_display_get_shell (shell->display))
|
|
|
|
return TRUE;
|
2008-03-18 21:22:21 +00:00
|
|
|
|
2018-06-28 00:52:08 +02:00
|
|
|
/* we will scroll around in the next tick anyway, so we just can as
|
|
|
|
* well skip the drawing of this frame and wait for the next
|
|
|
|
*/
|
|
|
|
if (shell->size_allocate_center_image)
|
|
|
|
return TRUE;
|
|
|
|
|
2009-10-18 22:19:29 +02:00
|
|
|
/* ignore events on overlays */
|
2010-10-19 20:00:10 +02:00
|
|
|
if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
|
2003-11-11 17:07:41 +00:00
|
|
|
{
|
app: fix a crash when converting to higher precision.
gimp_display_shell_render() writes to a GeglBuffer backed by allocated memory
(shell->profile_data). Unfortunately while converting prevision in
gimp_image_convert_precision(), we change the "precision" property (hence the
source format) first, hence end up trying to write data in a too small buffer.
This crash was hard to find as it was not showing up on my machine (though it
did produce rendering artifacts!), unless I built both GIMP and babl with
`b_sanitize=address`.
Note that an alternate fix was to make sure that the profile_data buffer is big
enough (by calling gimp_display_shell_profile_update() before rendering), but
anyway the image is in an inconsistent state while conversion is in progress:
whereas the `src_format` is the new one, the `src_profile` is still the old one
(and cannot be changed before we finish converting).
Moreover the render happen regularly on progress signals, once after each
converted drawable. So each of these rendering step happens in an inconsistent
state, with the wrong profile set, some of the drawables converted and others
not yet.
We could still render properly if each drawable's buffer used space-aware format
(thus allowing different drawables to use different profiles/spaces), but it
feels over-engineering the problem. It might be much better to ignore rendering
steps while converting the image precision. Moreover it would obviously make a
faster conversion.
See discussions in #9136 for this crash, which didn't have dedicated report
AFAIK.
(cherry picked from commit de25be92104e6883cb35ea7bf0ea12408c8ca722)
Note: on the `master` branch, even with sanitized code, I don't get the crash.
Yet this change seems relevant enough that I'm adding it.
2023-02-19 13:54:03 +01:00
|
|
|
GimpImage *image = gimp_display_get_image (shell->display);
|
|
|
|
|
|
|
|
/* If we are currently converting the image, it might be in inconsistent
|
|
|
|
* state and should not be redrawn.
|
|
|
|
*/
|
|
|
|
if (image != NULL && ! gimp_image_get_converting (image))
|
2010-08-28 00:09:31 +02:00
|
|
|
{
|
2013-04-18 11:56:43 +02:00
|
|
|
gimp_display_shell_canvas_draw_image (shell, cr);
|
2010-05-01 18:02:42 +02:00
|
|
|
}
|
2023-02-19 18:53:42 +01:00
|
|
|
else if (image == NULL)
|
2010-05-01 18:02:42 +02:00
|
|
|
{
|
2013-04-18 11:56:43 +02:00
|
|
|
gimp_display_shell_canvas_draw_drop_zone (shell, cr);
|
2010-05-01 18:02:42 +02:00
|
|
|
}
|
2003-11-11 17:07:41 +00:00
|
|
|
}
|
2008-03-19 19:33:51 +00:00
|
|
|
|
2010-05-01 18:02:42 +02:00
|
|
|
return FALSE;
|
2001-11-30 16:39:40 +00:00
|
|
|
}
|
2001-11-08 19:14:51 +00:00
|
|
|
|
2001-08-19 11:21:48 +00:00
|
|
|
gboolean
|
2001-11-02 09:31:21 +00:00
|
|
|
gimp_display_shell_origin_button_press (GtkWidget *widget,
|
|
|
|
GdkEventButton *event,
|
|
|
|
GimpDisplayShell *shell)
|
1998-06-09 09:20:46 +00:00
|
|
|
{
|
2008-03-18 21:22:21 +00:00
|
|
|
if (! shell->display->gimp->busy)
|
1998-06-09 09:20:46 +00:00
|
|
|
{
|
2011-09-19 00:45:36 +02:00
|
|
|
if (event->type == GDK_BUTTON_PRESS && event->button == 1)
|
2004-11-09 11:38:29 +00:00
|
|
|
{
|
|
|
|
gboolean unused;
|
|
|
|
|
|
|
|
g_signal_emit_by_name (shell, "popup-menu", &unused);
|
|
|
|
}
|
1998-06-09 09:20:46 +00:00
|
|
|
}
|
|
|
|
|
2001-07-29 14:09:50 +00:00
|
|
|
/* Return TRUE to stop signal emission so the button doesn't grab the
|
2001-08-07 12:42:23 +00:00
|
|
|
* pointer away from us.
|
|
|
|
*/
|
2001-07-29 14:09:50 +00:00
|
|
|
return TRUE;
|
1998-06-09 09:20:46 +00:00
|
|
|
}
|
2001-11-16 15:08:59 +00:00
|
|
|
|
2001-11-30 14:41:56 +00:00
|
|
|
gboolean
|
2005-09-19 12:44:06 +00:00
|
|
|
gimp_display_shell_quick_mask_button_press (GtkWidget *widget,
|
|
|
|
GdkEventButton *bevent,
|
|
|
|
GimpDisplayShell *shell)
|
2001-11-30 14:41:56 +00:00
|
|
|
{
|
2009-10-06 19:20:44 +02:00
|
|
|
if (! gimp_display_get_image (shell->display))
|
2008-03-18 21:22:21 +00:00
|
|
|
return TRUE;
|
|
|
|
|
2011-10-02 16:23:59 +02:00
|
|
|
if (gdk_event_triggers_context_menu ((GdkEvent *) bevent))
|
2001-11-30 14:41:56 +00:00
|
|
|
{
|
2009-09-29 20:32:26 +02:00
|
|
|
GimpImageWindow *window = gimp_display_shell_get_window (shell);
|
2009-09-23 16:58:03 +02:00
|
|
|
|
2009-09-29 20:32:26 +02:00
|
|
|
if (window)
|
2009-09-29 21:44:43 +02:00
|
|
|
{
|
2023-06-09 17:20:11 +02:00
|
|
|
Gimp *gimp;
|
|
|
|
GimpUIManager *manager;
|
2009-09-29 21:44:43 +02:00
|
|
|
|
2023-06-09 17:20:11 +02:00
|
|
|
gimp = shell->display->gimp;
|
|
|
|
manager = gimp_menu_factory_get_manager (menus_get_global_menu_factory (gimp), "<QuickMask>", gimp);
|
2018-05-02 12:09:39 +02:00
|
|
|
gimp_ui_manager_ui_popup_at_widget (manager,
|
|
|
|
"/quick-mask-popup",
|
2023-02-27 18:49:45 +01:00
|
|
|
NULL, NULL,
|
2018-05-02 12:09:39 +02:00
|
|
|
widget,
|
|
|
|
GDK_GRAVITY_EAST,
|
|
|
|
GDK_GRAVITY_SOUTH_WEST,
|
|
|
|
(GdkEvent *) bevent,
|
|
|
|
NULL, NULL);
|
2009-09-29 21:44:43 +02:00
|
|
|
}
|
2001-11-30 14:41:56 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2005-09-19 12:44:06 +00:00
|
|
|
gimp_display_shell_quick_mask_toggled (GtkWidget *widget,
|
|
|
|
GimpDisplayShell *shell)
|
2001-11-30 14:41:56 +00:00
|
|
|
{
|
2009-10-06 19:20:44 +02:00
|
|
|
GimpImage *image = gimp_display_get_image (shell->display);
|
|
|
|
gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
|
2009-07-15 14:29:43 +02:00
|
|
|
|
2009-10-06 19:20:44 +02:00
|
|
|
if (active != gimp_image_get_quick_mask_state (image))
|
2004-02-14 15:37:23 +00:00
|
|
|
{
|
2016-10-01 01:06:02 +02:00
|
|
|
GimpImageWindow *window = gimp_display_shell_get_window (shell);
|
|
|
|
|
|
|
|
if (window)
|
|
|
|
{
|
2023-03-07 18:23:38 +01:00
|
|
|
GimpUIManager *manager = menus_get_image_manager_singleton (shell->display->gimp);
|
2001-11-30 14:41:56 +00:00
|
|
|
|
2016-10-01 01:06:02 +02:00
|
|
|
gimp_ui_manager_toggle_action (manager,
|
|
|
|
"quick-mask", "quick-mask-toggle",
|
|
|
|
active);
|
|
|
|
}
|
2004-02-14 15:37:23 +00:00
|
|
|
}
|
2001-11-30 14:41:56 +00:00
|
|
|
}
|
2001-11-30 16:39:40 +00:00
|
|
|
|
2002-05-05 19:17:41 +00:00
|
|
|
gboolean
|
2011-02-23 07:13:45 +01:00
|
|
|
gimp_display_shell_navigation_button_press (GtkWidget *widget,
|
|
|
|
GdkEventButton *bevent,
|
|
|
|
GimpDisplayShell *shell)
|
2002-05-05 19:17:41 +00:00
|
|
|
{
|
2009-10-06 19:20:44 +02:00
|
|
|
if (! gimp_display_get_image (shell->display))
|
2008-03-18 21:22:21 +00:00
|
|
|
return TRUE;
|
|
|
|
|
2011-09-19 00:45:36 +02:00
|
|
|
if (bevent->type == GDK_BUTTON_PRESS && bevent->button == 1)
|
2002-05-05 19:17:41 +00:00
|
|
|
{
|
2018-05-01 13:42:19 +02:00
|
|
|
gimp_navigation_editor_popup (shell, widget,
|
|
|
|
(GdkEvent *) bevent,
|
|
|
|
bevent->x, bevent->y);
|
2002-05-05 19:17:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2001-11-30 16:39:40 +00:00
|
|
|
|
2011-02-22 16:27:18 +01:00
|
|
|
/* private functions */
|
|
|
|
|
2001-11-30 16:39:40 +00:00
|
|
|
static void
|
2011-02-23 07:13:45 +01:00
|
|
|
gimp_display_shell_vadjustment_changed (GtkAdjustment *adjustment,
|
|
|
|
GimpDisplayShell *shell)
|
2001-11-30 16:39:40 +00:00
|
|
|
{
|
2011-02-23 07:13:45 +01:00
|
|
|
/* If we are panning with mouse, scrollbars are to be ignored or
|
|
|
|
* they will cause jitter in motion
|
2010-01-02 15:23:09 +02:00
|
|
|
*/
|
2022-07-26 19:52:47 +02:00
|
|
|
if (shell->mod_action == GIMP_MODIFIER_ACTION_NONE)
|
2010-01-02 15:23:09 +02:00
|
|
|
gimp_display_shell_scroll (shell,
|
|
|
|
0,
|
|
|
|
gtk_adjustment_get_value (adjustment) -
|
|
|
|
shell->offset_y);
|
2001-11-30 16:39:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-02-23 07:13:45 +01:00
|
|
|
gimp_display_shell_hadjustment_changed (GtkAdjustment *adjustment,
|
|
|
|
GimpDisplayShell *shell)
|
2001-11-30 16:39:40 +00:00
|
|
|
{
|
2011-02-23 07:13:45 +01:00
|
|
|
/* If we are panning with mouse, scrollbars are to be ignored or
|
|
|
|
* they will cause jitter in motion
|
2010-01-02 15:23:09 +02:00
|
|
|
*/
|
2022-07-26 19:52:47 +02:00
|
|
|
if (shell->mod_action == GIMP_MODIFIER_ACTION_NONE)
|
2010-01-02 15:23:09 +02:00
|
|
|
gimp_display_shell_scroll (shell,
|
|
|
|
gtk_adjustment_get_value (adjustment) -
|
|
|
|
shell->offset_x,
|
|
|
|
0);
|
2001-11-30 16:39:40 +00:00
|
|
|
}
|
|
|
|
|
2008-08-05 11:05:56 +00:00
|
|
|
static gboolean
|
2011-02-23 07:13:45 +01:00
|
|
|
gimp_display_shell_hscrollbar_change_value (GtkRange *range,
|
2008-08-05 11:05:56 +00:00
|
|
|
GtkScrollType scroll,
|
|
|
|
gdouble value,
|
|
|
|
GimpDisplayShell *shell)
|
|
|
|
{
|
|
|
|
if (! shell->display)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if ((scroll == GTK_SCROLL_JUMP) ||
|
|
|
|
(scroll == GTK_SCROLL_PAGE_BACKWARD) ||
|
|
|
|
(scroll == GTK_SCROLL_PAGE_FORWARD))
|
|
|
|
return FALSE;
|
|
|
|
|
2009-10-09 09:54:27 +02:00
|
|
|
g_object_freeze_notify (G_OBJECT (shell->hsbdata));
|
|
|
|
|
2016-01-05 18:02:59 +01:00
|
|
|
gimp_display_shell_scrollbars_setup_horizontal (shell, value);
|
2008-08-05 11:05:56 +00:00
|
|
|
|
2009-10-09 09:54:27 +02:00
|
|
|
g_object_thaw_notify (G_OBJECT (shell->hsbdata)); /* emits "changed" */
|
2008-08-05 11:05:56 +00:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-02-23 07:13:45 +01:00
|
|
|
gimp_display_shell_vscrollbar_change_value (GtkRange *range,
|
2008-08-05 11:05:56 +00:00
|
|
|
GtkScrollType scroll,
|
|
|
|
gdouble value,
|
|
|
|
GimpDisplayShell *shell)
|
|
|
|
{
|
|
|
|
if (! shell->display)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if ((scroll == GTK_SCROLL_JUMP) ||
|
|
|
|
(scroll == GTK_SCROLL_PAGE_BACKWARD) ||
|
|
|
|
(scroll == GTK_SCROLL_PAGE_FORWARD))
|
|
|
|
return FALSE;
|
|
|
|
|
2009-10-09 09:54:27 +02:00
|
|
|
g_object_freeze_notify (G_OBJECT (shell->vsbdata));
|
|
|
|
|
2016-01-05 18:02:59 +01:00
|
|
|
gimp_display_shell_scrollbars_setup_vertical (shell, value);
|
2008-08-05 11:05:56 +00:00
|
|
|
|
2009-10-09 09:54:27 +02:00
|
|
|
g_object_thaw_notify (G_OBJECT (shell->vsbdata)); /* emits "changed" */
|
2008-08-05 11:05:56 +00:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2008-03-19 19:33:51 +00:00
|
|
|
static void
|
2013-04-18 11:56:43 +02:00
|
|
|
gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell,
|
|
|
|
cairo_t *cr)
|
2008-03-19 19:19:37 +00:00
|
|
|
{
|
2013-04-19 16:22:19 +02:00
|
|
|
cairo_rectangle_list_t *clip_rectangles;
|
2019-09-04 15:50:29 +03:00
|
|
|
GeglRectangle image_rect;
|
|
|
|
GeglRectangle rotated_image_rect;
|
2019-09-15 16:12:17 +03:00
|
|
|
GeglRectangle canvas_rect;
|
2017-12-09 04:25:35 -05:00
|
|
|
cairo_matrix_t matrix;
|
2019-09-04 15:50:29 +03:00
|
|
|
gdouble x1, y1;
|
|
|
|
gdouble x2, y2;
|
2010-05-02 12:12:48 +02:00
|
|
|
|
2019-09-04 15:50:29 +03:00
|
|
|
gimp_display_shell_scale_get_image_unrotated_bounding_box (
|
|
|
|
shell,
|
|
|
|
&image_rect.x,
|
|
|
|
&image_rect.y,
|
|
|
|
&image_rect.width,
|
|
|
|
&image_rect.height);
|
2008-03-19 19:19:37 +00:00
|
|
|
|
2019-09-15 16:12:17 +03:00
|
|
|
gimp_display_shell_scale_get_image_unrotated_bounds (
|
|
|
|
shell,
|
|
|
|
&canvas_rect.x,
|
|
|
|
&canvas_rect.y,
|
|
|
|
&canvas_rect.width,
|
|
|
|
&canvas_rect.height);
|
|
|
|
|
2018-05-23 22:46:54 +02:00
|
|
|
/* first, draw the background
|
2013-04-19 02:08:10 +02:00
|
|
|
*/
|
2013-04-18 11:56:43 +02:00
|
|
|
|
2018-05-23 22:46:54 +02:00
|
|
|
gimp_display_shell_draw_background (shell, cr);
|
2008-03-19 19:19:37 +00:00
|
|
|
|
|
|
|
|
2010-05-02 12:12:48 +02:00
|
|
|
/* then, draw the exposed part of the region that is inside the
|
2013-04-19 02:08:10 +02:00
|
|
|
* image
|
2010-05-02 12:12:48 +02:00
|
|
|
*/
|
|
|
|
|
2013-04-19 02:08:10 +02:00
|
|
|
cairo_save (cr);
|
2013-04-19 16:22:19 +02:00
|
|
|
clip_rectangles = cairo_copy_clip_rectangle_list (cr);
|
2017-12-09 04:25:35 -05:00
|
|
|
cairo_get_matrix (cr, &matrix);
|
2013-04-19 16:22:19 +02:00
|
|
|
|
|
|
|
if (shell->rotate_transform)
|
|
|
|
cairo_transform (cr, shell->rotate_transform);
|
2010-05-02 12:12:48 +02:00
|
|
|
|
2019-09-04 15:50:29 +03:00
|
|
|
if (shell->show_all)
|
|
|
|
{
|
|
|
|
cairo_save (cr);
|
2019-09-15 16:12:17 +03:00
|
|
|
|
|
|
|
if (gimp_display_shell_get_padding_in_show_all (shell))
|
|
|
|
{
|
|
|
|
cairo_rectangle (cr,
|
|
|
|
canvas_rect.x,
|
|
|
|
canvas_rect.y,
|
|
|
|
canvas_rect.width,
|
|
|
|
canvas_rect.height);
|
|
|
|
cairo_clip (cr);
|
|
|
|
}
|
|
|
|
|
2019-09-04 15:50:29 +03:00
|
|
|
gimp_display_shell_draw_checkerboard (shell, cr);
|
2019-09-15 16:12:17 +03:00
|
|
|
|
2019-09-04 15:50:29 +03:00
|
|
|
cairo_restore (cr);
|
|
|
|
}
|
|
|
|
|
2013-04-19 02:08:10 +02:00
|
|
|
cairo_rectangle (cr,
|
|
|
|
image_rect.x,
|
|
|
|
image_rect.y,
|
|
|
|
image_rect.width,
|
|
|
|
image_rect.height);
|
|
|
|
cairo_clip (cr);
|
2008-03-19 19:19:37 +00:00
|
|
|
|
2019-09-04 15:50:29 +03:00
|
|
|
gimp_display_shell_rotate_bounds (shell,
|
|
|
|
image_rect.x,
|
|
|
|
image_rect.y,
|
|
|
|
image_rect.x + image_rect.width,
|
|
|
|
image_rect.y + image_rect.height,
|
|
|
|
&x1, &y1, &x2, &y2);
|
|
|
|
|
|
|
|
rotated_image_rect.x = floor (x1);
|
|
|
|
rotated_image_rect.y = floor (y1);
|
|
|
|
rotated_image_rect.width = ceil (x2) - rotated_image_rect.x;
|
|
|
|
rotated_image_rect.height = ceil (y2) - rotated_image_rect.y;
|
|
|
|
|
2013-04-19 02:08:10 +02:00
|
|
|
if (gdk_cairo_get_clip_rectangle (cr, NULL))
|
2008-03-19 19:19:37 +00:00
|
|
|
{
|
2013-04-19 16:22:19 +02:00
|
|
|
gint i;
|
2013-04-19 02:08:10 +02:00
|
|
|
|
2019-09-04 15:50:29 +03:00
|
|
|
if (! shell->show_all)
|
|
|
|
{
|
|
|
|
cairo_save (cr);
|
|
|
|
gimp_display_shell_draw_checkerboard (shell, cr);
|
|
|
|
cairo_restore (cr);
|
|
|
|
}
|
2010-09-28 21:10:03 +02:00
|
|
|
|
2019-08-10 22:00:14 +03:00
|
|
|
if (shell->show_image)
|
2013-04-18 11:56:43 +02:00
|
|
|
{
|
2019-08-10 22:00:14 +03:00
|
|
|
cairo_set_matrix (cr, &matrix);
|
|
|
|
|
|
|
|
for (i = 0; i < clip_rectangles->num_rectangles; i++)
|
|
|
|
{
|
2019-09-04 15:50:29 +03:00
|
|
|
cairo_rectangle_t clip_rect = clip_rectangles->rectangles[i];
|
|
|
|
GeglRectangle rect;
|
|
|
|
|
|
|
|
rect.x = floor (clip_rect.x);
|
|
|
|
rect.y = floor (clip_rect.y);
|
|
|
|
rect.width = ceil (clip_rect.x + clip_rect.width) - rect.x;
|
|
|
|
rect.height = ceil (clip_rect.y + clip_rect.height) - rect.y;
|
|
|
|
|
|
|
|
if (gegl_rectangle_intersect (&rect, &rect, &rotated_image_rect))
|
|
|
|
{
|
|
|
|
gimp_display_shell_draw_image (shell, cr,
|
|
|
|
rect.x, rect.y,
|
|
|
|
rect.width, rect.height);
|
|
|
|
}
|
2019-08-10 22:00:14 +03:00
|
|
|
}
|
2013-04-18 11:56:43 +02:00
|
|
|
}
|
2010-05-02 12:12:48 +02:00
|
|
|
}
|
2008-03-19 19:19:37 +00:00
|
|
|
|
2013-04-19 16:22:19 +02:00
|
|
|
cairo_rectangle_list_destroy (clip_rectangles);
|
2013-04-19 02:08:10 +02:00
|
|
|
cairo_restore (cr);
|
|
|
|
|
2010-05-02 12:12:48 +02:00
|
|
|
|
|
|
|
/* finally, draw all the remaining image window stuff on top
|
|
|
|
*/
|
2008-03-19 19:19:37 +00:00
|
|
|
|
2010-10-01 09:15:52 +02:00
|
|
|
/* draw canvas items */
|
2013-04-24 00:01:01 +02:00
|
|
|
cairo_save (cr);
|
|
|
|
|
2013-04-19 16:22:19 +02:00
|
|
|
if (shell->rotate_transform)
|
|
|
|
cairo_transform (cr, shell->rotate_transform);
|
|
|
|
|
2010-10-01 14:54:53 +02:00
|
|
|
gimp_canvas_item_draw (shell->canvas_item, cr);
|
2010-09-22 22:24:22 +02:00
|
|
|
|
2013-04-24 00:01:01 +02:00
|
|
|
cairo_restore (cr);
|
|
|
|
|
|
|
|
gimp_canvas_item_draw (shell->unrotated_item, cr);
|
|
|
|
|
2008-03-19 19:19:37 +00:00
|
|
|
/* restart (and recalculate) the selection boundaries */
|
2021-10-22 23:08:07 +02:00
|
|
|
gimp_display_shell_selection_draw (shell, cr);
|
2010-10-09 20:23:05 +02:00
|
|
|
gimp_display_shell_selection_restart (shell);
|
2008-03-19 19:33:51 +00:00
|
|
|
}
|
2008-03-19 19:19:37 +00:00
|
|
|
|
2008-03-19 19:33:51 +00:00
|
|
|
static void
|
2013-04-18 11:56:43 +02:00
|
|
|
gimp_display_shell_canvas_draw_drop_zone (GimpDisplayShell *shell,
|
|
|
|
cairo_t *cr)
|
2008-03-19 19:33:51 +00:00
|
|
|
{
|
2014-03-07 11:32:24 +01:00
|
|
|
cairo_save (cr);
|
|
|
|
|
2013-04-18 11:56:43 +02:00
|
|
|
gimp_display_shell_draw_background (shell, cr);
|
2008-03-19 19:33:51 +00:00
|
|
|
|
2013-09-28 18:00:31 +02:00
|
|
|
gimp_cairo_draw_drop_wilber (shell->canvas, cr, shell->blink);
|
2014-03-07 11:32:24 +01:00
|
|
|
|
|
|
|
cairo_restore (cr);
|
|
|
|
|
|
|
|
#ifdef GIMP_UNSTABLE
|
|
|
|
{
|
2018-05-06 18:22:39 -04:00
|
|
|
GtkWidget *widget = GTK_WIDGET (shell);
|
|
|
|
GtkStyleContext *context = gtk_widget_get_style_context (widget);
|
|
|
|
GtkStateFlags state = gtk_widget_get_state_flags (widget);
|
|
|
|
PangoLayout *layout;
|
|
|
|
gchar *msg;
|
|
|
|
GtkAllocation allocation;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
gdouble scale;
|
|
|
|
GdkRGBA color;
|
2014-03-07 11:32:24 +01:00
|
|
|
|
2014-05-27 21:58:10 +02:00
|
|
|
layout = gtk_widget_create_pango_layout (shell->canvas, NULL);
|
2015-03-12 12:07:32 +05:30
|
|
|
|
|
|
|
msg = g_strdup_printf (_("<big>Unstable Development Version</big>\n\n"
|
|
|
|
"<small>commit <tt>%s</tt></small>\n\n"
|
2015-08-31 18:49:37 +05:30
|
|
|
"<small>Please test bugs against "
|
|
|
|
"latest git master branch\n"
|
|
|
|
"before reporting them.</small>"),
|
2017-03-21 22:54:11 -04:00
|
|
|
GIMP_GIT_VERSION_ABBREV);
|
2015-03-12 12:07:32 +05:30
|
|
|
pango_layout_set_markup (layout, msg, -1);
|
|
|
|
g_free (msg);
|
2014-03-07 11:32:24 +01:00
|
|
|
pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
|
|
|
|
|
|
|
|
pango_layout_get_pixel_size (layout, &width, &height);
|
|
|
|
gtk_widget_get_allocation (shell->canvas, &allocation);
|
|
|
|
|
|
|
|
scale = MIN (((gdouble) allocation.width / 2.0) / (gdouble) width,
|
|
|
|
((gdouble) allocation.height / 2.0) / (gdouble) height);
|
|
|
|
|
2018-05-06 18:22:39 -04:00
|
|
|
gtk_style_context_get_color (context, state, &color);
|
|
|
|
gdk_cairo_set_source_rgba (cr, &color);
|
|
|
|
|
2014-03-07 11:32:24 +01:00
|
|
|
cairo_move_to (cr,
|
|
|
|
(allocation.width - (width * scale)) / 2,
|
|
|
|
(allocation.height - (height * scale)) / 2);
|
|
|
|
|
|
|
|
cairo_scale (cr, scale, scale);
|
|
|
|
|
|
|
|
pango_cairo_show_layout (cr, layout);
|
|
|
|
|
|
|
|
g_object_unref (layout);
|
|
|
|
}
|
|
|
|
#endif /* GIMP_UNSTABLE */
|
2008-03-19 19:19:37 +00:00
|
|
|
}
|