Merge lp:~gala-dev/gala/screenshot into lp:gala

Proposed by Rico Tzschichholz
Status: Merged
Merged at revision: 556
Proposed branch: lp:~gala-dev/gala/screenshot
Merge into: lp:gala
Diff against target: 328 lines (+218/-20)
7 files modified
src/DBus.vala (+15/-0)
src/DBusAccelerator.vala (+9/-17)
src/Makefile.am (+2/-0)
src/ScreenshotManager.vala (+167/-0)
vapi/Makefile.am (+1/-0)
vapi/compat.vapi (+21/-0)
vapi/mutter-clutter-1.0.vapi (+3/-3)
To merge this branch: bzr merge lp:~gala-dev/gala/screenshot
Reviewer Review Type Date Requested Status
Santiago Pending
Gala developers Pending
Review via email: mp+313930@code.launchpad.net

Description of the change

This implements part of the interface gnome-settings-daemon uses to take screenshots by using shortcuts (or the Print Screen key). It implements window screenshots and full screen screenshots.

To post a comment you must log in.
lp:~gala-dev/gala/screenshot updated
552. By Rico Tzschichholz

maskcorners: Add missing license header

554. By Santiago

screenshotmanager: Implement Screenshot and ScreenshotArea

555. By Rico Tzschichholz

screenshotmanager: Add support for mutter 3.22+

556. By Rico Tzschichholz

dbus: Acquire "org.gnome.Shell.Screenshot" bus-name

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/DBus.vala'
2--- src/DBus.vala 2015-11-11 19:56:40 +0000
3+++ src/DBus.vala 2017-02-16 18:34:50 +0000
4@@ -39,6 +39,21 @@
5 },
6 () => {},
7 () => warning ("Could not acquire name\n") );
8+
9+ Bus.own_name (BusType.SESSION, "org.gnome.Shell", BusNameOwnerFlags.NONE,
10+ (connection) => {
11+ try {
12+ connection.register_object ("/org/gnome/Shell", DBusAccelerator.init (wm));
13+ connection.register_object ("/org/gnome/Shell/Screenshot", ScreenshotManager.init (wm));
14+ } catch (Error e) { warning (e.message); }
15+ },
16+ () => {},
17+ () => critical ("Could not acquire name") );
18+
19+ Bus.own_name (BusType.SESSION, "org.gnome.Shell.Screenshot", BusNameOwnerFlags.REPLACE,
20+ () => {},
21+ () => {},
22+ () => critical ("Could not acquire name") );
23 }
24
25 private DBus ()
26
27=== modified file 'src/DBusAccelerator.vala'
28--- src/DBusAccelerator.vala 2016-08-03 11:14:55 +0000
29+++ src/DBusAccelerator.vala 2017-02-16 18:34:50 +0000
30@@ -27,24 +27,14 @@
31 public class DBusAccelerator
32 {
33 static DBusAccelerator? instance;
34- static WindowManager wm;
35-
36+
37 [DBus (visible = false)]
38- public static void init (WindowManager _wm)
39+ public static unowned DBusAccelerator init (WindowManager wm)
40 {
41- wm = _wm;
42-
43- Bus.own_name (BusType.SESSION, "org.gnome.Shell", BusNameOwnerFlags.NONE,
44- (connection) => {
45- if (instance == null)
46- instance = new DBusAccelerator ();
47-
48- try {
49- connection.register_object ("/org/gnome/Shell", instance);
50- } catch (Error e) { warning (e.message); }
51- },
52- () => {},
53- () => critical ("Could not acquire name") );
54+ if (instance == null)
55+ instance = new DBusAccelerator (wm);
56+
57+ return instance;
58 }
59
60 #if HAS_GSD316
61@@ -53,10 +43,12 @@
62 public signal void accelerator_activated (uint action, uint device_id, uint timestamp);
63 #endif
64
65+ WindowManager wm;
66 HashTable<string, uint?> grabbed_accelerators;
67
68- DBusAccelerator ()
69+ DBusAccelerator (WindowManager _wm)
70 {
71+ wm = _wm;
72 grabbed_accelerators = new HashTable<string, uint> (str_hash, str_equal);
73
74 wm.get_screen ().get_display ().accelerator_activated.connect (on_accelerator_activated);
75
76=== modified file 'src/Makefile.am'
77--- src/Makefile.am 2016-08-03 11:14:55 +0000
78+++ src/Makefile.am 2017-02-16 18:34:50 +0000
79@@ -8,6 +8,7 @@
80 --vapidir $(VAPIDIR) \
81 $(VAPIDIR)/config.vapi \
82 $(VAPIDIR)/cogl-fixes.vapi \
83+ $(VAPIDIR)/compat.vapi \
84 $(NULL)
85
86 galadir = $(bindir)
87@@ -41,6 +42,7 @@
88 MediaFeedback.vala \
89 PluginManager.vala \
90 ScreenSaver.vala \
91+ ScreenshotManager.vala \
92 Settings.vala \
93 ShadowEffect.vala \
94 TextShadowEffect.vala \
95
96=== added file 'src/ScreenshotManager.vala'
97--- src/ScreenshotManager.vala 1970-01-01 00:00:00 +0000
98+++ src/ScreenshotManager.vala 2017-02-16 18:34:50 +0000
99@@ -0,0 +1,167 @@
100+//
101+// Copyright (C) 2016 Rico Tzschichholz, Santiago León O.
102+//
103+// This program is free software: you can redistribute it and/or modify
104+// it under the terms of the GNU General Public License as published by
105+// the Free Software Foundation, either version 3 of the License, or
106+// (at your option) any later version.
107+//
108+// This program is distributed in the hope that it will be useful,
109+// but WITHOUT ANY WARRANTY; without even the implied warranty of
110+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
111+// GNU General Public License for more details.
112+//
113+// You should have received a copy of the GNU General Public License
114+// along with this program. If not, see <http://www.gnu.org/licenses/>.
115+//
116+
117+namespace Gala
118+{
119+ [DBus (name="org.gnome.Shell.Screenshot")]
120+ public class ScreenshotManager : Object
121+ {
122+ static ScreenshotManager? instance;
123+
124+ [DBus (visible = false)]
125+ public static unowned ScreenshotManager init (WindowManager wm)
126+ {
127+ if (instance == null)
128+ instance = new ScreenshotManager (wm);
129+
130+ return instance;
131+ }
132+
133+ WindowManager wm;
134+
135+ ScreenshotManager (WindowManager _wm)
136+ {
137+ wm = _wm;
138+ }
139+
140+ public void flash_area (int x, int y, int width, int height)
141+ {
142+ warning ("FlashArea not implemented");
143+ }
144+
145+ public void screenshot (bool include_cursor, bool flash, string filename, out bool success, out string filename_used)
146+ {
147+ debug ("Taking screenshot");
148+
149+ int width, height;
150+ wm.get_screen ().get_size (out width, out height);
151+
152+ var image = take_screenshot (0, 0, width, height);
153+ success = save_image (image, filename, out filename_used);
154+ }
155+
156+ public void screenshot_area (int x, int y, int width, int height, bool flash, string filename, out bool success, out string filename_used)
157+ {
158+ warning ("ScreenShotArea not implemented");
159+ filename_used = "";
160+ success = false;
161+ }
162+
163+ public void screenshot_window (bool include_frame, bool include_cursor, bool flash, string filename, out bool success, out string filename_used)
164+ {
165+ debug ("Taking window screenshot");
166+
167+ var window = wm.get_screen ().get_display ().get_focus_window ();
168+ var window_actor = (Meta.WindowActor) window.get_compositor_private ();
169+ unowned Meta.ShapedTexture window_texture = (Meta.ShapedTexture) window_actor.get_texture ();
170+
171+ float actor_x, actor_y;
172+ window_actor.get_position (out actor_x, out actor_y);
173+
174+ var rect = window.get_frame_rect ();
175+ if (include_frame) {
176+ rect = window.frame_rect_to_client_rect (rect);
177+ }
178+
179+ Cairo.RectangleInt clip = { rect.x - (int) actor_x, rect.y - (int) actor_y, rect.width, rect.height };
180+ var image = (Cairo.ImageSurface) window_texture.get_image (clip);
181+ success = save_image (image, filename, out filename_used);
182+ }
183+
184+ public void select_area (out int x, out int y, out int width, out int height)
185+ {
186+ warning ("SelectArea not implemented");
187+ x = y = width = height = 0;
188+ }
189+
190+ static bool save_image (Cairo.ImageSurface image, string filename, out string used_filename)
191+ {
192+ if (!Path.is_absolute (filename)) {
193+ string path = Environment.get_user_special_dir (UserDirectory.PICTURES);
194+ if (!FileUtils.test (path, FileTest.EXISTS)) {
195+ path = Environment.get_home_dir ();
196+ }
197+
198+ if (!filename.has_suffix (".png")) {
199+ used_filename = Path.build_filename (path, filename.concat (".png"), null);
200+ } else {
201+ used_filename = Path.build_filename (path, filename, null);
202+ }
203+ } else {
204+ used_filename = filename;
205+ }
206+
207+ try {
208+ var screenshot = Gdk.pixbuf_get_from_surface (image, 0, 0, image.get_width (), image.get_height ());
209+ screenshot.save (used_filename, "png");
210+ return true;
211+ } catch (GLib.Error e) {
212+ return false;
213+ }
214+ }
215+
216+ Cairo.ImageSurface take_screenshot (int x, int y, int width, int height)
217+ {
218+ Cairo.ImageSurface image;
219+#if HAS_MUTTER322
220+ Clutter.Capture[] captures;
221+ wm.stage.capture (false, {x, y, width, height}, out captures);
222+
223+ if (captures.length == 0)
224+ image = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
225+ else if (captures.length == 1)
226+ image = captures[0].image;
227+ else
228+ image = composite_capture_images (captures, x, y, width, height);
229+#else
230+ unowned Clutter.Backend backend = Clutter.get_default_backend ();
231+ unowned Cogl.Context context = Clutter.backend_get_cogl_context (backend);
232+
233+ image = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
234+ var bitmap = Cogl.bitmap_new_for_data (context, width, height, Cogl.PixelFormat.BGRA_8888_PRE, image.get_stride (), image.get_data ());
235+ Cogl.framebuffer_read_pixels_into_bitmap (Cogl.get_draw_framebuffer (), x, y, Cogl.ReadPixelsFlags.BUFFER, bitmap);
236+ image.mark_dirty ();
237+#endif
238+
239+ return image;
240+ }
241+
242+#if HAS_MUTTER322
243+ Cairo.ImageSurface composite_capture_images (Clutter.Capture[] captures, int x, int y, int width, int height)
244+ {
245+ var image = new Cairo.ImageSurface (captures[0].image.get_format (), width, height);
246+ var cr = new Cairo.Context (image);
247+
248+ foreach (unowned Clutter.Capture capture in captures) {
249+ // Ignore capture regions with scale other than 1 for now; mutter can't
250+ // produce them yet, so there is no way to test them.
251+ double capture_scale = 1.0;
252+ capture.image.get_device_scale (out capture_scale, null);
253+ if (capture_scale != 1.0)
254+ continue;
255+
256+ cr.save ();
257+ cr.translate (capture.rect.x - x, capture.rect.y - y);
258+ cr.set_source_surface (capture.image, 0, 0);
259+ cr.restore ();
260+ }
261+
262+ return image;
263+ }
264+#endif
265+ }
266+}
267
268=== modified file 'vapi/Makefile.am'
269--- vapi/Makefile.am 2016-11-14 14:38:40 +0000
270+++ vapi/Makefile.am 2017-02-16 18:34:50 +0000
271@@ -1,5 +1,6 @@
272 VAPIS = \
273 cogl-fixes.vapi \
274+ compat.vapi \
275 config.vapi \
276 libbamf3.vapi \
277 gdesktopenums-3.0.vapi \
278
279=== added file 'vapi/compat.vapi'
280--- vapi/compat.vapi 1970-01-01 00:00:00 +0000
281+++ vapi/compat.vapi 2017-02-16 18:34:50 +0000
282@@ -0,0 +1,21 @@
283+namespace Cogl
284+{
285+ [CCode (cheader_filename = "cogl/cogl.h")]
286+ public class Context : Cogl.Handle {
287+ }
288+
289+ [CCode (cname = "cogl_bitmap_new_for_data")]
290+ public static Cogl.Bitmap bitmap_new_for_data (Cogl.Context Context, int width, int height, Cogl.PixelFormat format, int rowstride, [CCode (array_length = false)] uchar[] data);
291+
292+ [CCode (cname = "cogl_get_draw_framebuffer")]
293+ public static unowned Cogl.Framebuffer get_draw_framebuffer ();
294+
295+ [CCode (cname = "cogl_framebuffer_read_pixels_into_bitmap")]
296+ public static Cogl.Bool framebuffer_read_pixels_into_bitmap (Cogl.Framebuffer framebuffer, int x, int y, Cogl.ReadPixelsFlags source, Cogl.Bitmap bitmap);
297+}
298+
299+namespace Clutter
300+{
301+ [CCode (cname = "clutter_backend_get_cogl_context")]
302+ public static unowned Cogl.Context backend_get_cogl_context (Clutter.Backend backend);
303+}
304
305=== modified file 'vapi/mutter-clutter-1.0.vapi'
306--- vapi/mutter-clutter-1.0.vapi 2016-11-14 14:38:40 +0000
307+++ vapi/mutter-clutter-1.0.vapi 2017-02-16 18:34:50 +0000
308@@ -7330,7 +7330,7 @@
309 [CCode (has_construct_function = false, type = "ClutterActor*")]
310 [Version (since = "0.8")]
311 public Stage ();
312- public bool capture (bool paint, Cairo.RectangleInt rect, Clutter.Capture captures, int n_captures);
313+ public bool capture (bool paint, Cairo.RectangleInt rect, out Clutter.Capture[] captures);
314 [CCode (cname = "clutter_stage_event")]
315 [Version (since = "0.4")]
316 public bool emit_event (Clutter.Event event);
317@@ -8361,9 +8361,9 @@
318 public bool prev (out unowned Clutter.Actor child);
319 public void remove ();
320 }
321- [CCode (cheader_filename = "clutter/clutter.h", has_type_id = false)]
322+ [CCode (cheader_filename = "clutter/clutter.h", has_destroy_function = false, has_type_id = false)]
323 public struct Capture {
324- public weak Cairo.Surface image;
325+ public Cairo.ImageSurface image;
326 public Cairo.RectangleInt rect;
327 }
328 [CCode (cheader_filename = "clutter/clutter.h", type_id = "CLUTTER_TYPE_COLOR")]

Subscribers

People subscribed via source and target branches