1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * Screenshot plug-in
5 * Copyright 1998-2007 Sven Neumann <sven@gimp.org>
6 * Copyright 2003 Henrik Brix Andersen <brix@gimp.org>
7 * Copyright 2016 Michael Natterer <mitch@gimp.org>
8 * Copyright 2017 Jehan <jehan@gimp.org>
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24 #include "config.h"
25
26 #include <glib.h>
27 #include <glib/gstdio.h> /* g_unlink() */
28
29 #include <libgimp/gimp.h>
30 #include <libgimp/gimpui.h>
31
32 #include "screenshot.h"
33 #include "screenshot-kwin.h"
34
35
36 static GDBusProxy *proxy = NULL;
37
38
39 gboolean
screenshot_kwin_available(void)40 screenshot_kwin_available (void)
41 {
42 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
43 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
44 NULL,
45 "org.kde.KWin",
46 "/Screenshot",
47 "org.kde.kwin.Screenshot",
48 NULL, NULL);
49
50 if (proxy)
51 {
52 GError *error = NULL;
53
54 g_dbus_proxy_call_sync (proxy, "org.freedesktop.DBus.Peer.Ping",
55 NULL,
56 G_DBUS_CALL_FLAGS_NONE,
57 -1, NULL, &error);
58 if (! error)
59 return TRUE;
60
61 g_clear_error (&error);
62
63 g_object_unref (proxy);
64 proxy = NULL;
65 }
66
67 return FALSE;
68 }
69
70 ScreenshotCapabilities
screenshot_kwin_get_capabilities(void)71 screenshot_kwin_get_capabilities (void)
72 {
73 return (SCREENSHOT_CAN_SHOOT_DECORATIONS |
74 SCREENSHOT_CAN_SHOOT_POINTER |
75 SCREENSHOT_CAN_SHOOT_WINDOW |
76 SCREENSHOT_CAN_PICK_WINDOW);
77 /* TODO: SCREENSHOT_CAN_SHOOT_REGION.
78 * The KDE API has "screenshotArea" method but no method to get
79 * coordinates could be found. See below.
80 */
81 }
82
83 GimpPDBStatusType
screenshot_kwin_shoot(ScreenshotValues * shootvals,GdkScreen * screen,gint32 * image_ID,GError ** error)84 screenshot_kwin_shoot (ScreenshotValues *shootvals,
85 GdkScreen *screen,
86 gint32 *image_ID,
87 GError **error)
88 {
89 gchar *filename = NULL;
90 const gchar *method = NULL;
91 GVariant *args = NULL;
92 GVariant *retval;
93 gint monitor = shootvals->monitor;
94 gint32 mask;
95
96 switch (shootvals->shoot_type)
97 {
98 case SHOOT_ROOT:
99 if (shootvals->screenshot_delay > 0)
100 screenshot_delay (shootvals->screenshot_delay);
101 else
102 {
103 /* As an exception, I force a delay of at least 0.5 seconds
104 * for KWin. Because of windows effect slowly fading out, the
105 * screenshot plug-in GUI was constantly visible (with
106 * transparency as it is fading out) in 0s-delay screenshots.
107 */
108 g_usleep (500000);
109 }
110
111 method = "screenshotFullscreen";
112 args = g_variant_new ("(b)", shootvals->show_cursor);
113
114 /* FIXME: figure profile */
115 break;
116
117 case SHOOT_REGION:
118 break;
119 /* FIXME: GNOME-shell has a "SelectArea" returning coordinates
120 * which can be fed to "ScreenshotArea". KDE has the equivalent
121 * "screenshotArea", but no "SelectArea" equivalent that I could
122 * find.
123 * Also at first, I expected "interactive" method to take care of
124 * the whole selecting-are-then-screenshotting workflow, but this
125 * is apparently only made to select interactively a specific
126 * window, not an area.
127 */
128 method = "screenshotArea";
129 args = g_variant_new ("(iiii)",
130 shootvals->x1,
131 shootvals->y1,
132 shootvals->x2 - shootvals->x1,
133 shootvals->y2 - shootvals->y1);
134 args = NULL;
135
136 break;
137
138 case SHOOT_WINDOW:
139 if (shootvals->select_delay > 0)
140 screenshot_delay (shootvals->select_delay);
141
142 /* XXX I expected "screenshotWindowUnderCursor" method to be the
143 * right one, but it returns nothing, nor is there a file
144 * descriptor in argument. So I don't understand how to grab the
145 * screenshot. Also "interactive" changes the cursor to a
146 * crosshair, waiting for click, which is more helpful than
147 * immediate screenshot under cursor.
148 */
149 method = "interactive";
150 mask = (shootvals->decorate ? 1 : 0) |
151 (shootvals->show_cursor ? 1 << 1 : 0);
152 args = g_variant_new ("(i)", mask);
153
154 /* FIXME: figure monitor */
155 break;
156 }
157
158 retval = g_dbus_proxy_call_sync (proxy, method, args,
159 G_DBUS_CALL_FLAGS_NONE,
160 -1, NULL, error);
161 if (! retval)
162 goto failure;
163
164 g_variant_get (retval, "(s)",
165 &filename);
166 g_variant_unref (retval);
167
168 if (filename)
169 {
170 GimpColorProfile *profile;
171
172 *image_ID = gimp_file_load (GIMP_RUN_NONINTERACTIVE,
173 filename, filename);
174 gimp_image_set_filename (*image_ID, "screenshot.png");
175
176 /* This is very wrong in multi-display setups since we have no
177 * idea which profile is to be used. Let's keep it anyway and
178 * assume always the monitor 0, which will still work in common
179 * cases.
180 */
181 profile = gimp_screen_get_color_profile (screen, monitor);
182
183 if (profile)
184 {
185 gimp_image_set_color_profile (*image_ID, profile);
186 g_object_unref (profile);
187 }
188
189 g_unlink (filename);
190 g_free (filename);
191
192 g_object_unref (proxy);
193 proxy = NULL;
194
195 return GIMP_PDB_SUCCESS;
196 }
197
198 failure:
199
200 if (filename)
201 g_free (filename);
202
203 g_object_unref (proxy);
204 proxy = NULL;
205
206 return GIMP_PDB_EXECUTION_ERROR;
207 }
208