aboutsummaryrefslogtreecommitdiffstats
path: root/src/screenshot.zig
blob: 6f74429e8f26d3e98e726b48bbe45b5c0adc1eb1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
const build_options = @import("build_options");
const c = @import("c.zig").c;

const std = @import("std");

extern fn XDestroyImage(ximage: *c.XImage) c_int;

const ShmInfo = if (build_options.use_xshm) c.XShmSegmentInfo else struct {};

pub const Screenshot = struct {
    image: *c.XImage,
    shm: ShmInfo = .{},

    pub fn capture(display: *c.Display, window: c.Window) !Screenshot {
        var attrs: c.XWindowAttributes = undefined;
        _ = c.XGetWindowAttributes(display, window, &attrs);

        if (build_options.use_xshm) {
            const screen = c.XDefaultScreen(display);

            var ss = Screenshot{ .image = undefined, .shm = undefined };

            ss.image = c.XShmCreateImage(
                display,
                c.XDefaultVisual(display, @intCast(screen)),
                @intCast(c.XDefaultDepthOfScreen(c.XScreenOfDisplay(display, @intCast(screen)))),
                c.ZPixmap,
                null,
                &ss.shm,
                @intCast(attrs.width),
                @intCast(attrs.height),
            ) orelse return error.ScreenshotFailed;

            ss.shm.shmid = c.shmget(c.IPC_PRIVATE, @intCast(ss.image.*.bytes_per_line * ss.image.*.height), c.IPC_CREAT | 0o777);
            ss.shm.shmaddr = @ptrCast(c.shmat(ss.shm.shmid, null, 0));
            ss.image.*.data = @ptrCast(ss.shm.shmaddr);
            ss.shm.readOnly = c.False;

            _ = c.XShmAttach(display, &ss.shm);
            _ = c.XShmGetImage(display, window, ss.image, 0, 0, c.AllPlanes);

            return ss;
        } else {
            const image = c.XGetImage(display, window, 0, 0, @intCast(attrs.width), @intCast(attrs.height), c.AllPlanes, c.ZPixmap);
            if (image == null) return error.ScreenshotFailed;
            return .{ .image = image.? };
        }
    }

    pub fn deinit(self: *Screenshot) void {
        if (build_options.use_xshm) {
            _ = XDestroyImage(self.image);
            _ = c.shmdt(self.shm.shmaddr);
            _ = c.shmctl(self.shm.shmid, c.IPC_RMID, null);
        } else {
            _ = XDestroyImage(self.image);
        }
    }
};