libgimpwidgets: Use Screenshot portal for picking

Freedesktop (XDG) portals are a collection of D-Bus APIs that work
across desktop environments, display servers and work within
containerized applications, like Flatpak. The internal implementation
can then choose to implement these in such a way that takes into account
security considerations, as well as making sure the user consents to
certain actions.

One such portal is the `Screenshot` portal, which contains a
`Screenshot()` method as well as `PickColor()`. We already use the
former for taking a screenshot, and this commit makes sure our color
picker also makes use of the latter.

By doing this, color picking is now possible on the major Wayland
compositors.

(Honestly, we should remove DE-specific backends like that of KWin, to
have less variation on the possible results of a color picking
operation).

Fixes https://gitlab.gnome.org/GNOME/gimp/-/issues/1074
This commit is contained in:
Niels De Graef 2021-12-13 09:13:19 +01:00
parent e51d5d480d
commit e82f6d5b0f
5 changed files with 208 additions and 2 deletions

View file

@ -155,7 +155,9 @@ libgimpwidgets_sources += \
gimppickbutton-default.c \
gimppickbutton-default.h \
gimppickbutton-kwin.c \
gimppickbutton-kwin.h
gimppickbutton-kwin.h \
gimppickbutton-xdg.c \
gimppickbutton-xdg.h
endif

View file

@ -0,0 +1,175 @@
/* LIBGIMP - The GIMP Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* gimppickbutton-xdg.c
* Copyright (C) 2021 Niels De Graef <nielsdegraef@gmail.com>
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
#include "libgimpcolor/gimpcolor.h"
#include "gimpwidgetstypes.h"
#include "gimppickbutton.h"
#include "gimppickbutton-default.h"
#include "gimppickbutton-xdg.h"
#include "libgimp/libgimp-intl.h"
#include "libgimp/gimpui.h"
gboolean
_gimp_pick_button_xdg_available (void)
{
GDBusProxy *proxy = NULL;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL,
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Screenshot",
NULL, NULL);
if (proxy)
{
GError *error = NULL;
g_dbus_proxy_call_sync (proxy, "org.freedesktop.DBus.Peer.Ping",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, &error);
if (! error)
return TRUE;
g_clear_error (&error);
g_object_unref (proxy);
proxy = NULL;
}
return FALSE;
}
static void
pick_color_xdg_dbus_signal (GDBusProxy *proxy,
gchar *sender_name,
gchar *signal_name,
GVariant *parameters,
GimpPickButton *button)
{
if (g_strcmp0 (signal_name, "Response") == 0)
{
GVariant *results;
guint32 response;
g_variant_get (parameters, "(u@a{sv})",
&response,
&results);
/* Possible values:
* 0: Success, the request is carried out
* 1: The user cancelled the interaction
* 2: The user interaction was ended in some other way
* Cf. https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.Request.xml
*/
if (response == 0)
{
GimpRGB color;
if (g_variant_lookup (results, "color", "(ddd)", &color.r, &color.g, &color.b))
{
g_signal_emit_by_name (button, "color-picked", &color);
}
}
g_variant_unref (results);
/* Quit anyway. */
gtk_main_quit ();
}
}
/* entry point to this file, called from gimppickbutton.c */
void
_gimp_pick_button_xdg_pick (GimpPickButton *button)
{
GDBusProxy *proxy = NULL;
GVariant *retval = NULL;
gchar *opath = NULL;
gchar *parent_window = NULL;
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
{
GdkWindow *window;
window = gtk_widget_get_window (GTK_WIDGET (button));
if (window)
{
gint id;
id = GDK_WINDOW_XID (window);
parent_window = g_strdup_printf ("x11:0x%x", id);
}
}
#endif
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL,
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Screenshot",
NULL, NULL);
if (!proxy)
{
return;
}
retval = g_dbus_proxy_call_sync (proxy, "PickColor",
g_variant_new ("(sa{sv})", parent_window ? parent_window : "", NULL),
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, NULL);
g_free (parent_window);
g_clear_object (&proxy);
if (retval)
{
g_variant_get (retval, "(o)", &opath);
g_variant_unref (retval);
}
if (opath)
{
GDBusProxy *proxy2 = NULL;
proxy2 = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL,
"org.freedesktop.portal.Desktop",
opath,
"org.freedesktop.portal.Request",
NULL, NULL);
g_signal_connect (proxy2, "g-signal",
G_CALLBACK (pick_color_xdg_dbus_signal),
button);
gtk_main ();
g_object_unref (proxy2);
g_free (opath);
}
}

View file

@ -0,0 +1,25 @@
/* LIBGIMP - The GIMP Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* gimppickbutton-xdg.h
* Copyright (C) 2021 Niels De Graef <nielsdegraef@gmail.com>
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
/* Private header file which is not meant to be exported. */
#ifndef __GIMP_PICK_BUTTON_XDG_H__
#define __GIMP_PICK_BUTTON_XDG_H__
gboolean _gimp_pick_button_xdg_available (void);
void _gimp_pick_button_xdg_pick (GimpPickButton *button);
#endif /* __GIMP_PICK_BUTTON_XDG_H__ */

View file

@ -32,6 +32,7 @@
#include "gimppickbutton.h"
#include "gimppickbutton-default.h"
#include "gimppickbutton-kwin.h"
#include "gimppickbutton-xdg.h"
#include "gimppickbutton-private.h"
#ifdef GDK_WINDOWING_QUARTZ
@ -143,7 +144,9 @@ gimp_pick_button_clicked (GtkButton *button)
#ifdef GDK_WINDOWING_QUARTZ
_gimp_pick_button_quartz_pick (GIMP_PICK_BUTTON (button));
#else
if (_gimp_pick_button_kwin_available ())
if (_gimp_pick_button_xdg_available ())
_gimp_pick_button_xdg_pick (GIMP_PICK_BUTTON (button));
else if (_gimp_pick_button_kwin_available ())
_gimp_pick_button_kwin_pick (GIMP_PICK_BUTTON (button));
else
_gimp_pick_button_default_pick (GIMP_PICK_BUTTON (button));

View file

@ -180,6 +180,7 @@ else
libgimpwidgets_sources += [
'gimppickbutton-default.c',
'gimppickbutton-kwin.c',
'gimppickbutton-xdg.c',
]
endif