2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
1998-04-20 11:21:31 +08:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2015-11-08 05:21:53 +08:00
|
|
|
* Screenshot plug-in
|
|
|
|
* Copyright 1998-2007 Sven Neumann <sven@gimp.org>
|
|
|
|
* Copyright 2003 Henrik Brix Andersen <brix@gimp.org>
|
|
|
|
* Copyright 2012 Simone Karin Lehmann - OS X patches
|
2016-04-03 03:44:09 +08:00
|
|
|
* Copyright 2016 Michael Natterer <mitch@gimp.org>
|
2015-11-08 05:21:53 +08:00
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
1998-04-20 11:21:31 +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
|
1998-04-20 11:21:31 +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/>.
|
1998-04-20 11:21:31 +08:00
|
|
|
*/
|
|
|
|
|
2000-01-08 23:23:28 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <libgimp/gimp.h>
|
|
|
|
#include <libgimp/gimpui.h>
|
|
|
|
|
2015-11-08 05:21:53 +08:00
|
|
|
#include "screenshot.h"
|
plug-ins: implementation of the Freedesktop portal for screenshot.
I am told by the GNOME/Flatpak people that this is what we will
ultimately need to implement. Basically this portal is supposed to work
everywhere, in sandboxes (Flatpak, hopefully Snap too?), but also out
of sandboxes, i.e. in GNOME and KDE, whether Wayland or X11. So that
should be the unique API we will have to implement in the end, and every
desktop environment/sandbox will need to implement this API (which is
good!).
Apparently it is not part of default GNOME yet, but has to be installed
separately (on Fedora, package is xdg-desktop-portal-gtk for GNOME and
xdg-desktop-portal-kde for KDE).
Now there are currently many shortcomings, and in particular, the
screenshot API has apparently no advanced features (at all!). No window
snap, no rectangular selection, no delaying, no choice on including
cursor or decoration, nothing! Apparently this is normal that the API
presents no feature, because "the API itself is not meant to specify the
details how the screenshot is obtained. Instead the portal will present
the user a dialog to take a screenshot, and that screenshot will be
given back to the sandboxed app".
This is acceptable behavior, except that currently, the dialog has none
of the basic features so this is a very bad regression. This is why I
test the freedesktop API last, which basically means it will likely
never be actually used. That's on purpose. At least, the code is in and
will be easy to improve later. Of course, when the Freedesktop portal
for screenshot will finally be featureful, it is meant to be tested
first.
See: https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.Screenshot.xml
2017-12-16 09:15:57 +08:00
|
|
|
#include "screenshot-freedesktop.h"
|
2016-04-02 21:02:00 +08:00
|
|
|
#include "screenshot-osx.h"
|
2015-11-08 05:21:53 +08:00
|
|
|
#include "screenshot-x11.h"
|
2016-04-02 21:02:00 +08:00
|
|
|
#include "screenshot-win32.h"
|
2003-08-29 04:23:09 +08:00
|
|
|
|
1999-11-23 06:38:02 +08:00
|
|
|
#include "libgimp/stdplugins-intl.h"
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2000-05-02 04:22:55 +08:00
|
|
|
|
1998-04-20 11:21:31 +08:00
|
|
|
/* Defines */
|
2016-03-30 04:06:31 +08:00
|
|
|
|
2005-08-16 03:39:02 +08:00
|
|
|
#define PLUG_IN_PROC "plug-in-screenshot"
|
|
|
|
#define PLUG_IN_BINARY "screenshot"
|
2011-04-09 02:31:34 +08:00
|
|
|
#define PLUG_IN_ROLE "gimp-screenshot"
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2019-08-15 17:48:05 +08:00
|
|
|
typedef struct _Screenshot Screenshot;
|
|
|
|
typedef struct _ScreenshotClass ScreenshotClass;
|
|
|
|
|
|
|
|
struct _Screenshot
|
|
|
|
{
|
|
|
|
GimpPlugIn parent_instance;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _ScreenshotClass
|
|
|
|
{
|
|
|
|
GimpPlugInClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define SCREENSHOT_TYPE (screenshot_get_type ())
|
2023-10-19 00:29:37 +08:00
|
|
|
#define SCREENSHOT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SCREENSHOT_TYPE, Screenshot))
|
2019-08-15 17:48:05 +08:00
|
|
|
|
|
|
|
GType screenshot_get_type (void) G_GNUC_CONST;
|
|
|
|
|
|
|
|
static GList * screenshot_query_procedures (GimpPlugIn *plug_in);
|
|
|
|
static GimpProcedure * screenshot_create_procedure (GimpPlugIn *plug_in,
|
|
|
|
const gchar *name);
|
|
|
|
|
|
|
|
static GimpValueArray * screenshot_run (GimpProcedure *procedure,
|
2023-06-15 10:12:45 +08:00
|
|
|
GimpProcedureConfig *config,
|
2019-08-15 17:48:05 +08:00
|
|
|
gpointer run_data);
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
static GimpPDBStatusType shoot (GdkMonitor *monitor,
|
|
|
|
GimpImage **image,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
GError **error);
|
2003-08-29 04:23:09 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
static gboolean shoot_dialog (GimpProcedure *procedure,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
GdkMonitor **monitor);
|
|
|
|
static gboolean shoot_quit_timeout (gpointer data);
|
|
|
|
static gboolean shoot_delay_timeout (gpointer data);
|
2000-05-02 04:22:55 +08:00
|
|
|
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2019-08-15 17:48:05 +08:00
|
|
|
G_DEFINE_TYPE (Screenshot, screenshot, GIMP_TYPE_PLUG_IN)
|
|
|
|
|
|
|
|
GIMP_MAIN (SCREENSHOT_TYPE)
|
2022-05-26 06:59:36 +08:00
|
|
|
DEFINE_STD_SET_I18N
|
2019-08-15 17:48:05 +08:00
|
|
|
|
2015-11-08 05:21:53 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
static ScreenshotBackend backend = SCREENSHOT_BACKEND_NONE;
|
|
|
|
static ScreenshotCapabilities capabilities = 0;
|
2019-08-15 17:48:05 +08:00
|
|
|
|
|
|
|
static void
|
|
|
|
screenshot_class_init (ScreenshotClass *klass)
|
1998-04-20 11:21:31 +08:00
|
|
|
{
|
2019-08-15 17:48:05 +08:00
|
|
|
GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2019-08-15 17:48:05 +08:00
|
|
|
plug_in_class->query_procedures = screenshot_query_procedures;
|
|
|
|
plug_in_class->create_procedure = screenshot_create_procedure;
|
2022-05-26 06:59:36 +08:00
|
|
|
plug_in_class->set_i18n = STD_SET_I18N;
|
2019-08-15 17:48:05 +08:00
|
|
|
}
|
2000-10-30 02:07:07 +08:00
|
|
|
|
2019-08-15 17:48:05 +08:00
|
|
|
static void
|
|
|
|
screenshot_init (Screenshot *screenshot)
|
|
|
|
{
|
|
|
|
}
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2019-08-15 17:48:05 +08:00
|
|
|
static GList *
|
|
|
|
screenshot_query_procedures (GimpPlugIn *plug_in)
|
|
|
|
{
|
|
|
|
return g_list_append (NULL, g_strdup (PLUG_IN_PROC));
|
|
|
|
}
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2019-08-15 17:48:05 +08:00
|
|
|
static GimpProcedure *
|
|
|
|
screenshot_create_procedure (GimpPlugIn *plug_in,
|
2023-06-15 10:12:45 +08:00
|
|
|
const gchar *name)
|
1998-04-20 11:21:31 +08:00
|
|
|
{
|
2019-08-15 17:48:05 +08:00
|
|
|
GimpProcedure *procedure = NULL;
|
|
|
|
|
|
|
|
if (! strcmp (name, PLUG_IN_PROC))
|
|
|
|
{
|
2023-06-17 00:34:53 +08:00
|
|
|
procedure = gimp_procedure_new (plug_in, name,
|
|
|
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
|
|
|
screenshot_run, NULL, NULL);
|
2019-08-15 17:48:05 +08:00
|
|
|
|
2022-07-05 04:50:53 +08:00
|
|
|
gimp_procedure_set_menu_label (procedure, _("_Screenshot..."));
|
2023-02-22 22:10:40 +08:00
|
|
|
gimp_procedure_add_menu_path (procedure, "<Image>/File/Create");
|
2019-08-15 17:48:05 +08:00
|
|
|
|
|
|
|
gimp_procedure_set_documentation
|
|
|
|
(procedure,
|
2022-07-05 04:50:53 +08:00
|
|
|
_("Create an image from an area of the screen"),
|
2024-07-27 02:56:53 +08:00
|
|
|
"The plug-in takes screenshots of an "
|
|
|
|
"interactively selected window or of the desktop, "
|
|
|
|
"either the whole desktop or an interactively "
|
|
|
|
"selected region. When called non-interactively, it "
|
|
|
|
"may grab the root window or use the window-id "
|
|
|
|
"passed as a parameter. The last four parameters "
|
|
|
|
"are optional and can be used to specify the corners "
|
|
|
|
"of the region to be grabbed."
|
|
|
|
"On Mac OS X, "
|
|
|
|
"when called non-interactively, the plug-in"
|
|
|
|
"only can take screenshots of the entire root window."
|
|
|
|
"Grabbing a window or a region is not supported"
|
|
|
|
"non-interactively. To grab a region or a particular"
|
|
|
|
"window, you need to use the interactive mode.",
|
2019-08-15 17:48:05 +08:00
|
|
|
name);
|
|
|
|
|
|
|
|
gimp_procedure_set_attribution (procedure,
|
|
|
|
"Sven Neumann <sven@gimp.org>, "
|
|
|
|
"Henrik Brix Andersen <brix@gimp.org>,"
|
|
|
|
"Simone Karin Lehmann",
|
|
|
|
"1998 - 2008",
|
|
|
|
"v1.1 (2008/04)");
|
|
|
|
|
|
|
|
gimp_procedure_set_icon_pixbuf (procedure,
|
2023-05-21 19:22:57 +08:00
|
|
|
gdk_pixbuf_new_from_resource ("/org/gimp/screenshot-icons/screenshot-icon.png", NULL));
|
2019-08-15 17:48:05 +08:00
|
|
|
|
2024-06-13 00:53:12 +08:00
|
|
|
gimp_procedure_add_enum_argument (procedure, "run-mode",
|
|
|
|
"Run mode",
|
|
|
|
"The run mode",
|
|
|
|
GIMP_TYPE_RUN_MODE,
|
|
|
|
GIMP_RUN_NONINTERACTIVE,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
2024-07-27 02:56:53 +08:00
|
|
|
/* TODO: Windows does not currently implement selecting by region to grab,
|
|
|
|
* so we'll hide this option for now */
|
|
|
|
gimp_procedure_add_choice_argument (procedure, "shoot-type",
|
|
|
|
_("Shoot _area"),
|
|
|
|
_("The shoot type"),
|
|
|
|
gimp_choice_new_with_values ("window", SHOOT_WINDOW, _("Take a screenshot of a single window"), NULL,
|
|
|
|
"screen", SHOOT_ROOT, _("Take a screenshot of the entire screen"), NULL,
|
|
|
|
#ifndef G_OS_WIN32
|
|
|
|
"region", SHOOT_REGION, _("Select a region to grab"), NULL,
|
|
|
|
#endif
|
|
|
|
NULL),
|
|
|
|
"window",
|
|
|
|
G_PARAM_READWRITE);
|
2024-06-13 00:53:12 +08:00
|
|
|
|
|
|
|
gimp_procedure_add_int_argument (procedure, "x1",
|
|
|
|
"X1",
|
|
|
|
"Region left x coord for SHOOT-WINDOW",
|
|
|
|
G_MININT, G_MAXINT, 0,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_int_argument (procedure, "y1",
|
|
|
|
"Y1",
|
|
|
|
"Region top y coord for SHOOT-WINDOW",
|
|
|
|
G_MININT, G_MAXINT, 0,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_int_argument (procedure, "x2",
|
|
|
|
"X2",
|
|
|
|
"Region right x coord for SHOOT-WINDOW",
|
|
|
|
G_MININT, G_MAXINT, 0,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_int_argument (procedure, "y2",
|
|
|
|
"Y2",
|
|
|
|
"Region bottom y coord for SHOOT-WINDOW",
|
|
|
|
G_MININT, G_MAXINT, 0,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_boolean_argument (procedure, "include-pointer",
|
|
|
|
_("Include _mouse pointer"),
|
|
|
|
_("Your pointing device's cursor will be part of the image"),
|
|
|
|
FALSE,
|
|
|
|
G_PARAM_READWRITE);
|
2023-06-15 10:12:45 +08:00
|
|
|
|
|
|
|
/* Since no backends allow window screenshot non-interactively so far, no
|
|
|
|
* need to expose this argument to the API.
|
|
|
|
*/
|
2024-06-13 00:53:12 +08:00
|
|
|
gimp_procedure_add_boolean_aux_argument (procedure, "include-decoration",
|
|
|
|
_("Include window _decoration"),
|
|
|
|
_("Title bar, window borders and shadow will be part of the image"),
|
2023-06-15 10:12:45 +08:00
|
|
|
#ifdef PLATFORM_OSX
|
|
|
|
/* on OS X, this just means shoot the shadow, default to nope */
|
|
|
|
FALSE,
|
|
|
|
#else
|
|
|
|
TRUE,
|
|
|
|
#endif
|
|
|
|
G_PARAM_READWRITE);
|
2024-06-13 00:53:12 +08:00
|
|
|
gimp_procedure_add_int_aux_argument (procedure, "selection-delay",
|
|
|
|
_("Selection d_elay"),
|
|
|
|
_("Delay before selection of the window or the region"),
|
|
|
|
0, 20, 0,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
gimp_procedure_add_int_aux_argument (procedure, "screenshot-delay",
|
|
|
|
_("Screenshot dela_y"),
|
|
|
|
_("Delay before snapping the screenshot"),
|
|
|
|
0, 20, 0,
|
|
|
|
G_PARAM_READWRITE);
|
2024-07-27 02:56:53 +08:00
|
|
|
gimp_procedure_add_choice_argument (procedure, "color-profile",
|
|
|
|
_("Color _Profile"),
|
|
|
|
"",
|
|
|
|
gimp_choice_new_with_values ("monitor", SCREENSHOT_PROFILE_POLICY_MONITOR, _("Tag image with monitor profile"), NULL,
|
|
|
|
"srgb", SCREENSHOT_PROFILE_POLICY_SRGB, _("Convert image with sRGB"), NULL,
|
|
|
|
NULL),
|
|
|
|
"monitor",
|
|
|
|
G_PARAM_READWRITE);
|
2024-06-13 00:53:12 +08:00
|
|
|
|
|
|
|
gimp_procedure_add_image_return_value (procedure, "image",
|
|
|
|
"Image",
|
|
|
|
"Output image",
|
|
|
|
FALSE,
|
|
|
|
G_PARAM_READWRITE);
|
2019-08-15 17:48:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return procedure;
|
1998-04-20 11:21:31 +08:00
|
|
|
}
|
|
|
|
|
2019-08-15 17:48:05 +08:00
|
|
|
static GimpValueArray *
|
|
|
|
screenshot_run (GimpProcedure *procedure,
|
2023-06-15 10:12:45 +08:00
|
|
|
GimpProcedureConfig *config,
|
2019-08-15 17:48:05 +08:00
|
|
|
gpointer run_data)
|
1998-04-20 11:21:31 +08:00
|
|
|
{
|
2019-08-15 17:48:05 +08:00
|
|
|
GimpValueArray *return_vals;
|
2016-04-02 07:28:34 +08:00
|
|
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
2012-11-28 03:58:05 +08:00
|
|
|
GimpRunMode run_mode;
|
2018-04-29 23:27:47 +08:00
|
|
|
GdkMonitor *monitor = NULL;
|
2019-08-16 17:54:50 +08:00
|
|
|
GimpImage *image = NULL;
|
|
|
|
GError *error = NULL;
|
2000-05-02 04:22:55 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
ShootType shoot_type;
|
|
|
|
ScreenshotProfilePolicy profile_policy;
|
|
|
|
|
2012-11-28 03:58:05 +08:00
|
|
|
gegl_init (NULL, NULL);
|
2000-05-02 04:22:55 +08:00
|
|
|
|
2024-07-27 02:56:53 +08:00
|
|
|
g_object_get (config, "run-mode", &run_mode, NULL);
|
|
|
|
shoot_type = gimp_procedure_config_get_choice_id (GIMP_PROCEDURE_CONFIG (config),
|
|
|
|
"shoot-type");
|
2023-06-15 10:12:45 +08:00
|
|
|
|
|
|
|
if (! gdk_init_check (NULL, NULL))
|
|
|
|
{
|
|
|
|
g_set_error_literal (&error, GIMP_PLUG_IN_ERROR, 0, _("GDK initialization failed."));
|
|
|
|
return gimp_procedure_new_return_values (procedure,
|
|
|
|
GIMP_PDB_EXECUTION_ERROR,
|
|
|
|
error);
|
|
|
|
}
|
2012-05-08 07:44:13 +08:00
|
|
|
|
2015-11-08 05:21:53 +08:00
|
|
|
#ifdef PLATFORM_OSX
|
2016-03-30 04:06:31 +08:00
|
|
|
if (! backend && screenshot_osx_available ())
|
|
|
|
{
|
|
|
|
backend = SCREENSHOT_BACKEND_OSX;
|
|
|
|
capabilities = screenshot_osx_get_capabilities ();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-04-02 21:02:00 +08:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
if (! backend && screenshot_win32_available ())
|
|
|
|
{
|
|
|
|
backend = SCREENSHOT_BACKEND_WIN32;
|
|
|
|
capabilities = screenshot_win32_get_capabilities ();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-03-30 04:06:31 +08:00
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
if (! backend && screenshot_x11_available ())
|
|
|
|
{
|
|
|
|
backend = SCREENSHOT_BACKEND_X11;
|
|
|
|
capabilities = screenshot_x11_get_capabilities ();
|
|
|
|
}
|
2015-11-08 05:21:53 +08:00
|
|
|
#endif
|
plug-ins: remove KDE screenshot portal in favor of Freedesktop portal.
On recent KDE, the screenshot plug-in fails with an authorization error,
unless we add a desktop file with a special KDE-only desktop entry to
give the permission, which seems a bit over-the-top (if we were to add a
desktop file for every plug-in, and with dedicated entries to every
desktop environment out there, it's never-ending). Of course, we are not
against either, but nobody has contributed a patch doing this in the
last year anyway.
Also Méven (KDE dev) was telling us that KDE recommends to use the
Freedesktop portal nowadays. So maybe let's just move on from the
KDE-specific portal, just as we did recently for the GNOME portal too.
This should hopefully take care of all permission issues and in the same
time simplifies the code.
Note that the Freedesktop API might miss some of the features (this was
one of the reason we were avoiding putting it as priority implementation
until now, to avoid feature regression), but the more we go, the less we
have a choice. It's either this or always fighting against the current.
2021-12-18 02:37:35 +08:00
|
|
|
if (! backend && screenshot_freedesktop_available ())
|
plug-ins: implementation of the Freedesktop portal for screenshot.
I am told by the GNOME/Flatpak people that this is what we will
ultimately need to implement. Basically this portal is supposed to work
everywhere, in sandboxes (Flatpak, hopefully Snap too?), but also out
of sandboxes, i.e. in GNOME and KDE, whether Wayland or X11. So that
should be the unique API we will have to implement in the end, and every
desktop environment/sandbox will need to implement this API (which is
good!).
Apparently it is not part of default GNOME yet, but has to be installed
separately (on Fedora, package is xdg-desktop-portal-gtk for GNOME and
xdg-desktop-portal-kde for KDE).
Now there are currently many shortcomings, and in particular, the
screenshot API has apparently no advanced features (at all!). No window
snap, no rectangular selection, no delaying, no choice on including
cursor or decoration, nothing! Apparently this is normal that the API
presents no feature, because "the API itself is not meant to specify the
details how the screenshot is obtained. Instead the portal will present
the user a dialog to take a screenshot, and that screenshot will be
given back to the sandboxed app".
This is acceptable behavior, except that currently, the dialog has none
of the basic features so this is a very bad regression. This is why I
test the freedesktop API last, which basically means it will likely
never be actually used. That's on purpose. At least, the code is in and
will be easy to improve later. Of course, when the Freedesktop portal
for screenshot will finally be featureful, it is meant to be tested
first.
See: https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.Screenshot.xml
2017-12-16 09:15:57 +08:00
|
|
|
{
|
|
|
|
backend = SCREENSHOT_BACKEND_FREEDESKTOP;
|
|
|
|
capabilities = screenshot_freedesktop_get_capabilities ();
|
|
|
|
}
|
2015-11-08 05:21:53 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
if (backend == SCREENSHOT_BACKEND_NONE)
|
|
|
|
{
|
|
|
|
g_set_error_literal (&error, GIMP_PLUG_IN_ERROR, 0,
|
|
|
|
_("No screenshot backends available."));
|
|
|
|
return gimp_procedure_new_return_values (procedure,
|
|
|
|
GIMP_PDB_EXECUTION_ERROR,
|
|
|
|
error);
|
|
|
|
}
|
2000-05-02 04:22:55 +08:00
|
|
|
/* how are we running today? */
|
1998-04-20 11:21:31 +08:00
|
|
|
switch (run_mode)
|
2000-05-02 04:22:55 +08:00
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RUN_INTERACTIVE:
|
2023-06-15 10:12:45 +08:00
|
|
|
gimp_ui_init (PLUG_IN_BINARY);
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
/* In interactive mode, coords are always reset. */
|
|
|
|
g_object_set (config,
|
|
|
|
"x1", 0, "y1", 0,
|
|
|
|
"x2", 0, "y2", 0,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if ((shoot_type == SHOOT_WINDOW &&
|
2017-12-17 04:54:49 +08:00
|
|
|
! (capabilities & SCREENSHOT_CAN_SHOOT_WINDOW)) ||
|
2023-06-15 10:12:45 +08:00
|
|
|
(shoot_type == SHOOT_REGION &&
|
2017-12-17 04:54:49 +08:00
|
|
|
! (capabilities & SCREENSHOT_CAN_SHOOT_REGION)))
|
|
|
|
{
|
|
|
|
/* Shoot root is the only type of shoot which is definitely
|
|
|
|
* shared by all screenshot backends (basically just snap the
|
|
|
|
* whole display setup).
|
|
|
|
*/
|
2024-07-27 02:56:53 +08:00
|
|
|
g_object_set (config, "shoot-type", "screen", NULL);
|
2017-12-17 04:54:49 +08:00
|
|
|
}
|
|
|
|
|
2020-12-31 00:21:43 +08:00
|
|
|
/* Get information from the dialog. Freedesktop portal comes with
|
|
|
|
* its own dialog.
|
|
|
|
*/
|
|
|
|
if (backend != SCREENSHOT_BACKEND_FREEDESKTOP)
|
|
|
|
{
|
2023-06-15 10:12:45 +08:00
|
|
|
if (! shoot_dialog (procedure, config, &monitor))
|
2020-12-31 00:21:43 +08:00
|
|
|
status = GIMP_PDB_CANCEL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* This is ugly but in reality we have no idea on which monitor
|
|
|
|
* a screenshot was taken from with portals. It's like a
|
|
|
|
* better-than-nothing trick for easy single-display cases.
|
|
|
|
*/
|
|
|
|
monitor = gdk_display_get_monitor (gdk_display_get_default (), 0);
|
|
|
|
}
|
1998-04-20 11:21:31 +08:00
|
|
|
break;
|
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RUN_NONINTERACTIVE:
|
2023-06-15 10:12:45 +08:00
|
|
|
if (backend == SCREENSHOT_BACKEND_FREEDESKTOP)
|
2008-10-20 14:04:39 +08:00
|
|
|
{
|
2023-06-15 10:12:45 +08:00
|
|
|
/* With portals, even the basic full screenshot is interactive. */
|
|
|
|
status = GIMP_PDB_CALLING_ERROR;
|
|
|
|
}
|
|
|
|
else if (! (capabilities & SCREENSHOT_CAN_PICK_NONINTERACTIVELY))
|
|
|
|
{
|
|
|
|
if (shoot_type == SHOOT_WINDOW ||
|
|
|
|
shoot_type == SHOOT_REGION)
|
|
|
|
status = GIMP_PDB_CALLING_ERROR;
|
2005-03-23 05:29:04 +08:00
|
|
|
}
|
2019-08-15 17:48:05 +08:00
|
|
|
break;
|
2000-05-02 04:22:55 +08:00
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RUN_WITH_LAST_VALS:
|
1998-04-20 11:21:31 +08:00
|
|
|
break;
|
2000-05-02 04:22:55 +08:00
|
|
|
|
1998-04-20 11:21:31 +08:00
|
|
|
default:
|
|
|
|
break;
|
2000-05-02 04:22:55 +08:00
|
|
|
}
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2006-06-18 17:44:43 +08:00
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
2023-06-15 10:12:45 +08:00
|
|
|
status = shoot (monitor, &image, config, &error);
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
2000-05-02 04:22:55 +08:00
|
|
|
{
|
2016-06-01 04:29:49 +08:00
|
|
|
gchar *comment = gimp_get_default_comment ();
|
|
|
|
|
2020-02-17 05:01:49 +08:00
|
|
|
gimp_image_undo_disable (image);
|
|
|
|
|
2024-07-27 02:56:53 +08:00
|
|
|
profile_policy = gimp_procedure_config_get_choice_id (GIMP_PROCEDURE_CONFIG (config),
|
|
|
|
"color-profile");
|
2023-06-15 10:12:45 +08:00
|
|
|
|
|
|
|
if (run_mode == GIMP_RUN_NONINTERACTIVE)
|
|
|
|
profile_policy = SCREENSHOT_PROFILE_POLICY_MONITOR;
|
|
|
|
|
|
|
|
if (profile_policy == SCREENSHOT_PROFILE_POLICY_SRGB)
|
2017-02-01 04:26:44 +08:00
|
|
|
{
|
|
|
|
GimpColorProfile *srgb_profile = gimp_color_profile_new_rgb_srgb ();
|
|
|
|
|
2019-08-16 17:54:50 +08:00
|
|
|
gimp_image_convert_color_profile (image,
|
2017-02-01 04:26:44 +08:00
|
|
|
srgb_profile,
|
|
|
|
GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
|
|
|
|
TRUE);
|
|
|
|
g_object_unref (srgb_profile);
|
|
|
|
}
|
|
|
|
|
2016-06-01 04:29:49 +08:00
|
|
|
if (comment)
|
|
|
|
{
|
|
|
|
GimpParasite *parasite;
|
|
|
|
|
|
|
|
parasite = gimp_parasite_new ("gimp-comment",
|
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
strlen (comment) + 1, comment);
|
|
|
|
|
2019-08-16 17:54:50 +08:00
|
|
|
gimp_image_attach_parasite (image, parasite);
|
2016-06-01 04:29:49 +08:00
|
|
|
gimp_parasite_free (parasite);
|
|
|
|
|
|
|
|
g_free (comment);
|
|
|
|
}
|
|
|
|
|
2020-02-17 05:01:49 +08:00
|
|
|
gimp_image_undo_enable (image);
|
2016-06-01 04:29:49 +08:00
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
if (run_mode == GIMP_RUN_INTERACTIVE)
|
2008-10-20 14:04:39 +08:00
|
|
|
{
|
2023-06-15 10:12:45 +08:00
|
|
|
guint select_delay;
|
2005-03-23 05:29:04 +08:00
|
|
|
|
2019-08-16 17:54:50 +08:00
|
|
|
gimp_display_new (image);
|
2012-05-07 08:18:32 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
g_object_get (config,
|
|
|
|
"selection-delay", &select_delay,
|
|
|
|
NULL);
|
2012-05-07 08:18:32 +08:00
|
|
|
/* Give some sort of feedback that the shot is done */
|
2023-06-15 10:12:45 +08:00
|
|
|
if (select_delay > 0)
|
2012-05-07 08:18:32 +08:00
|
|
|
{
|
2018-04-29 23:27:47 +08:00
|
|
|
gdk_display_beep (gdk_monitor_get_display (monitor));
|
2018-05-08 06:54:02 +08:00
|
|
|
/* flush so the beep makes it to the server */
|
|
|
|
gdk_display_flush (gdk_monitor_get_display (monitor));
|
2012-05-07 08:18:32 +08:00
|
|
|
}
|
2008-10-20 14:04:39 +08:00
|
|
|
}
|
2000-05-02 04:22:55 +08:00
|
|
|
}
|
2000-10-30 02:07:07 +08:00
|
|
|
|
2019-08-15 17:48:05 +08:00
|
|
|
return_vals = gimp_procedure_new_return_values (procedure, status, error);
|
|
|
|
|
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
2019-08-16 17:54:50 +08:00
|
|
|
GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
|
2016-04-02 07:28:34 +08:00
|
|
|
|
2019-08-15 17:48:05 +08:00
|
|
|
return return_vals;
|
1998-04-20 11:21:31 +08:00
|
|
|
}
|
|
|
|
|
2005-03-23 05:29:04 +08:00
|
|
|
|
2005-06-15 02:25:33 +08:00
|
|
|
/* The main Screenshot function */
|
2003-08-29 04:23:09 +08:00
|
|
|
|
2015-11-08 05:21:53 +08:00
|
|
|
static GimpPDBStatusType
|
2023-06-15 10:12:45 +08:00
|
|
|
shoot (GdkMonitor *monitor,
|
|
|
|
GimpImage **image,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
GError **error)
|
2012-10-14 23:03:24 +08:00
|
|
|
{
|
2024-08-25 21:31:31 +08:00
|
|
|
#if defined(PLATFORM_OSX) || defined(G_OS_WIN32)
|
2023-06-15 10:12:45 +08:00
|
|
|
ShootType shoot_type;
|
2024-08-25 21:31:31 +08:00
|
|
|
#endif
|
2023-06-15 10:12:45 +08:00
|
|
|
gboolean decorate;
|
|
|
|
guint select_delay;
|
|
|
|
guint screenshot_delay;
|
|
|
|
gboolean show_cursor;
|
|
|
|
|
|
|
|
g_object_get (config,
|
|
|
|
"screenshot-delay", &screenshot_delay,
|
|
|
|
"selection-delay", &select_delay,
|
|
|
|
"include-decoration", &decorate,
|
|
|
|
"include-pointer", &show_cursor,
|
|
|
|
NULL);
|
2024-08-25 21:31:31 +08:00
|
|
|
#if defined(PLATFORM_OSX) || defined(G_OS_WIN32)
|
2024-07-27 02:56:53 +08:00
|
|
|
shoot_type = gimp_procedure_config_get_choice_id (GIMP_PROCEDURE_CONFIG (config),
|
|
|
|
"shoot-type");
|
2024-08-25 21:31:31 +08:00
|
|
|
#endif
|
2023-06-15 10:12:45 +08:00
|
|
|
|
2012-10-14 23:03:24 +08:00
|
|
|
#ifdef PLATFORM_OSX
|
2016-03-30 04:06:31 +08:00
|
|
|
if (backend == SCREENSHOT_BACKEND_OSX)
|
2023-06-15 10:12:45 +08:00
|
|
|
return screenshot_osx_shoot (shoot_type,
|
|
|
|
select_delay, screenshot_delay,
|
|
|
|
decorate, show_cursor,
|
|
|
|
image, error);
|
2012-10-14 23:03:24 +08:00
|
|
|
#endif
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2016-04-02 21:02:00 +08:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
if (backend == SCREENSHOT_BACKEND_WIN32)
|
2023-06-15 10:12:45 +08:00
|
|
|
return screenshot_win32_shoot (shoot_type, screenshot_delay, show_cursor,
|
|
|
|
monitor, image, error);
|
2016-04-02 21:02:00 +08:00
|
|
|
#endif
|
|
|
|
|
plug-ins: implementation of the Freedesktop portal for screenshot.
I am told by the GNOME/Flatpak people that this is what we will
ultimately need to implement. Basically this portal is supposed to work
everywhere, in sandboxes (Flatpak, hopefully Snap too?), but also out
of sandboxes, i.e. in GNOME and KDE, whether Wayland or X11. So that
should be the unique API we will have to implement in the end, and every
desktop environment/sandbox will need to implement this API (which is
good!).
Apparently it is not part of default GNOME yet, but has to be installed
separately (on Fedora, package is xdg-desktop-portal-gtk for GNOME and
xdg-desktop-portal-kde for KDE).
Now there are currently many shortcomings, and in particular, the
screenshot API has apparently no advanced features (at all!). No window
snap, no rectangular selection, no delaying, no choice on including
cursor or decoration, nothing! Apparently this is normal that the API
presents no feature, because "the API itself is not meant to specify the
details how the screenshot is obtained. Instead the portal will present
the user a dialog to take a screenshot, and that screenshot will be
given back to the sandboxed app".
This is acceptable behavior, except that currently, the dialog has none
of the basic features so this is a very bad regression. This is why I
test the freedesktop API last, which basically means it will likely
never be actually used. That's on purpose. At least, the code is in and
will be easy to improve later. Of course, when the Freedesktop portal
for screenshot will finally be featureful, it is meant to be tested
first.
See: https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.Screenshot.xml
2017-12-16 09:15:57 +08:00
|
|
|
if (backend == SCREENSHOT_BACKEND_FREEDESKTOP)
|
2023-06-15 10:12:45 +08:00
|
|
|
return screenshot_freedesktop_shoot (monitor, image, error);
|
2016-03-30 04:06:31 +08:00
|
|
|
|
2015-11-08 05:21:53 +08:00
|
|
|
#ifdef GDK_WINDOWING_X11
|
2016-03-30 04:06:31 +08:00
|
|
|
if (backend == SCREENSHOT_BACKEND_X11)
|
2023-06-15 10:12:45 +08:00
|
|
|
return screenshot_x11_shoot (config, monitor, image, error);
|
2015-11-08 05:21:53 +08:00
|
|
|
#endif
|
2012-10-14 23:03:24 +08:00
|
|
|
|
2015-11-08 05:21:53 +08:00
|
|
|
return GIMP_PDB_CALLING_ERROR; /* silence compiler */
|
2012-10-14 23:03:24 +08:00
|
|
|
}
|
2012-10-17 17:53:45 +08:00
|
|
|
|
2012-10-14 23:03:24 +08:00
|
|
|
|
2005-06-15 02:25:33 +08:00
|
|
|
/* Screenshot dialog */
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
static gboolean
|
|
|
|
shoot_dialog (GimpProcedure *procedure,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
GdkMonitor **monitor)
|
2007-02-15 22:38:46 +08:00
|
|
|
{
|
2023-06-15 10:12:45 +08:00
|
|
|
GtkWidget *dialog;
|
|
|
|
GimpValueArray *values;
|
|
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
gboolean run;
|
|
|
|
|
|
|
|
dialog = gimp_procedure_dialog_new (procedure,
|
|
|
|
GIMP_PROCEDURE_CONFIG (config),
|
|
|
|
_("Screenshot"));
|
|
|
|
gimp_procedure_dialog_set_ok_label (GIMP_PROCEDURE_DIALOG (dialog), _("S_nap"));
|
|
|
|
|
|
|
|
if (capabilities & SCREENSHOT_CAN_SHOOT_POINTER ||
|
|
|
|
capabilities & SCREENSHOT_CAN_SHOOT_DECORATIONS)
|
2017-12-10 08:30:31 +08:00
|
|
|
{
|
2023-06-15 10:12:45 +08:00
|
|
|
if (! (capabilities & SCREENSHOT_CAN_SHOOT_POINTER))
|
|
|
|
gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"contents-box",
|
|
|
|
"include-decoration",
|
|
|
|
NULL);
|
|
|
|
else if (! (capabilities & SCREENSHOT_CAN_SHOOT_DECORATIONS))
|
|
|
|
gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"contents-box",
|
|
|
|
"include-pointer",
|
|
|
|
NULL);
|
2017-12-10 08:30:31 +08:00
|
|
|
else
|
2023-06-15 10:12:45 +08:00
|
|
|
gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"contents-box",
|
|
|
|
"include-decoration",
|
|
|
|
"include-pointer",
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"contents-frame-title",
|
2023-07-18 06:06:26 +08:00
|
|
|
_("Contents"), FALSE, FALSE);
|
2023-06-15 10:12:45 +08:00
|
|
|
gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"contents-frame", "contents-frame-title",
|
|
|
|
FALSE, "contents-box");
|
2007-02-15 22:38:46 +08:00
|
|
|
|
2017-12-17 04:54:49 +08:00
|
|
|
if (capabilities & SCREENSHOT_CAN_SHOOT_DECORATIONS)
|
|
|
|
{
|
2023-06-15 10:12:45 +08:00
|
|
|
values = gimp_value_array_new (1);
|
2024-07-27 02:56:53 +08:00
|
|
|
g_value_init (&value, G_TYPE_STRING);
|
|
|
|
g_value_set_string (&value, "window");
|
2023-06-15 10:12:45 +08:00
|
|
|
gimp_value_array_append (values, &value);
|
|
|
|
g_value_unset (&value);
|
|
|
|
gimp_procedure_dialog_set_sensitive_if_in (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"include-decoration",
|
|
|
|
NULL, "shoot-type",
|
|
|
|
values, TRUE);
|
2017-12-17 04:54:49 +08:00
|
|
|
}
|
|
|
|
if (capabilities & SCREENSHOT_CAN_SHOOT_POINTER)
|
|
|
|
{
|
2023-06-15 10:12:45 +08:00
|
|
|
values = gimp_value_array_new (1);
|
2024-07-27 02:56:53 +08:00
|
|
|
g_value_init (&value, G_TYPE_STRING);
|
|
|
|
g_value_set_string (&value, "region");
|
2023-06-15 10:12:45 +08:00
|
|
|
gimp_value_array_append (values, &value);
|
|
|
|
g_value_unset (&value);
|
|
|
|
gimp_procedure_dialog_set_sensitive_if_in (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"include-pointer",
|
|
|
|
NULL, "shoot-type",
|
|
|
|
values, FALSE);
|
2017-12-17 04:54:49 +08:00
|
|
|
}
|
|
|
|
}
|
2005-12-17 01:01:44 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
if (capabilities & SCREENSHOT_CAN_DELAY_WINDOW_SHOT)
|
2015-11-08 05:21:53 +08:00
|
|
|
{
|
2023-06-15 10:12:45 +08:00
|
|
|
if (capabilities & SCREENSHOT_CAN_PICK_WINDOW)
|
2017-07-18 21:04:09 +08:00
|
|
|
{
|
2023-06-15 10:12:45 +08:00
|
|
|
gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"delay-box",
|
|
|
|
"selection-delay",
|
|
|
|
"screenshot-delay",
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
values = gimp_value_array_new (1);
|
2024-07-27 02:56:53 +08:00
|
|
|
g_value_init (&value, G_TYPE_STRING);
|
|
|
|
g_value_set_string (&value, "screen");
|
2023-06-15 10:12:45 +08:00
|
|
|
gimp_value_array_append (values, &value);
|
|
|
|
g_value_unset (&value);
|
|
|
|
gimp_procedure_dialog_set_sensitive_if_in (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"selection-delay",
|
|
|
|
NULL, "shoot-type",
|
|
|
|
values, FALSE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"delay-box", "screenshot-delay", NULL);
|
2017-07-18 21:04:09 +08:00
|
|
|
}
|
2017-12-10 07:28:22 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"delay-frame-title",
|
2023-07-18 06:06:26 +08:00
|
|
|
_("Delay"), FALSE, FALSE);
|
2023-06-15 10:12:45 +08:00
|
|
|
gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"delay-frame", "delay-frame-title",
|
|
|
|
FALSE, "delay-box");
|
2017-12-10 07:28:22 +08:00
|
|
|
}
|
2017-02-01 04:26:44 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog), "shoot-type", NULL);
|
2017-02-01 04:26:44 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
if ((capabilities & SCREENSHOT_CAN_SHOOT_POINTER) ||
|
|
|
|
(capabilities & SCREENSHOT_CAN_SHOOT_DECORATIONS))
|
|
|
|
gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog), "contents-frame", NULL);
|
2017-02-01 04:26:44 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
if (capabilities & SCREENSHOT_CAN_DELAY_WINDOW_SHOT)
|
|
|
|
gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog), "delay-frame", NULL);
|
2017-02-01 04:26:44 +08:00
|
|
|
|
2023-06-15 10:12:45 +08:00
|
|
|
gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog), "color-profile", NULL);
|
|
|
|
run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));
|
2003-11-06 23:27:05 +08:00
|
|
|
|
2024-03-07 11:14:48 +08:00
|
|
|
/* Get the screen on which we are running */
|
|
|
|
if (run)
|
|
|
|
*monitor = gimp_widget_get_monitor (dialog);
|
|
|
|
|
2003-11-06 23:27:05 +08:00
|
|
|
gtk_widget_destroy (dialog);
|
|
|
|
|
|
|
|
if (run)
|
2005-12-17 01:01:44 +08:00
|
|
|
{
|
|
|
|
/* A short timeout to give the server a chance to
|
|
|
|
* redraw the area that was obscured by our dialog.
|
|
|
|
*/
|
|
|
|
g_timeout_add (100, shoot_quit_timeout, NULL);
|
|
|
|
gtk_main ();
|
|
|
|
}
|
1998-04-20 11:21:31 +08:00
|
|
|
|
2003-11-06 23:27:05 +08:00
|
|
|
return run;
|
1998-06-05 00:17:59 +08:00
|
|
|
}
|
|
|
|
|
2005-11-30 16:01:04 +08:00
|
|
|
static gboolean
|
|
|
|
shoot_quit_timeout (gpointer data)
|
|
|
|
{
|
|
|
|
gtk_main_quit ();
|
2015-11-08 05:21:53 +08:00
|
|
|
|
2005-11-30 16:01:04 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
2016-03-30 05:34:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
shoot_delay_timeout (gpointer data)
|
|
|
|
{
|
|
|
|
gint *seconds_left = data;
|
|
|
|
|
|
|
|
(*seconds_left)--;
|
|
|
|
|
|
|
|
if (!*seconds_left)
|
|
|
|
gtk_main_quit ();
|
|
|
|
|
|
|
|
return *seconds_left;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
|
|
|
void
|
2023-06-15 10:12:45 +08:00
|
|
|
screenshot_wait_delay (gint seconds)
|
2016-03-30 05:34:51 +08:00
|
|
|
{
|
|
|
|
g_timeout_add (1000, shoot_delay_timeout, &seconds);
|
|
|
|
gtk_main ();
|
|
|
|
}
|