2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
1997-11-25 06:05:25 +08:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
1997-11-25 06:05:25 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
1997-11-25 06:05:25 +08: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-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
1997-11-25 06:05:25 +08:00
|
|
|
*/
|
2000-12-17 05:37:03 +08:00
|
|
|
|
app/appenv.h New file. Includes <math.h>. Move G_PI, RINT(), ROUND() etc
1999-09-01 Tor Lillqvist <tml@iki.fi>
* app/appenv.h
* libgimp/gimpmath.h: New file. Includes <math.h>. Move G_PI,
RINT(), ROUND() etc from app/appenv.h here, so plug-ins can
use them, too. Remove some commented-out old stuff in appenv.h.
* libgimp/gimp.h: Include gimpmath.h.
* libgimp/gimp.c (gimp_main): Win32: Don't install signal
handlers, we can't do anything useful in the handler ourselves
anyway (it would be nice to print out a backtrace, but that seems
pretty hard to do, even if not impossible). Let Windows inform the
user about the crash. If the plug-in was compiled with MSVC, and
the user also has it, she is offered a chance to start the
debugger automatically anyway.
* app/*several*.c: Include gimpmath.h for G_PI etc. Don't include
<math.h>, as gimpmath.h includes it.
* plug-ins/*/*many*.c: Include config.h. Don't include <math.h>.
Remove all the duplicated definitions of G_PI and rint(). Use
RINT() instead of rint().
* app/app_procs.[ch]: app_exit() takes a gboolean.
* app/batch.c
* app/commands.c
* app/interface.c: Call app_exit() with FALSE or TRUE.
* app/main.c (on_error): Call gimp_fatal_error. (main): Don't
install any signal handler on Win32 here, either.
* app/errors.c (gimp_fatal_error, gimp_terminate): Win32: Format
the message and call MessageBox with it. g_on_error_query doesn't
do anything useful on Win32, and printf'ing a message to stdout or
stderr doesn't do anything, either, in a windowing application.
1999-09-02 04:30:56 +08:00
|
|
|
#include "config.h"
|
2001-10-29 19:47:11 +08:00
|
|
|
|
2008-10-10 04:24:04 +08:00
|
|
|
#include <gegl.h>
|
2000-12-17 05:37:03 +08:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
2019-07-31 16:16:21 +08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2007-03-09 21:00:01 +08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
|
|
|
|
2001-09-26 07:23:09 +08:00
|
|
|
#include "display-types.h"
|
2002-05-03 20:45:22 +08:00
|
|
|
#include "tools/tools-types.h"
|
|
|
|
|
2009-10-03 03:15:07 +08:00
|
|
|
#include "config/gimpguiconfig.h"
|
2008-03-19 05:22:21 +08:00
|
|
|
|
2001-07-07 20:17:23 +08:00
|
|
|
#include "core/gimp.h"
|
2008-11-03 05:34:14 +08:00
|
|
|
#include "core/gimpcontainer.h"
|
2009-10-03 03:50:02 +08:00
|
|
|
#include "core/gimpcontext.h"
|
2001-05-09 10:32:03 +08:00
|
|
|
#include "core/gimpimage.h"
|
2004-08-11 02:47:21 +08:00
|
|
|
#include "core/gimpprogress.h"
|
2003-01-11 01:55:53 +08:00
|
|
|
|
2013-02-28 06:26:49 +08:00
|
|
|
#include "widgets/gimpdialogfactory.h"
|
|
|
|
|
2003-04-15 22:20:19 +08:00
|
|
|
#include "tools/gimptool.h"
|
2001-02-28 10:53:27 +08:00
|
|
|
#include "tools/tool_manager.h"
|
|
|
|
|
2001-09-26 07:23:09 +08:00
|
|
|
#include "gimpdisplay.h"
|
2001-11-01 05:20:09 +08:00
|
|
|
#include "gimpdisplay-handlers.h"
|
2001-09-26 07:23:09 +08:00
|
|
|
#include "gimpdisplayshell.h"
|
2009-10-03 05:55:26 +08:00
|
|
|
#include "gimpdisplayshell-expose.h"
|
2001-11-11 07:03:22 +08:00
|
|
|
#include "gimpdisplayshell-handlers.h"
|
2019-07-16 05:24:35 +08:00
|
|
|
#include "gimpdisplayshell-render.h"
|
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 21:11:54 +08:00
|
|
|
#include "gimpdisplayshell-scroll.h"
|
|
|
|
#include "gimpdisplayshell-scrollbars.h"
|
2020-04-19 23:00:04 +08:00
|
|
|
#include "gimpdisplayshell-title.h"
|
2003-01-04 02:01:30 +08:00
|
|
|
#include "gimpdisplayshell-transform.h"
|
2009-09-30 02:56:14 +08:00
|
|
|
#include "gimpimagewindow.h"
|
2001-04-18 05:43:29 +08:00
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
#include "gimp-intl.h"
|
2000-04-28 01:27:28 +08:00
|
|
|
|
2001-07-31 19:33:13 +08:00
|
|
|
|
2018-04-08 21:16:53 +08:00
|
|
|
#define PAINT_AREA_CHUNK_WIDTH 32
|
|
|
|
#define PAINT_AREA_CHUNK_HEIGHT 32
|
2010-10-12 04:49:10 +08:00
|
|
|
|
|
|
|
|
2002-05-10 21:09:19 +08:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
2005-05-12 04:41:51 +08:00
|
|
|
PROP_IMAGE,
|
|
|
|
PROP_SHELL
|
2002-05-10 21:09:19 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
struct _GimpDisplayImplPrivate
|
2009-10-06 02:06:13 +08:00
|
|
|
{
|
2014-05-31 07:22:54 +08:00
|
|
|
GimpImage *image; /* pointer to the associated image */
|
|
|
|
gint instance; /* the instance # of this display as
|
|
|
|
* taken from the image at creation */
|
2010-02-28 23:14:54 +08:00
|
|
|
|
2019-09-04 20:50:29 +08:00
|
|
|
GeglRectangle bounding_box;
|
|
|
|
|
2014-05-31 07:22:54 +08:00
|
|
|
GtkWidget *shell;
|
|
|
|
cairo_region_t *update_region;
|
2009-10-06 02:06:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2001-11-01 05:20:09 +08:00
|
|
|
/* local function prototypes */
|
2001-07-31 19:33:13 +08:00
|
|
|
|
2011-02-06 19:07:55 +08:00
|
|
|
static void gimp_display_progress_iface_init (GimpProgressInterface *iface);
|
|
|
|
|
|
|
|
static void gimp_display_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_display_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
2021-04-30 09:39:23 +08:00
|
|
|
static gboolean gimp_display_impl_present (GimpDisplay *display);
|
2021-07-05 21:24:12 +08:00
|
|
|
static gboolean gimp_display_impl_grab_focus (GimpDisplay *display);
|
2021-04-30 09:39:23 +08:00
|
|
|
|
2011-02-06 19:07:55 +08:00
|
|
|
static GimpProgress * gimp_display_progress_start (GimpProgress *progress,
|
2014-07-13 05:45:20 +08:00
|
|
|
gboolean cancellable,
|
|
|
|
const gchar *message);
|
2011-02-06 19:07:55 +08:00
|
|
|
static void gimp_display_progress_end (GimpProgress *progress);
|
|
|
|
static gboolean gimp_display_progress_is_active (GimpProgress *progress);
|
|
|
|
static void gimp_display_progress_set_text (GimpProgress *progress,
|
|
|
|
const gchar *message);
|
|
|
|
static void gimp_display_progress_set_value (GimpProgress *progress,
|
|
|
|
gdouble percentage);
|
|
|
|
static gdouble gimp_display_progress_get_value (GimpProgress *progress);
|
|
|
|
static void gimp_display_progress_pulse (GimpProgress *progress);
|
app, libgimp*, pdb, plug-ins: reimplement generic inter-process transient window.
Having windows ID as guint32 is a mistake. Different systems have
different protocols. In Wayland in particular, Windows handles are
exchanged as strings. What this commit does is the following:
In core:
- get_window_id() virtual function in core GimpProgress is changed to
return a GBytes, as a generic "data" to represent a window differently
on different systems.
- All implementations of get_window_id() in various classes implementing
this interface are updated accordingly:
* GimpSubProgress
* GimpDisplay returns the handle of its shell.
* GimpDisplayShell now creates its window handle at construction with
libgimpwidget's gimp_widget_set_native_handle() and simply return
this handle every time it's requested.
* GimpFileDialog also creates its window handle at construction with
gimp_widget_set_native_handle().
- gimp_window_set_transient_for() in core is changed to take a
GimpProgress as argument (instead of a guint32 ID), requests and
process the ID itself, according to the running platform. In
particular, the following were improved:
* Unlike old code, it will work even if the window is not visible yet.
In such a case, the function simply adds a signal handler to set
transient at mapping. It makes it easier to use it at construction
in a reliable way.
* It now works for Wayland too, additionally to X11.
- GimpPdbProgress now exchanges a GBytes too with the command
GIMP_PROGRESS_COMMAND_GET_WINDOW.
- display_get_window_id() in gimp-gui.h also returns a GBytes now.
PDB/libgimp:
- gimp_display_get_window_handle() and gimp_progress_get_window_handle()
now return a GBytes to represent a window handle in an opaque way
(depending on the running platform).
In libgimp:
- GimpProgress's get_window() virtual function changed to return a
GBytes and renamed get_window_handle().
- In particular GimpProgressBar is the only implementation of
get_window_handle(). It creates its handle at object construction with
libgimpwidget's gimp_widget_set_native_handle() and the virtual
method's implementation simply returns the GBytes.
In libgimpUi:
- gimp_ui_get_display_window() and gimp_ui_get_progress_window() were
removed. We should not assume anymore that it is possible to create a
GdkWindow to be used. For instance this is not possible with Wayland
which has its own way to set a window transient with a string handle.
- gimp_window_set_transient_for_display() and
gimp_window_set_transient() now use an internal implementation similar
to core gimp_window_set_transient_for(), with the same improvements
(works even at construction when the window is not visible yet + works
for Wayland too).
In libgimpwidgets:
- New gimp_widget_set_native_handle() is a helper function used both in
core and libgimp* libraries for widgets which we want to be usable as
possible parents. It takes care of getting the relevant window handle
(depending on the running platform) and stores it in a given pointer,
either immediately or after a callback once the widget is mapped. So
it can be used at construction. Also it sets a handle for X11 or
Wayland.
In plug-ins:
- Screenshot uses the new gimp_progress_get_window_handle() directly now
in its X11 code path and creates out of it a GdkWindows itself with
gdk_x11_window_foreign_new_for_display().
Our inter-process transient implementation only worked for X11, and with
this commit, it works for Wayland too.
There is code for Windows but it is currently disabled as it apparently
hangs (there is a comment in-code which links to this old report:
https://bugzilla.gnome.org/show_bug.cgi?id=359538). NikcDC tested
yesterday with re-enabling the code and said they experienced a freeze.
;-(
Finally there is no infrastructure yet to make this work on macOS and
apparently there is no implementation of window handle in GDK for macOS
that I could find. I'm not sure if macOS doesn't have this concept of
setting transient on another processus's window or GDK is simply lacking
the implementation.
2023-08-14 20:23:06 +08:00
|
|
|
static GBytes * gimp_display_progress_get_window_id (GimpProgress *progress);
|
2011-02-06 19:07:55 +08:00
|
|
|
static gboolean gimp_display_progress_message (GimpProgress *progress,
|
|
|
|
Gimp *gimp,
|
|
|
|
GimpMessageSeverity severity,
|
|
|
|
const gchar *domain,
|
|
|
|
const gchar *message);
|
|
|
|
static void gimp_display_progress_canceled (GimpProgress *progress,
|
|
|
|
GimpDisplay *display);
|
|
|
|
|
2018-07-01 22:19:54 +08:00
|
|
|
static void gimp_display_flush_update_region (GimpDisplay *display);
|
2011-02-06 19:07:55 +08:00
|
|
|
static void gimp_display_paint_area (GimpDisplay *display,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h);
|
2001-09-26 01:44:03 +08:00
|
|
|
|
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
G_DEFINE_TYPE_WITH_CODE (GimpDisplayImpl, gimp_display_impl, GIMP_TYPE_DISPLAY,
|
|
|
|
G_ADD_PRIVATE (GimpDisplayImpl)
|
2005-12-11 03:24:36 +08:00
|
|
|
G_IMPLEMENT_INTERFACE (GIMP_TYPE_PROGRESS,
|
2006-05-15 17:46:31 +08:00
|
|
|
gimp_display_progress_iface_init))
|
2001-09-26 01:44:03 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
#define parent_class gimp_display_impl_parent_class
|
2001-09-26 01:44:03 +08:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
2019-09-04 20:27:18 +08:00
|
|
|
gimp_display_impl_class_init (GimpDisplayImplClass *klass)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2021-04-30 09:39:23 +08:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
GimpDisplayClass *display_class = GIMP_DISPLAY_CLASS (klass);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-05-10 21:09:19 +08:00
|
|
|
object_class->set_property = gimp_display_set_property;
|
|
|
|
object_class->get_property = gimp_display_get_property;
|
|
|
|
|
2021-04-30 09:39:23 +08:00
|
|
|
display_class->present = gimp_display_impl_present;
|
2021-07-05 21:24:12 +08:00
|
|
|
display_class->grab_focus = gimp_display_impl_grab_focus;
|
2021-04-30 09:39:23 +08:00
|
|
|
|
2002-05-10 21:09:19 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_IMAGE,
|
2004-07-12 19:43:00 +08:00
|
|
|
g_param_spec_object ("image",
|
|
|
|
NULL, NULL,
|
|
|
|
GIMP_TYPE_IMAGE,
|
2006-01-19 04:29:40 +08:00
|
|
|
GIMP_PARAM_READABLE));
|
2005-05-12 04:41:51 +08:00
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_SHELL,
|
|
|
|
g_param_spec_object ("shell",
|
|
|
|
NULL, NULL,
|
|
|
|
GIMP_TYPE_DISPLAY_SHELL,
|
2006-01-19 04:29:40 +08:00
|
|
|
GIMP_PARAM_READABLE));
|
2001-09-26 01:44:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-09-04 20:27:18 +08:00
|
|
|
gimp_display_impl_init (GimpDisplayImpl *display)
|
2001-09-26 01:44:03 +08:00
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
display->priv = gimp_display_impl_get_instance_private (display);
|
2001-09-26 01:44:03 +08:00
|
|
|
}
|
|
|
|
|
2004-08-11 02:47:21 +08:00
|
|
|
static void
|
2005-12-11 03:24:36 +08:00
|
|
|
gimp_display_progress_iface_init (GimpProgressInterface *iface)
|
2004-08-11 02:47:21 +08:00
|
|
|
{
|
2011-02-06 19:07:55 +08:00
|
|
|
iface->start = gimp_display_progress_start;
|
|
|
|
iface->end = gimp_display_progress_end;
|
|
|
|
iface->is_active = gimp_display_progress_is_active;
|
|
|
|
iface->set_text = gimp_display_progress_set_text;
|
|
|
|
iface->set_value = gimp_display_progress_set_value;
|
|
|
|
iface->get_value = gimp_display_progress_get_value;
|
|
|
|
iface->pulse = gimp_display_progress_pulse;
|
|
|
|
iface->get_window_id = gimp_display_progress_get_window_id;
|
|
|
|
iface->message = gimp_display_progress_message;
|
2004-08-11 02:47:21 +08:00
|
|
|
}
|
|
|
|
|
2002-05-10 21:09:19 +08:00
|
|
|
static void
|
|
|
|
gimp_display_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_display_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImpl *display = GIMP_DISPLAY_IMPL (object);
|
2002-05-10 21:09:19 +08:00
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_IMAGE:
|
2019-09-04 20:27:18 +08:00
|
|
|
g_value_set_object (value, display->priv->image);
|
2002-05-10 21:09:19 +08:00
|
|
|
break;
|
2008-03-19 05:22:21 +08:00
|
|
|
|
2005-05-12 04:41:51 +08:00
|
|
|
case PROP_SHELL:
|
2019-09-04 20:27:18 +08:00
|
|
|
g_value_set_object (value, display->priv->shell);
|
2005-05-12 04:41:51 +08:00
|
|
|
break;
|
2008-03-19 05:22:21 +08:00
|
|
|
|
2002-05-10 21:09:19 +08:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-30 09:39:23 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_display_impl_present (GimpDisplay *display)
|
|
|
|
{
|
|
|
|
gimp_display_shell_present (gimp_display_get_shell (display));
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2021-07-05 21:24:12 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_display_impl_grab_focus (GimpDisplay *display)
|
|
|
|
{
|
|
|
|
GimpDisplayImpl *display_impl = GIMP_DISPLAY_IMPL (display);
|
|
|
|
|
|
|
|
if (display_impl->priv->shell && gimp_display_get_image (display))
|
|
|
|
{
|
|
|
|
GimpImageWindow *image_window;
|
|
|
|
|
|
|
|
image_window = gimp_display_shell_get_window (gimp_display_get_shell (display));
|
|
|
|
|
|
|
|
gimp_display_present (display);
|
|
|
|
gtk_widget_grab_focus (gimp_window_get_primary_focus_widget (GIMP_WINDOW (image_window)));
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2004-08-11 02:47:21 +08:00
|
|
|
static GimpProgress *
|
|
|
|
gimp_display_progress_start (GimpProgress *progress,
|
2014-07-13 05:45:20 +08:00
|
|
|
gboolean cancellable,
|
|
|
|
const gchar *message)
|
2004-08-11 02:47:21 +08:00
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImpl *display = GIMP_DISPLAY_IMPL (progress);
|
2004-09-01 23:26:48 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
if (display->priv->shell)
|
|
|
|
return gimp_progress_start (GIMP_PROGRESS (display->priv->shell),
|
|
|
|
cancellable,
|
2014-07-13 05:45:20 +08:00
|
|
|
"%s", message);
|
2004-09-01 23:26:48 +08:00
|
|
|
|
2006-10-09 16:17:22 +08:00
|
|
|
return NULL;
|
2004-08-11 02:47:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_display_progress_end (GimpProgress *progress)
|
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImpl *display = GIMP_DISPLAY_IMPL (progress);
|
2004-08-11 02:47:21 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
if (display->priv->shell)
|
|
|
|
gimp_progress_end (GIMP_PROGRESS (display->priv->shell));
|
2004-08-11 02:47:21 +08:00
|
|
|
}
|
|
|
|
|
2004-08-11 18:29:56 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_display_progress_is_active (GimpProgress *progress)
|
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImpl *display = GIMP_DISPLAY_IMPL (progress);
|
2004-09-01 23:26:48 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
if (display->priv->shell)
|
|
|
|
return gimp_progress_is_active (GIMP_PROGRESS (display->priv->shell));
|
2004-09-01 23:26:48 +08:00
|
|
|
|
2006-10-09 16:17:22 +08:00
|
|
|
return FALSE;
|
2004-08-11 18:29:56 +08:00
|
|
|
}
|
|
|
|
|
2004-08-11 02:47:21 +08:00
|
|
|
static void
|
|
|
|
gimp_display_progress_set_text (GimpProgress *progress,
|
|
|
|
const gchar *message)
|
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImpl *display = GIMP_DISPLAY_IMPL (progress);
|
2004-08-11 02:47:21 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
if (display->priv->shell)
|
|
|
|
gimp_progress_set_text_literal (GIMP_PROGRESS (display->priv->shell),
|
|
|
|
message);
|
2004-08-11 02:47:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_display_progress_set_value (GimpProgress *progress,
|
|
|
|
gdouble percentage)
|
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImpl *display = GIMP_DISPLAY_IMPL (progress);
|
2004-08-11 02:47:21 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
if (display->priv->shell)
|
|
|
|
gimp_progress_set_value (GIMP_PROGRESS (display->priv->shell),
|
|
|
|
percentage);
|
2004-08-11 02:47:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static gdouble
|
|
|
|
gimp_display_progress_get_value (GimpProgress *progress)
|
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImpl *display = GIMP_DISPLAY_IMPL (progress);
|
2004-09-01 23:26:48 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
if (display->priv->shell)
|
|
|
|
return gimp_progress_get_value (GIMP_PROGRESS (display->priv->shell));
|
2004-09-01 23:26:48 +08:00
|
|
|
|
2006-10-09 16:17:22 +08:00
|
|
|
return 0.0;
|
2004-08-11 02:47:21 +08:00
|
|
|
}
|
|
|
|
|
2005-02-12 22:18:12 +08:00
|
|
|
static void
|
|
|
|
gimp_display_progress_pulse (GimpProgress *progress)
|
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImpl *display = GIMP_DISPLAY_IMPL (progress);
|
2005-02-12 22:18:12 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
if (display->priv->shell)
|
|
|
|
gimp_progress_pulse (GIMP_PROGRESS (display->priv->shell));
|
2005-02-12 22:18:12 +08:00
|
|
|
}
|
|
|
|
|
app, libgimp*, pdb, plug-ins: reimplement generic inter-process transient window.
Having windows ID as guint32 is a mistake. Different systems have
different protocols. In Wayland in particular, Windows handles are
exchanged as strings. What this commit does is the following:
In core:
- get_window_id() virtual function in core GimpProgress is changed to
return a GBytes, as a generic "data" to represent a window differently
on different systems.
- All implementations of get_window_id() in various classes implementing
this interface are updated accordingly:
* GimpSubProgress
* GimpDisplay returns the handle of its shell.
* GimpDisplayShell now creates its window handle at construction with
libgimpwidget's gimp_widget_set_native_handle() and simply return
this handle every time it's requested.
* GimpFileDialog also creates its window handle at construction with
gimp_widget_set_native_handle().
- gimp_window_set_transient_for() in core is changed to take a
GimpProgress as argument (instead of a guint32 ID), requests and
process the ID itself, according to the running platform. In
particular, the following were improved:
* Unlike old code, it will work even if the window is not visible yet.
In such a case, the function simply adds a signal handler to set
transient at mapping. It makes it easier to use it at construction
in a reliable way.
* It now works for Wayland too, additionally to X11.
- GimpPdbProgress now exchanges a GBytes too with the command
GIMP_PROGRESS_COMMAND_GET_WINDOW.
- display_get_window_id() in gimp-gui.h also returns a GBytes now.
PDB/libgimp:
- gimp_display_get_window_handle() and gimp_progress_get_window_handle()
now return a GBytes to represent a window handle in an opaque way
(depending on the running platform).
In libgimp:
- GimpProgress's get_window() virtual function changed to return a
GBytes and renamed get_window_handle().
- In particular GimpProgressBar is the only implementation of
get_window_handle(). It creates its handle at object construction with
libgimpwidget's gimp_widget_set_native_handle() and the virtual
method's implementation simply returns the GBytes.
In libgimpUi:
- gimp_ui_get_display_window() and gimp_ui_get_progress_window() were
removed. We should not assume anymore that it is possible to create a
GdkWindow to be used. For instance this is not possible with Wayland
which has its own way to set a window transient with a string handle.
- gimp_window_set_transient_for_display() and
gimp_window_set_transient() now use an internal implementation similar
to core gimp_window_set_transient_for(), with the same improvements
(works even at construction when the window is not visible yet + works
for Wayland too).
In libgimpwidgets:
- New gimp_widget_set_native_handle() is a helper function used both in
core and libgimp* libraries for widgets which we want to be usable as
possible parents. It takes care of getting the relevant window handle
(depending on the running platform) and stores it in a given pointer,
either immediately or after a callback once the widget is mapped. So
it can be used at construction. Also it sets a handle for X11 or
Wayland.
In plug-ins:
- Screenshot uses the new gimp_progress_get_window_handle() directly now
in its X11 code path and creates out of it a GdkWindows itself with
gdk_x11_window_foreign_new_for_display().
Our inter-process transient implementation only worked for X11, and with
this commit, it works for Wayland too.
There is code for Windows but it is currently disabled as it apparently
hangs (there is a comment in-code which links to this old report:
https://bugzilla.gnome.org/show_bug.cgi?id=359538). NikcDC tested
yesterday with re-enabling the code and said they experienced a freeze.
;-(
Finally there is no infrastructure yet to make this work on macOS and
apparently there is no implementation of window handle in GDK for macOS
that I could find. I'm not sure if macOS doesn't have this concept of
setting transient on another processus's window or GDK is simply lacking
the implementation.
2023-08-14 20:23:06 +08:00
|
|
|
static GBytes *
|
2011-02-06 19:07:55 +08:00
|
|
|
gimp_display_progress_get_window_id (GimpProgress *progress)
|
2005-09-10 02:07:31 +08:00
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImpl *display = GIMP_DISPLAY_IMPL (progress);
|
2005-09-10 02:07:31 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
if (display->priv->shell)
|
|
|
|
return gimp_progress_get_window_id (GIMP_PROGRESS (display->priv->shell));
|
2006-10-09 16:17:22 +08:00
|
|
|
|
app, libgimp*, pdb, plug-ins: reimplement generic inter-process transient window.
Having windows ID as guint32 is a mistake. Different systems have
different protocols. In Wayland in particular, Windows handles are
exchanged as strings. What this commit does is the following:
In core:
- get_window_id() virtual function in core GimpProgress is changed to
return a GBytes, as a generic "data" to represent a window differently
on different systems.
- All implementations of get_window_id() in various classes implementing
this interface are updated accordingly:
* GimpSubProgress
* GimpDisplay returns the handle of its shell.
* GimpDisplayShell now creates its window handle at construction with
libgimpwidget's gimp_widget_set_native_handle() and simply return
this handle every time it's requested.
* GimpFileDialog also creates its window handle at construction with
gimp_widget_set_native_handle().
- gimp_window_set_transient_for() in core is changed to take a
GimpProgress as argument (instead of a guint32 ID), requests and
process the ID itself, according to the running platform. In
particular, the following were improved:
* Unlike old code, it will work even if the window is not visible yet.
In such a case, the function simply adds a signal handler to set
transient at mapping. It makes it easier to use it at construction
in a reliable way.
* It now works for Wayland too, additionally to X11.
- GimpPdbProgress now exchanges a GBytes too with the command
GIMP_PROGRESS_COMMAND_GET_WINDOW.
- display_get_window_id() in gimp-gui.h also returns a GBytes now.
PDB/libgimp:
- gimp_display_get_window_handle() and gimp_progress_get_window_handle()
now return a GBytes to represent a window handle in an opaque way
(depending on the running platform).
In libgimp:
- GimpProgress's get_window() virtual function changed to return a
GBytes and renamed get_window_handle().
- In particular GimpProgressBar is the only implementation of
get_window_handle(). It creates its handle at object construction with
libgimpwidget's gimp_widget_set_native_handle() and the virtual
method's implementation simply returns the GBytes.
In libgimpUi:
- gimp_ui_get_display_window() and gimp_ui_get_progress_window() were
removed. We should not assume anymore that it is possible to create a
GdkWindow to be used. For instance this is not possible with Wayland
which has its own way to set a window transient with a string handle.
- gimp_window_set_transient_for_display() and
gimp_window_set_transient() now use an internal implementation similar
to core gimp_window_set_transient_for(), with the same improvements
(works even at construction when the window is not visible yet + works
for Wayland too).
In libgimpwidgets:
- New gimp_widget_set_native_handle() is a helper function used both in
core and libgimp* libraries for widgets which we want to be usable as
possible parents. It takes care of getting the relevant window handle
(depending on the running platform) and stores it in a given pointer,
either immediately or after a callback once the widget is mapped. So
it can be used at construction. Also it sets a handle for X11 or
Wayland.
In plug-ins:
- Screenshot uses the new gimp_progress_get_window_handle() directly now
in its X11 code path and creates out of it a GdkWindows itself with
gdk_x11_window_foreign_new_for_display().
Our inter-process transient implementation only worked for X11, and with
this commit, it works for Wayland too.
There is code for Windows but it is currently disabled as it apparently
hangs (there is a comment in-code which links to this old report:
https://bugzilla.gnome.org/show_bug.cgi?id=359538). NikcDC tested
yesterday with re-enabling the code and said they experienced a freeze.
;-(
Finally there is no infrastructure yet to make this work on macOS and
apparently there is no implementation of window handle in GDK for macOS
that I could find. I'm not sure if macOS doesn't have this concept of
setting transient on another processus's window or GDK is simply lacking
the implementation.
2023-08-14 20:23:06 +08:00
|
|
|
return NULL;
|
2006-10-09 16:17:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_display_progress_message (GimpProgress *progress,
|
|
|
|
Gimp *gimp,
|
|
|
|
GimpMessageSeverity severity,
|
|
|
|
const gchar *domain,
|
|
|
|
const gchar *message)
|
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImpl *display = GIMP_DISPLAY_IMPL (progress);
|
2006-10-09 16:17:22 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
if (display->priv->shell)
|
|
|
|
return gimp_progress_message (GIMP_PROGRESS (display->priv->shell), gimp,
|
2006-10-09 16:17:22 +08:00
|
|
|
severity, domain, message);
|
2005-09-10 02:07:31 +08:00
|
|
|
|
2006-10-09 16:17:22 +08:00
|
|
|
return FALSE;
|
2005-09-10 02:07:31 +08:00
|
|
|
}
|
|
|
|
|
2004-08-11 02:47:21 +08:00
|
|
|
static void
|
|
|
|
gimp_display_progress_canceled (GimpProgress *progress,
|
|
|
|
GimpDisplay *display)
|
|
|
|
{
|
|
|
|
gimp_progress_cancel (GIMP_PROGRESS (display));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
2001-09-26 01:44:03 +08:00
|
|
|
GimpDisplay *
|
2008-03-23 21:40:39 +08:00
|
|
|
gimp_display_new (Gimp *gimp,
|
|
|
|
GimpImage *image,
|
|
|
|
GimpUnit unit,
|
|
|
|
gdouble scale,
|
|
|
|
GimpUIManager *popup_manager,
|
2014-05-03 02:20:46 +08:00
|
|
|
GimpDialogFactory *dialog_factory,
|
2018-04-29 23:27:47 +08:00
|
|
|
GdkMonitor *monitor)
|
2001-09-26 01:44:03 +08:00
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplay *display;
|
|
|
|
GimpDisplayImplPrivate *private;
|
|
|
|
GimpImageWindow *window = NULL;
|
|
|
|
GimpDisplayShell *shell;
|
2001-09-26 01:44:03 +08:00
|
|
|
|
2008-03-19 05:22:21 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
|
|
|
|
g_return_val_if_fail (image == NULL || GIMP_IS_IMAGE (image), NULL);
|
2018-04-29 23:27:47 +08:00
|
|
|
g_return_val_if_fail (GDK_IS_MONITOR (monitor), NULL);
|
2001-10-29 19:47:11 +08:00
|
|
|
|
2006-12-12 04:57:44 +08:00
|
|
|
/* If there isn't an interface, never create a display */
|
2008-03-19 05:22:21 +08:00
|
|
|
if (gimp->no_interface)
|
2001-09-26 01:44:03 +08:00
|
|
|
return NULL;
|
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
display = g_object_new (GIMP_TYPE_DISPLAY_IMPL,
|
2008-03-19 05:22:21 +08:00
|
|
|
"gimp", gimp,
|
2006-03-29 01:55:52 +08:00
|
|
|
NULL);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
private = GIMP_DISPLAY_IMPL (display)->priv;
|
2009-10-06 02:06:13 +08:00
|
|
|
|
2002-05-08 20:39:01 +08:00
|
|
|
/* refs the image */
|
2008-03-19 05:22:21 +08:00
|
|
|
if (image)
|
2009-10-08 01:42:08 +08:00
|
|
|
gimp_display_set_image (display, image);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2009-10-03 03:15:07 +08:00
|
|
|
/* get an image window */
|
|
|
|
if (GIMP_GUI_CONFIG (display->config)->single_window_mode)
|
|
|
|
{
|
2009-10-03 03:50:02 +08:00
|
|
|
GimpDisplay *active_display;
|
2009-10-03 03:15:07 +08:00
|
|
|
|
2009-10-03 03:50:02 +08:00
|
|
|
active_display = gimp_context_get_display (gimp_get_user_context (gimp));
|
2009-10-03 03:15:07 +08:00
|
|
|
|
2009-10-03 03:50:02 +08:00
|
|
|
if (! active_display)
|
2009-10-03 03:15:07 +08:00
|
|
|
{
|
2009-10-03 03:50:02 +08:00
|
|
|
active_display =
|
|
|
|
GIMP_DISPLAY (gimp_container_get_first_child (gimp->displays));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (active_display)
|
|
|
|
{
|
2009-10-06 01:27:04 +08:00
|
|
|
GimpDisplayShell *shell = gimp_display_get_shell (active_display);
|
2009-10-03 03:15:07 +08:00
|
|
|
|
|
|
|
window = gimp_display_shell_get_window (shell);
|
|
|
|
}
|
|
|
|
}
|
2009-09-30 02:56:14 +08:00
|
|
|
|
2009-10-03 03:15:07 +08:00
|
|
|
if (! window)
|
2009-10-04 08:01:53 +08:00
|
|
|
{
|
2009-10-26 05:02:38 +08:00
|
|
|
window = gimp_image_window_new (gimp,
|
2010-02-28 23:14:54 +08:00
|
|
|
private->image,
|
2014-05-03 02:20:46 +08:00
|
|
|
dialog_factory,
|
|
|
|
monitor);
|
2009-10-04 08:01:53 +08:00
|
|
|
}
|
2009-10-03 03:15:07 +08:00
|
|
|
|
|
|
|
/* create the shell for the image */
|
2009-10-06 02:06:13 +08:00
|
|
|
private->shell = gimp_display_shell_new (display, unit, scale,
|
2014-05-03 06:54:20 +08:00
|
|
|
popup_manager,
|
|
|
|
monitor);
|
2001-11-10 00:54:56 +08:00
|
|
|
|
2009-10-06 01:27:04 +08:00
|
|
|
shell = gimp_display_get_shell (display);
|
2009-09-24 00:52:42 +08:00
|
|
|
|
2019-09-04 20:50:29 +08:00
|
|
|
gimp_display_update_bounding_box (display);
|
|
|
|
|
2009-10-05 01:30:32 +08:00
|
|
|
gimp_image_window_add_shell (window, shell);
|
|
|
|
gimp_display_shell_present (shell);
|
|
|
|
|
2013-02-28 06:26:49 +08:00
|
|
|
/* make sure the docks are visible, in case all other image windows
|
|
|
|
* are iconified, see bug #686544.
|
|
|
|
*/
|
|
|
|
gimp_dialog_factory_show_with_display (dialog_factory);
|
|
|
|
|
2009-10-05 01:30:32 +08:00
|
|
|
g_signal_connect (gimp_display_shell_get_statusbar (shell), "cancel",
|
2004-08-11 02:47:21 +08:00
|
|
|
G_CALLBACK (gimp_display_progress_canceled),
|
2006-03-29 01:55:52 +08:00
|
|
|
display);
|
2004-08-11 02:47:21 +08:00
|
|
|
|
2006-05-10 03:15:49 +08:00
|
|
|
/* add the display to the list */
|
2008-03-19 05:22:21 +08:00
|
|
|
gimp_container_add (gimp->displays, GIMP_OBJECT (display));
|
2006-05-10 03:15:49 +08:00
|
|
|
|
2006-03-29 01:55:52 +08:00
|
|
|
return display;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2008-04-06 04:32:24 +08:00
|
|
|
/**
|
|
|
|
* gimp_display_delete:
|
|
|
|
* @display:
|
|
|
|
*
|
|
|
|
* Closes the display and removes it from the display list. You should
|
|
|
|
* not call this function directly, use gimp_display_close() instead.
|
|
|
|
*/
|
2001-11-01 05:20:09 +08:00
|
|
|
void
|
2006-03-29 01:55:52 +08:00
|
|
|
gimp_display_delete (GimpDisplay *display)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImplPrivate *private;
|
|
|
|
GimpTool *active_tool;
|
2001-07-08 01:36:00 +08:00
|
|
|
|
2006-03-29 01:55:52 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY (display));
|
2001-09-26 01:44:03 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
private = GIMP_DISPLAY_IMPL (display)->priv;
|
2009-10-06 02:06:13 +08:00
|
|
|
|
2001-11-01 05:20:09 +08:00
|
|
|
/* remove the display from the list */
|
2008-04-06 04:32:24 +08:00
|
|
|
gimp_container_remove (display->gimp->displays, GIMP_OBJECT (display));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2008-03-19 05:22:21 +08:00
|
|
|
/* unrefs the image */
|
|
|
|
gimp_display_set_image (display, NULL);
|
2001-07-08 01:36:00 +08:00
|
|
|
|
2008-03-19 05:22:21 +08:00
|
|
|
active_tool = tool_manager_get_active (display->gimp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2006-06-19 03:58:49 +08:00
|
|
|
if (active_tool && active_tool->focus_display == display)
|
2008-03-19 05:22:21 +08:00
|
|
|
tool_manager_focus_display_active (display->gimp, NULL);
|
1998-04-13 12:32:39 +08:00
|
|
|
|
2009-10-06 02:06:13 +08:00
|
|
|
if (private->shell)
|
2001-09-26 01:44:03 +08:00
|
|
|
{
|
2009-10-06 01:27:04 +08:00
|
|
|
GimpDisplayShell *shell = gimp_display_get_shell (display);
|
2009-09-30 02:32:26 +08:00
|
|
|
GimpImageWindow *window = gimp_display_shell_get_window (shell);
|
2004-01-03 01:36:45 +08:00
|
|
|
|
2009-10-06 02:06:13 +08:00
|
|
|
/* set private->shell to NULL *before* destroying the shell.
|
2004-01-03 01:36:45 +08:00
|
|
|
* all callbacks in gimpdisplayshell-callbacks.c will check
|
|
|
|
* this pointer and do nothing if the shell is in destruction.
|
|
|
|
*/
|
2009-10-06 02:06:13 +08:00
|
|
|
private->shell = NULL;
|
2009-09-26 04:06:19 +08:00
|
|
|
|
2009-09-30 05:01:33 +08:00
|
|
|
if (window)
|
2009-09-26 04:06:19 +08:00
|
|
|
{
|
2009-09-30 05:01:33 +08:00
|
|
|
if (gimp_image_window_get_n_shells (window) > 1)
|
|
|
|
{
|
2009-10-02 01:38:52 +08:00
|
|
|
g_object_ref (shell);
|
|
|
|
|
2009-09-30 05:01:33 +08:00
|
|
|
gimp_image_window_remove_shell (window, shell);
|
2009-10-02 01:38:52 +08:00
|
|
|
gtk_widget_destroy (GTK_WIDGET (shell));
|
|
|
|
|
|
|
|
g_object_unref (shell);
|
2009-09-30 05:01:33 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-26 05:02:38 +08:00
|
|
|
gimp_image_window_destroy (window);
|
2009-09-30 05:01:33 +08:00
|
|
|
}
|
2009-09-26 04:06:19 +08:00
|
|
|
}
|
2009-09-30 05:01:33 +08:00
|
|
|
else
|
2009-09-26 04:06:19 +08:00
|
|
|
{
|
2009-09-30 05:01:33 +08:00
|
|
|
g_object_unref (shell);
|
2009-09-26 04:06:19 +08:00
|
|
|
}
|
2001-09-26 01:44:03 +08:00
|
|
|
}
|
1998-02-14 23:30:31 +08:00
|
|
|
|
2006-03-29 01:55:52 +08:00
|
|
|
g_object_unref (display);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2008-04-06 04:32:24 +08:00
|
|
|
/**
|
|
|
|
* gimp_display_close:
|
|
|
|
* @display:
|
|
|
|
*
|
|
|
|
* Closes the display. If this is the last display, it will remain
|
|
|
|
* open, but without an image.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gimp_display_close (GimpDisplay *display)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY (display));
|
|
|
|
|
2008-11-21 06:45:19 +08:00
|
|
|
if (gimp_container_get_n_children (display->gimp->displays) > 1)
|
2008-04-06 04:32:24 +08:00
|
|
|
{
|
|
|
|
gimp_display_delete (display);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_display_empty (display);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-12 00:57:27 +08:00
|
|
|
/**
|
|
|
|
* gimp_display_get_action_name:
|
|
|
|
* @display:
|
|
|
|
*
|
|
|
|
* Returns: The action name for the given display. The action name
|
|
|
|
* depends on the display ID. The result must be freed with g_free().
|
|
|
|
**/
|
|
|
|
gchar *
|
|
|
|
gimp_display_get_action_name (GimpDisplay *display)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
|
|
|
|
|
|
|
|
return g_strdup_printf ("windows-display-%04d",
|
2019-08-24 04:23:23 +08:00
|
|
|
gimp_display_get_id (display));
|
2012-02-12 00:57:27 +08:00
|
|
|
}
|
|
|
|
|
2009-10-05 01:39:22 +08:00
|
|
|
GimpImage *
|
|
|
|
gimp_display_get_image (GimpDisplay *display)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
|
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
return GIMP_DISPLAY_IMPL (display)->priv->image;
|
2009-10-05 01:39:22 +08:00
|
|
|
}
|
|
|
|
|
2001-11-01 05:20:09 +08:00
|
|
|
void
|
2008-03-19 05:22:21 +08:00
|
|
|
gimp_display_set_image (GimpDisplay *display,
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImplPrivate *private;
|
|
|
|
GimpImage *old_image = NULL;
|
|
|
|
GimpDisplayShell *shell;
|
2006-03-07 01:35:40 +08:00
|
|
|
|
2006-03-29 01:55:52 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY (display));
|
2008-03-19 05:22:21 +08:00
|
|
|
g_return_if_fail (image == NULL || GIMP_IS_IMAGE (image));
|
2001-09-26 01:44:03 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
private = GIMP_DISPLAY_IMPL (display)->priv;
|
2009-10-06 15:16:46 +08:00
|
|
|
|
2009-10-08 01:59:54 +08:00
|
|
|
shell = gimp_display_get_shell (display);
|
|
|
|
|
2010-02-28 23:14:54 +08:00
|
|
|
if (private->image)
|
2008-03-19 05:22:21 +08:00
|
|
|
{
|
|
|
|
/* stop any active tool */
|
|
|
|
tool_manager_control_active (display->gimp, GIMP_TOOL_ACTION_HALT,
|
|
|
|
display);
|
2003-10-12 19:20:22 +08:00
|
|
|
|
2009-10-08 01:59:54 +08:00
|
|
|
gimp_display_shell_disconnect (shell);
|
2001-11-11 07:03:22 +08:00
|
|
|
|
2008-03-19 05:22:21 +08:00
|
|
|
gimp_display_disconnect (display);
|
2009-10-08 03:13:39 +08:00
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_pointer (&private->update_region, cairo_region_destroy);
|
2014-05-31 07:22:54 +08:00
|
|
|
|
2010-02-28 23:14:54 +08:00
|
|
|
gimp_image_dec_display_count (private->image);
|
2009-10-08 03:13:39 +08:00
|
|
|
|
2010-02-28 23:14:54 +08:00
|
|
|
/* set private->image before unrefing because there may be code
|
2009-10-08 03:13:39 +08:00
|
|
|
* that listens for image removals and then iterates the
|
|
|
|
* display list to find a valid display.
|
|
|
|
*/
|
2010-02-28 23:14:54 +08:00
|
|
|
old_image = private->image;
|
2009-10-08 03:13:39 +08:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
g_print ("%s: image->ref_count before unrefing: %d\n",
|
|
|
|
G_STRFUNC, G_OBJECT (old_image)->ref_count);
|
|
|
|
#endif
|
2008-03-19 05:22:21 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2010-02-28 23:14:54 +08:00
|
|
|
private->image = image;
|
2009-10-08 03:13:39 +08:00
|
|
|
|
2008-03-19 05:22:21 +08:00
|
|
|
if (image)
|
2009-10-06 15:16:46 +08:00
|
|
|
{
|
2009-10-08 03:13:39 +08:00
|
|
|
#if 0
|
|
|
|
g_print ("%s: image->ref_count before refing: %d\n",
|
|
|
|
G_STRFUNC, G_OBJECT (image)->ref_count);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
g_object_ref (image);
|
|
|
|
|
2010-02-04 04:20:29 +08:00
|
|
|
private->instance = gimp_image_get_instance_count (image);
|
|
|
|
gimp_image_inc_instance_count (image);
|
2009-10-06 15:16:46 +08:00
|
|
|
|
2010-02-04 05:59:50 +08:00
|
|
|
gimp_image_inc_display_count (image);
|
2009-10-08 03:13:39 +08:00
|
|
|
|
|
|
|
gimp_display_connect (display);
|
2009-10-08 02:11:48 +08:00
|
|
|
|
|
|
|
if (shell)
|
|
|
|
gimp_display_shell_connect (shell);
|
2009-10-06 15:16:46 +08:00
|
|
|
}
|
2001-11-01 05:20:09 +08:00
|
|
|
|
2008-03-19 05:22:21 +08:00
|
|
|
if (old_image)
|
|
|
|
g_object_unref (old_image);
|
2006-03-07 01:35:40 +08:00
|
|
|
|
2019-09-04 20:50:29 +08:00
|
|
|
gimp_display_update_bounding_box (display);
|
|
|
|
|
2009-10-08 01:42:08 +08:00
|
|
|
if (shell)
|
|
|
|
{
|
|
|
|
if (image)
|
2020-04-19 23:00:04 +08:00
|
|
|
{
|
|
|
|
gimp_display_shell_reconnect (shell);
|
|
|
|
}
|
2009-10-08 01:42:08 +08:00
|
|
|
else
|
2020-04-19 23:00:04 +08:00
|
|
|
{
|
|
|
|
gimp_display_shell_title_update (shell);
|
|
|
|
}
|
2009-10-08 01:42:08 +08:00
|
|
|
}
|
2008-05-10 23:22:17 +08:00
|
|
|
|
2009-09-25 07:55:39 +08:00
|
|
|
if (old_image != image)
|
|
|
|
g_object_notify (G_OBJECT (display), "image");
|
2001-11-01 05:20:09 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2009-10-06 15:16:46 +08:00
|
|
|
gint
|
|
|
|
gimp_display_get_instance (GimpDisplay *display)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DISPLAY (display), 0);
|
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
return GIMP_DISPLAY_IMPL (display)->priv->instance;
|
2009-10-06 15:16:46 +08:00
|
|
|
}
|
|
|
|
|
2009-10-05 01:39:22 +08:00
|
|
|
GimpDisplayShell *
|
|
|
|
gimp_display_get_shell (GimpDisplay *display)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
|
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
return GIMP_DISPLAY_SHELL (GIMP_DISPLAY_IMPL (display)->priv->shell);
|
2009-10-05 01:39:22 +08:00
|
|
|
}
|
|
|
|
|
2008-03-20 00:15:50 +08:00
|
|
|
void
|
|
|
|
gimp_display_empty (GimpDisplay *display)
|
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImplPrivate *private;
|
|
|
|
GList *iter;
|
2010-02-28 23:14:54 +08:00
|
|
|
|
2008-03-20 00:15:50 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY (display));
|
2010-02-28 23:14:54 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
private = GIMP_DISPLAY_IMPL (display)->priv;
|
2010-02-28 23:14:54 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (private->image));
|
2008-03-20 00:15:50 +08:00
|
|
|
|
2019-01-08 23:00:51 +08:00
|
|
|
for (iter = display->gimp->context_list; iter; iter = g_list_next (iter))
|
|
|
|
{
|
|
|
|
GimpContext *context = iter->data;
|
|
|
|
|
|
|
|
if (gimp_context_get_display (context) == display)
|
|
|
|
gimp_context_set_image (context, NULL);
|
|
|
|
}
|
|
|
|
|
2008-03-20 00:15:50 +08:00
|
|
|
gimp_display_set_image (display, NULL);
|
|
|
|
|
2009-10-06 01:27:04 +08:00
|
|
|
gimp_display_shell_empty (gimp_display_get_shell (display));
|
2008-03-20 00:15:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_display_fill (GimpDisplay *display,
|
|
|
|
GimpImage *image,
|
|
|
|
GimpUnit unit,
|
|
|
|
gdouble scale)
|
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImplPrivate *private;
|
2010-02-28 23:14:54 +08:00
|
|
|
|
2008-03-20 00:15:50 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY (display));
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (image));
|
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
private = GIMP_DISPLAY_IMPL (display)->priv;
|
2010-02-28 23:14:54 +08:00
|
|
|
|
|
|
|
g_return_if_fail (private->image == NULL);
|
|
|
|
|
2008-03-20 00:15:50 +08:00
|
|
|
gimp_display_set_image (display, image);
|
|
|
|
|
2009-10-06 01:27:04 +08:00
|
|
|
gimp_display_shell_fill (gimp_display_get_shell (display),
|
2008-03-20 00:15:50 +08:00
|
|
|
image, unit, scale);
|
|
|
|
}
|
|
|
|
|
2019-09-04 20:50:29 +08:00
|
|
|
void
|
|
|
|
gimp_display_update_bounding_box (GimpDisplay *display)
|
|
|
|
{
|
|
|
|
GimpDisplayImplPrivate *private;
|
|
|
|
GimpDisplayShell *shell;
|
|
|
|
GeglRectangle bounding_box = {};
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY (display));
|
|
|
|
|
|
|
|
private = GIMP_DISPLAY_IMPL (display)->priv;
|
|
|
|
shell = gimp_display_get_shell (display);
|
|
|
|
|
|
|
|
if (shell)
|
|
|
|
{
|
|
|
|
bounding_box = gimp_display_shell_get_bounding_box (shell);
|
|
|
|
|
|
|
|
if (! gegl_rectangle_equal (&bounding_box, &private->bounding_box))
|
|
|
|
{
|
|
|
|
GeglRectangle diff_rects[4];
|
|
|
|
gint n_diff_rects;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
n_diff_rects = gegl_rectangle_subtract (diff_rects,
|
|
|
|
&private->bounding_box,
|
|
|
|
&bounding_box);
|
|
|
|
|
|
|
|
for (i = 0; i < n_diff_rects; i++)
|
|
|
|
{
|
|
|
|
gimp_display_paint_area (display,
|
|
|
|
diff_rects[i].x, diff_rects[i].y,
|
|
|
|
diff_rects[i].width, diff_rects[i].height);
|
|
|
|
}
|
|
|
|
|
|
|
|
private->bounding_box = bounding_box;
|
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 21:11:54 +08:00
|
|
|
|
|
|
|
gimp_display_shell_scroll_clamp_and_update (shell);
|
|
|
|
gimp_display_shell_scrollbars_update (shell);
|
2019-09-04 20:50:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
private->bounding_box = bounding_box;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-11-11 07:03:22 +08:00
|
|
|
void
|
2006-03-29 01:55:52 +08:00
|
|
|
gimp_display_update_area (GimpDisplay *display,
|
2004-07-14 00:36:29 +08:00
|
|
|
gboolean now,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImplPrivate *private;
|
2009-10-06 02:06:13 +08:00
|
|
|
|
2006-03-29 01:55:52 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY (display));
|
1998-10-02 00:22:28 +08:00
|
|
|
|
2019-09-04 20:27:18 +08:00
|
|
|
private = GIMP_DISPLAY_IMPL (display)->priv;
|
2009-10-06 02:06:13 +08:00
|
|
|
|
2004-07-14 00:36:29 +08:00
|
|
|
if (now)
|
|
|
|
{
|
2006-03-29 01:55:52 +08:00
|
|
|
gimp_display_paint_area (display, x, y, w, h);
|
2004-07-14 00:36:29 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-05-31 07:22:54 +08:00
|
|
|
cairo_rectangle_int_t rect;
|
|
|
|
gint image_width;
|
|
|
|
gint image_height;
|
|
|
|
|
|
|
|
image_width = gimp_image_get_width (private->image);
|
|
|
|
image_height = gimp_image_get_height (private->image);
|
2007-12-26 00:21:40 +08:00
|
|
|
|
2014-05-31 07:22:54 +08:00
|
|
|
rect.x = CLAMP (x, 0, image_width);
|
|
|
|
rect.y = CLAMP (y, 0, image_height);
|
|
|
|
rect.width = CLAMP (x + w, 0, image_width) - rect.x;
|
|
|
|
rect.height = CLAMP (y + h, 0, image_height) - rect.y;
|
1997-11-27 03:30:17 +08:00
|
|
|
|
2014-05-31 07:22:54 +08:00
|
|
|
if (private->update_region)
|
|
|
|
cairo_region_union_rectangle (private->update_region, &rect);
|
|
|
|
else
|
|
|
|
private->update_region = cairo_region_create_rectangle (&rect);
|
2004-07-14 00:36:29 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1998-10-02 00:22:28 +08:00
|
|
|
void
|
2006-03-29 01:55:52 +08:00
|
|
|
gimp_display_flush (GimpDisplay *display)
|
1998-10-02 00:22:28 +08:00
|
|
|
{
|
2006-03-29 01:55:52 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY (display));
|
2001-09-26 01:44:03 +08:00
|
|
|
|
2020-05-16 20:51:27 +08:00
|
|
|
/* FIXME: we can end up being called during shell construction if "show all"
|
|
|
|
* is enabled by default, in which case the shell's display pointer is still
|
|
|
|
* NULL
|
|
|
|
*/
|
|
|
|
if (gimp_display_get_shell (display))
|
|
|
|
{
|
|
|
|
gimp_display_flush_update_region (display);
|
2018-07-01 22:19:54 +08:00
|
|
|
|
2020-05-16 20:51:27 +08:00
|
|
|
gimp_display_shell_flush (gimp_display_get_shell (display));
|
|
|
|
}
|
1998-10-02 00:22:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-03-29 01:55:52 +08:00
|
|
|
gimp_display_flush_now (GimpDisplay *display)
|
1998-10-02 00:22:28 +08:00
|
|
|
{
|
2006-03-29 01:55:52 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY (display));
|
2001-09-26 01:44:03 +08:00
|
|
|
|
2018-07-01 22:19:54 +08:00
|
|
|
gimp_display_flush_update_region (display);
|
1998-10-02 00:22:28 +08:00
|
|
|
}
|
|
|
|
|
2001-02-20 23:15:30 +08:00
|
|
|
|
2001-11-11 07:03:22 +08:00
|
|
|
/* private functions */
|
|
|
|
|
|
|
|
static void
|
2018-07-01 22:19:54 +08:00
|
|
|
gimp_display_flush_update_region (GimpDisplay *display)
|
2001-06-18 21:10:03 +08:00
|
|
|
{
|
2019-09-04 20:27:18 +08:00
|
|
|
GimpDisplayImplPrivate *private = GIMP_DISPLAY_IMPL (display)->priv;
|
2009-10-06 02:06:13 +08:00
|
|
|
|
2014-05-31 07:22:54 +08:00
|
|
|
if (private->update_region)
|
2001-06-18 21:10:03 +08:00
|
|
|
{
|
2014-05-31 07:22:54 +08:00
|
|
|
gint n_rects = cairo_region_num_rectangles (private->update_region);
|
|
|
|
gint i;
|
2004-07-14 00:36:29 +08:00
|
|
|
|
2014-05-31 07:22:54 +08:00
|
|
|
for (i = 0; i < n_rects; i++)
|
2003-07-30 00:36:56 +08:00
|
|
|
{
|
2014-05-31 07:22:54 +08:00
|
|
|
cairo_rectangle_int_t rect;
|
2003-07-30 00:36:56 +08:00
|
|
|
|
2014-05-31 07:22:54 +08:00
|
|
|
cairo_region_get_rectangle (private->update_region,
|
|
|
|
i, &rect);
|
|
|
|
|
|
|
|
gimp_display_paint_area (display,
|
|
|
|
rect.x,
|
|
|
|
rect.y,
|
|
|
|
rect.width,
|
|
|
|
rect.height);
|
2003-07-30 00:36:56 +08:00
|
|
|
}
|
2007-08-14 03:36:18 +08:00
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_pointer (&private->update_region, cairo_region_destroy);
|
2001-06-18 21:10:03 +08:00
|
|
|
}
|
2001-11-11 07:03:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-03-29 01:55:52 +08:00
|
|
|
gimp_display_paint_area (GimpDisplay *display,
|
2001-11-11 07:03:22 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h)
|
|
|
|
{
|
2019-09-04 20:50:29 +08:00
|
|
|
GimpDisplayImplPrivate *private = GIMP_DISPLAY_IMPL (display)->priv;
|
|
|
|
GimpDisplayShell *shell = gimp_display_get_shell (display);
|
|
|
|
GeglRectangle rect;
|
2019-09-04 20:27:18 +08:00
|
|
|
gint x1, y1, x2, y2;
|
|
|
|
gdouble x1_f, y1_f, x2_f, y2_f;
|
2001-11-11 07:03:22 +08:00
|
|
|
|
2019-09-04 20:50:29 +08:00
|
|
|
if (! gegl_rectangle_intersect (&rect,
|
|
|
|
&private->bounding_box,
|
|
|
|
GEGL_RECTANGLE (x, y, w, h)))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2001-11-11 07:03:22 +08:00
|
|
|
|
|
|
|
/* display the area */
|
2013-04-19 22:22:19 +08:00
|
|
|
gimp_display_shell_transform_bounds (shell,
|
2019-09-04 20:50:29 +08:00
|
|
|
rect.x,
|
|
|
|
rect.y,
|
|
|
|
rect.x + rect.width,
|
|
|
|
rect.y + rect.height,
|
2013-04-19 22:22:19 +08:00
|
|
|
&x1_f, &y1_f, &x2_f, &y2_f);
|
2001-11-11 07:03:22 +08:00
|
|
|
|
2003-11-21 02:08:01 +08:00
|
|
|
/* make sure to expose a superset of the transformed sub-pixel expose
|
|
|
|
* area, not a subset. bug #126942. --mitch
|
2007-09-24 02:21:08 +08:00
|
|
|
*
|
2013-01-27 23:52:38 +08:00
|
|
|
* also accommodate for spill introduced by potential box filtering.
|
2007-09-24 02:21:08 +08:00
|
|
|
* (bug #474509). --simon
|
2003-11-21 02:08:01 +08:00
|
|
|
*/
|
2007-09-24 02:21:08 +08:00
|
|
|
x1 = floor (x1_f - 0.5);
|
|
|
|
y1 = floor (y1_f - 0.5);
|
|
|
|
x2 = ceil (x2_f + 0.5);
|
|
|
|
y2 = ceil (y2_f + 0.5);
|
2003-11-21 02:08:01 +08:00
|
|
|
|
2018-04-08 21:16:53 +08:00
|
|
|
/* align transformed area to a coarse grid, to simplify the
|
|
|
|
* invalidated area
|
|
|
|
*/
|
|
|
|
x1 = floor ((gdouble) x1 / PAINT_AREA_CHUNK_WIDTH) * PAINT_AREA_CHUNK_WIDTH;
|
|
|
|
y1 = floor ((gdouble) y1 / PAINT_AREA_CHUNK_HEIGHT) * PAINT_AREA_CHUNK_HEIGHT;
|
|
|
|
x2 = ceil ((gdouble) x2 / PAINT_AREA_CHUNK_WIDTH) * PAINT_AREA_CHUNK_WIDTH;
|
|
|
|
y2 = ceil ((gdouble) y2 / PAINT_AREA_CHUNK_HEIGHT) * PAINT_AREA_CHUNK_HEIGHT;
|
|
|
|
|
2003-11-21 02:08:01 +08:00
|
|
|
gimp_display_shell_expose_area (shell, x1, y1, x2 - x1, y2 - y1);
|
2019-07-16 05:24:35 +08:00
|
|
|
|
|
|
|
gimp_display_shell_render_invalidate_area (shell, x1, y1, x2 - x1, y2 - y1);
|
2001-06-18 21:10:03 +08:00
|
|
|
}
|