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
=== modified file 'src/DBus.vala'
--- src/DBus.vala 2015-11-11 19:56:40 +0000
+++ src/DBus.vala 2017-02-16 18:34:50 +0000
@@ -39,6 +39,21 @@
39 },39 },
40 () => {},40 () => {},
41 () => warning ("Could not acquire name\n") );41 () => warning ("Could not acquire name\n") );
42
43 Bus.own_name (BusType.SESSION, "org.gnome.Shell", BusNameOwnerFlags.NONE,
44 (connection) => {
45 try {
46 connection.register_object ("/org/gnome/Shell", DBusAccelerator.init (wm));
47 connection.register_object ("/org/gnome/Shell/Screenshot", ScreenshotManager.init (wm));
48 } catch (Error e) { warning (e.message); }
49 },
50 () => {},
51 () => critical ("Could not acquire name") );
52
53 Bus.own_name (BusType.SESSION, "org.gnome.Shell.Screenshot", BusNameOwnerFlags.REPLACE,
54 () => {},
55 () => {},
56 () => critical ("Could not acquire name") );
42 }57 }
4358
44 private DBus ()59 private DBus ()
4560
=== modified file 'src/DBusAccelerator.vala'
--- src/DBusAccelerator.vala 2016-08-03 11:14:55 +0000
+++ src/DBusAccelerator.vala 2017-02-16 18:34:50 +0000
@@ -27,24 +27,14 @@
27 public class DBusAccelerator27 public class DBusAccelerator
28 {28 {
29 static DBusAccelerator? instance;29 static DBusAccelerator? instance;
30 static WindowManager wm;30
31
32 [DBus (visible = false)]31 [DBus (visible = false)]
33 public static void init (WindowManager _wm)32 public static unowned DBusAccelerator init (WindowManager wm)
34 {33 {
35 wm = _wm;34 if (instance == null)
3635 instance = new DBusAccelerator (wm);
37 Bus.own_name (BusType.SESSION, "org.gnome.Shell", BusNameOwnerFlags.NONE,36
38 (connection) => {37 return instance;
39 if (instance == null)
40 instance = new DBusAccelerator ();
41
42 try {
43 connection.register_object ("/org/gnome/Shell", instance);
44 } catch (Error e) { warning (e.message); }
45 },
46 () => {},
47 () => critical ("Could not acquire name") );
48 }38 }
4939
50#if HAS_GSD31640#if HAS_GSD316
@@ -53,10 +43,12 @@
53 public signal void accelerator_activated (uint action, uint device_id, uint timestamp);43 public signal void accelerator_activated (uint action, uint device_id, uint timestamp);
54#endif44#endif
5545
46 WindowManager wm;
56 HashTable<string, uint?> grabbed_accelerators;47 HashTable<string, uint?> grabbed_accelerators;
5748
58 DBusAccelerator ()49 DBusAccelerator (WindowManager _wm)
59 {50 {
51 wm = _wm;
60 grabbed_accelerators = new HashTable<string, uint> (str_hash, str_equal);52 grabbed_accelerators = new HashTable<string, uint> (str_hash, str_equal);
6153
62 wm.get_screen ().get_display ().accelerator_activated.connect (on_accelerator_activated);54 wm.get_screen ().get_display ().accelerator_activated.connect (on_accelerator_activated);
6355
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2016-08-03 11:14:55 +0000
+++ src/Makefile.am 2017-02-16 18:34:50 +0000
@@ -8,6 +8,7 @@
8 --vapidir $(VAPIDIR) \8 --vapidir $(VAPIDIR) \
9 $(VAPIDIR)/config.vapi \9 $(VAPIDIR)/config.vapi \
10 $(VAPIDIR)/cogl-fixes.vapi \10 $(VAPIDIR)/cogl-fixes.vapi \
11 $(VAPIDIR)/compat.vapi \
11 $(NULL)12 $(NULL)
1213
13galadir = $(bindir)14galadir = $(bindir)
@@ -41,6 +42,7 @@
41 MediaFeedback.vala \42 MediaFeedback.vala \
42 PluginManager.vala \43 PluginManager.vala \
43 ScreenSaver.vala \44 ScreenSaver.vala \
45 ScreenshotManager.vala \
44 Settings.vala \46 Settings.vala \
45 ShadowEffect.vala \47 ShadowEffect.vala \
46 TextShadowEffect.vala \48 TextShadowEffect.vala \
4749
=== added file 'src/ScreenshotManager.vala'
--- src/ScreenshotManager.vala 1970-01-01 00:00:00 +0000
+++ src/ScreenshotManager.vala 2017-02-16 18:34:50 +0000
@@ -0,0 +1,167 @@
1//
2// Copyright (C) 2016 Rico Tzschichholz, Santiago León O.
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16//
17
18namespace Gala
19{
20 [DBus (name="org.gnome.Shell.Screenshot")]
21 public class ScreenshotManager : Object
22 {
23 static ScreenshotManager? instance;
24
25 [DBus (visible = false)]
26 public static unowned ScreenshotManager init (WindowManager wm)
27 {
28 if (instance == null)
29 instance = new ScreenshotManager (wm);
30
31 return instance;
32 }
33
34 WindowManager wm;
35
36 ScreenshotManager (WindowManager _wm)
37 {
38 wm = _wm;
39 }
40
41 public void flash_area (int x, int y, int width, int height)
42 {
43 warning ("FlashArea not implemented");
44 }
45
46 public void screenshot (bool include_cursor, bool flash, string filename, out bool success, out string filename_used)
47 {
48 debug ("Taking screenshot");
49
50 int width, height;
51 wm.get_screen ().get_size (out width, out height);
52
53 var image = take_screenshot (0, 0, width, height);
54 success = save_image (image, filename, out filename_used);
55 }
56
57 public void screenshot_area (int x, int y, int width, int height, bool flash, string filename, out bool success, out string filename_used)
58 {
59 warning ("ScreenShotArea not implemented");
60 filename_used = "";
61 success = false;
62 }
63
64 public void screenshot_window (bool include_frame, bool include_cursor, bool flash, string filename, out bool success, out string filename_used)
65 {
66 debug ("Taking window screenshot");
67
68 var window = wm.get_screen ().get_display ().get_focus_window ();
69 var window_actor = (Meta.WindowActor) window.get_compositor_private ();
70 unowned Meta.ShapedTexture window_texture = (Meta.ShapedTexture) window_actor.get_texture ();
71
72 float actor_x, actor_y;
73 window_actor.get_position (out actor_x, out actor_y);
74
75 var rect = window.get_frame_rect ();
76 if (include_frame) {
77 rect = window.frame_rect_to_client_rect (rect);
78 }
79
80 Cairo.RectangleInt clip = { rect.x - (int) actor_x, rect.y - (int) actor_y, rect.width, rect.height };
81 var image = (Cairo.ImageSurface) window_texture.get_image (clip);
82 success = save_image (image, filename, out filename_used);
83 }
84
85 public void select_area (out int x, out int y, out int width, out int height)
86 {
87 warning ("SelectArea not implemented");
88 x = y = width = height = 0;
89 }
90
91 static bool save_image (Cairo.ImageSurface image, string filename, out string used_filename)
92 {
93 if (!Path.is_absolute (filename)) {
94 string path = Environment.get_user_special_dir (UserDirectory.PICTURES);
95 if (!FileUtils.test (path, FileTest.EXISTS)) {
96 path = Environment.get_home_dir ();
97 }
98
99 if (!filename.has_suffix (".png")) {
100 used_filename = Path.build_filename (path, filename.concat (".png"), null);
101 } else {
102 used_filename = Path.build_filename (path, filename, null);
103 }
104 } else {
105 used_filename = filename;
106 }
107
108 try {
109 var screenshot = Gdk.pixbuf_get_from_surface (image, 0, 0, image.get_width (), image.get_height ());
110 screenshot.save (used_filename, "png");
111 return true;
112 } catch (GLib.Error e) {
113 return false;
114 }
115 }
116
117 Cairo.ImageSurface take_screenshot (int x, int y, int width, int height)
118 {
119 Cairo.ImageSurface image;
120#if HAS_MUTTER322
121 Clutter.Capture[] captures;
122 wm.stage.capture (false, {x, y, width, height}, out captures);
123
124 if (captures.length == 0)
125 image = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
126 else if (captures.length == 1)
127 image = captures[0].image;
128 else
129 image = composite_capture_images (captures, x, y, width, height);
130#else
131 unowned Clutter.Backend backend = Clutter.get_default_backend ();
132 unowned Cogl.Context context = Clutter.backend_get_cogl_context (backend);
133
134 image = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
135 var bitmap = Cogl.bitmap_new_for_data (context, width, height, Cogl.PixelFormat.BGRA_8888_PRE, image.get_stride (), image.get_data ());
136 Cogl.framebuffer_read_pixels_into_bitmap (Cogl.get_draw_framebuffer (), x, y, Cogl.ReadPixelsFlags.BUFFER, bitmap);
137 image.mark_dirty ();
138#endif
139
140 return image;
141 }
142
143#if HAS_MUTTER322
144 Cairo.ImageSurface composite_capture_images (Clutter.Capture[] captures, int x, int y, int width, int height)
145 {
146 var image = new Cairo.ImageSurface (captures[0].image.get_format (), width, height);
147 var cr = new Cairo.Context (image);
148
149 foreach (unowned Clutter.Capture capture in captures) {
150 // Ignore capture regions with scale other than 1 for now; mutter can't
151 // produce them yet, so there is no way to test them.
152 double capture_scale = 1.0;
153 capture.image.get_device_scale (out capture_scale, null);
154 if (capture_scale != 1.0)
155 continue;
156
157 cr.save ();
158 cr.translate (capture.rect.x - x, capture.rect.y - y);
159 cr.set_source_surface (capture.image, 0, 0);
160 cr.restore ();
161 }
162
163 return image;
164 }
165#endif
166 }
167}
0168
=== modified file 'vapi/Makefile.am'
--- vapi/Makefile.am 2016-11-14 14:38:40 +0000
+++ vapi/Makefile.am 2017-02-16 18:34:50 +0000
@@ -1,5 +1,6 @@
1VAPIS = \1VAPIS = \
2 cogl-fixes.vapi \2 cogl-fixes.vapi \
3 compat.vapi \
3 config.vapi \4 config.vapi \
4 libbamf3.vapi \5 libbamf3.vapi \
5 gdesktopenums-3.0.vapi \6 gdesktopenums-3.0.vapi \
67
=== added file 'vapi/compat.vapi'
--- vapi/compat.vapi 1970-01-01 00:00:00 +0000
+++ vapi/compat.vapi 2017-02-16 18:34:50 +0000
@@ -0,0 +1,21 @@
1namespace Cogl
2{
3 [CCode (cheader_filename = "cogl/cogl.h")]
4 public class Context : Cogl.Handle {
5 }
6
7 [CCode (cname = "cogl_bitmap_new_for_data")]
8 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);
9
10 [CCode (cname = "cogl_get_draw_framebuffer")]
11 public static unowned Cogl.Framebuffer get_draw_framebuffer ();
12
13 [CCode (cname = "cogl_framebuffer_read_pixels_into_bitmap")]
14 public static Cogl.Bool framebuffer_read_pixels_into_bitmap (Cogl.Framebuffer framebuffer, int x, int y, Cogl.ReadPixelsFlags source, Cogl.Bitmap bitmap);
15}
16
17namespace Clutter
18{
19 [CCode (cname = "clutter_backend_get_cogl_context")]
20 public static unowned Cogl.Context backend_get_cogl_context (Clutter.Backend backend);
21}
022
=== modified file 'vapi/mutter-clutter-1.0.vapi'
--- vapi/mutter-clutter-1.0.vapi 2016-11-14 14:38:40 +0000
+++ vapi/mutter-clutter-1.0.vapi 2017-02-16 18:34:50 +0000
@@ -7330,7 +7330,7 @@
7330 [CCode (has_construct_function = false, type = "ClutterActor*")]7330 [CCode (has_construct_function = false, type = "ClutterActor*")]
7331 [Version (since = "0.8")]7331 [Version (since = "0.8")]
7332 public Stage ();7332 public Stage ();
7333 public bool capture (bool paint, Cairo.RectangleInt rect, Clutter.Capture captures, int n_captures);7333 public bool capture (bool paint, Cairo.RectangleInt rect, out Clutter.Capture[] captures);
7334 [CCode (cname = "clutter_stage_event")]7334 [CCode (cname = "clutter_stage_event")]
7335 [Version (since = "0.4")]7335 [Version (since = "0.4")]
7336 public bool emit_event (Clutter.Event event);7336 public bool emit_event (Clutter.Event event);
@@ -8361,9 +8361,9 @@
8361 public bool prev (out unowned Clutter.Actor child);8361 public bool prev (out unowned Clutter.Actor child);
8362 public void remove ();8362 public void remove ();
8363 }8363 }
8364 [CCode (cheader_filename = "clutter/clutter.h", has_type_id = false)]8364 [CCode (cheader_filename = "clutter/clutter.h", has_destroy_function = false, has_type_id = false)]
8365 public struct Capture {8365 public struct Capture {
8366 public weak Cairo.Surface image;8366 public Cairo.ImageSurface image;
8367 public Cairo.RectangleInt rect;8367 public Cairo.RectangleInt rect;
8368 }8368 }
8369 [CCode (cheader_filename = "clutter/clutter.h", type_id = "CLUTTER_TYPE_COLOR")]8369 [CCode (cheader_filename = "clutter/clutter.h", type_id = "CLUTTER_TYPE_COLOR")]

Subscribers

People subscribed via source and target branches