2 * Copyright © 2015 Collabora, Ltd.
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 #include <linux/input.h>
32 #include "compositor.h"
33 #include "file-util.h"
36 encode_PAM_comment_line(const char *comment)
38 size_t len = strlen(comment);
39 char *str = malloc(len + 2);
41 const char *src = comment;
42 const char *end = src + len;
46 for (; src < end; src++, dst++) {
47 if (*src == '\n' || !isprint(*src))
58 * http://en.wikipedia.org/wiki/Netpbm#PAM_graphics_format
59 * RGBA is in byte address order.
61 * ImageMagick 'convert' can convert a PAM image to a more common format.
62 * To view the image metadata: $ head -n7 image.pam
65 write_PAM_image_rgba(FILE *fp, int width, int height,
66 void *pixels, size_t size, const char *comment)
71 assert(size == (size_t)4 * width * height);
73 ret = fprintf(fp, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\n"
74 "TUPLTYPE RGB_ALPHA\n", width, height);
79 str = encode_PAM_comment_line(comment);
80 ret = fprintf(fp, "%s\n", str);
87 ret = fprintf(fp, "ENDHDR\n");
91 if (fwrite(pixels, 1, size, fp) != size)
101 unmult(uint32_t c, uint32_t a)
103 return (c * 255 + a / 2) / a;
107 unpremultiply_and_swap_a8b8g8r8_to_PAMrgba(void *pixels, size_t size)
109 uint32_t *p = pixels;
112 for (end = p + size / 4; p < end; p++) {
116 a = (v & 0xff000000) >> 24;
120 uint8_t *dst = (uint8_t *)p;
122 dst[0] = unmult((v & 0x000000ff) >> 0, a);
123 dst[1] = unmult((v & 0x0000ff00) >> 8, a);
124 dst[2] = unmult((v & 0x00ff0000) >> 16, a);
131 trigger_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
134 const char *prefix = "surfaceshot-";
135 const char *suffix = ".pam";
137 struct weston_surface *surface;
141 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
146 if (seat->pointer_device_count == 0 ||
148 !seat->pointer->focus)
151 surface = seat->pointer->focus->surface;
153 weston_surface_get_content_size(surface, &width, &height);
155 if (!surface->get_label ||
156 surface->get_label(surface, desc, sizeof(desc)) < 0)
157 snprintf(desc, sizeof(desc), "(unknown)");
159 weston_log("surface screenshot of %p: '%s', %dx%d\n",
160 surface, desc, width, height);
162 sz = width * bytespp * height;
164 weston_log("no content for %p\n", surface);
170 weston_log("%s: failed to malloc %zu B\n", __func__, sz);
174 ret = weston_surface_copy_content(surface, pixels, sz,
175 0, 0, width, height);
177 weston_log("shooting surface %p failed\n", surface);
181 unpremultiply_and_swap_a8b8g8r8_to_PAMrgba(pixels, sz);
183 fp = file_create_dated(prefix, suffix, fname, sizeof(fname));
189 msg = "failure in datetime formatting";
192 msg = strerror(errno);
195 weston_log("Cannot open '%s*%s' for writing: %s\n",
196 prefix, suffix, msg);
200 ret = write_PAM_image_rgba(fp, width, height, pixels, sz, desc);
201 if (fclose(fp) != 0 || ret < 0)
202 weston_log("writing surface %p screenshot failed.\n", surface);
204 weston_log("successfully shot surface %p into '%s'\n",
212 module_init(struct weston_compositor *ec,
213 int *argc, char *argv[])
215 weston_compositor_add_debug_binding(ec, KEY_H, trigger_binding, ec);