aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/wm/output.c
blob: 3283c41dff656ad4fe5c1571e4b836a042c230a0 (plain)
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "wm.h"

typedef struct Payload  Payload;
struct Payload
{
    Client              *client;
    struct wlr_output   *output;
    struct wlr_renderer *renderer;
    struct timespec     *when;
};


static
void
draw(struct wlr_surface *surface, int sx, int sy, void *data)
{
    float matrix[9];
    double ox, oy;
    Client  *client;
    Payload *payload;
    struct wlr_box box;
    struct wlr_output *output;
    struct wlr_texture *texture;
    enum wl_output_transform transform;

    payload = data;
    client  = payload->client;
    output  = payload->output;

    texture = wlr_surface_get_texture(surface);
    if(!texture)
        return;

    ox = 0, oy = 0;
    wlr_output_layout_output_coords(server.output.layout, output, &ox, &oy);
    ox += client->x + sx, oy += client->y + sy;

    box = (struct wlr_box){
        .x = ox * output->scale,
        .y = oy * output->scale,
        .width = surface->current.width * output->scale,
        .height = surface->current.height * output->scale,
    };

    transform = wlr_output_transform_invert(surface->current.transform);
    wlr_matrix_project_box(matrix, &box, transform, 0, output->transform_matrix);

    wlr_render_texture_with_matrix(payload->renderer, texture, matrix, 1);
    wlr_surface_send_frame_done(surface, payload->when);
}

static
void
render(struct wl_listener *l, void *data)
{
    int width, height;
    struct timespec now;
    Client  *client;
    Monitor *monitor;
    struct wlr_renderer *renderer;
    float color[4] = {0.3, 0.3, 0.3, 1.0};

    monitor  = wl_container_of(l, monitor, event.render);
    renderer = server.renderer;
    clock_gettime(CLOCK_MONOTONIC, &now);

    if(!wlr_output_attach_render(monitor->output, nil))
        return;

    wlr_output_effective_resolution(monitor->output, &width, &height);

    /* start of rendering kernel */
    wlr_renderer_begin(renderer, width, height);
    wlr_renderer_clear(renderer, color);

    wl_list_for_each_reverse(client, &server.clients, link) {
        if(!client->mapped)
            continue;

        Payload payload = {
            .output   = monitor->output,
            .client   = client,
            .renderer = renderer,
            .when     = &now,
        };

        wlr_xdg_surface_for_each_surface(client->xdg, draw, &payload);
    }

    wlr_output_render_software_cursors(monitor->output, nil);

    wlr_renderer_end(renderer);
    wlr_output_commit(monitor->output);
}

void
make_output(struct wl_listener *l, void *data)
{
    struct wlr_output_mode *mode;
    struct Monitor         *monitor;
    struct wlr_output      *output = data;

    if (!wl_list_empty(&output->modes)) {
        mode = wlr_output_preferred_mode(output);
        wlr_output_set_mode(output, mode);
        wlr_output_enable(output, true);
        if (!wlr_output_commit(output)) {
            return;
        }
    }

    monitor = calloc(1, sizeof(*monitor));
    monitor->output = output;

    monitor->event.render.notify = render;
    wl_signal_add(&output->events.frame, &monitor->event.render);
    wl_list_insert(&server.output.list, &monitor->link);

    wlr_output_layout_add_auto(server.output.layout, output);
}