|
| 1 | +#include <inttypes.h> |
| 2 | +#include <stdio.h> |
| 3 | +#include <stdlib.h> |
| 4 | +#include <string.h> |
| 5 | +#include <time.h> |
| 6 | +#include <wayland-server-core.h> |
| 7 | +#include <wlr/backend.h> |
| 8 | +#include <wlr/backend/session.h> |
| 9 | +#include <wlr/render/allocator.h> |
| 10 | +#include <wlr/render/wlr_renderer.h> |
| 11 | +#include <wlr/types/wlr_output.h> |
| 12 | +#include <wlr/types/wlr_input_device.h> |
| 13 | +#include <wlr/types/wlr_keyboard.h> |
| 14 | +#include <wlr/util/log.h> |
| 15 | +#include <xkbcommon/xkbcommon.h> |
| 16 | + |
| 17 | +struct sample_state { |
| 18 | + struct wl_display *display; |
| 19 | + struct wl_listener new_output; |
| 20 | + struct wl_listener new_input; |
| 21 | + struct wlr_renderer *renderer; |
| 22 | + struct wlr_allocator *allocator; |
| 23 | + struct timespec last_frame; |
| 24 | + float color[4]; |
| 25 | + int dec; |
| 26 | +}; |
| 27 | + |
| 28 | +struct sample_output { |
| 29 | + struct sample_state *sample; |
| 30 | + struct wlr_output *output; |
| 31 | + struct wl_listener frame; |
| 32 | + struct wl_listener destroy; |
| 33 | +}; |
| 34 | + |
| 35 | +struct sample_keyboard { |
| 36 | + struct sample_state *sample; |
| 37 | + struct wlr_keyboard *wlr_keyboard; |
| 38 | + struct wl_listener key; |
| 39 | + struct wl_listener destroy; |
| 40 | +}; |
| 41 | + |
| 42 | +static void output_frame_notify(struct wl_listener *listener, void *data) { |
| 43 | + struct sample_output *sample_output = |
| 44 | + wl_container_of(listener, sample_output, frame); |
| 45 | + struct sample_state *sample = sample_output->sample; |
| 46 | + struct wlr_output *wlr_output = sample_output->output; |
| 47 | + |
| 48 | + struct timespec now; |
| 49 | + clock_gettime(CLOCK_MONOTONIC, &now); |
| 50 | + |
| 51 | + long ms = (now.tv_sec - sample->last_frame.tv_sec) * 1000 + |
| 52 | + (now.tv_nsec - sample->last_frame.tv_nsec) / 1000000; |
| 53 | + int inc = (sample->dec + 1) % 3; |
| 54 | + |
| 55 | + sample->color[inc] += ms / 2000.0f; |
| 56 | + sample->color[sample->dec] -= ms / 2000.0f; |
| 57 | + |
| 58 | + if (sample->color[sample->dec] < 0.0f) { |
| 59 | + sample->color[inc] = 1.0f; |
| 60 | + sample->color[sample->dec] = 0.0f; |
| 61 | + sample->dec = inc; |
| 62 | + } |
| 63 | + |
| 64 | + struct wlr_output_state state; |
| 65 | + wlr_output_state_init(&state); |
| 66 | + struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &state, NULL, NULL); |
| 67 | + wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){ |
| 68 | + .box = { .width = wlr_output->width, .height = wlr_output->height }, |
| 69 | + .color = { |
| 70 | + .r = sample->color[0], |
| 71 | + .g = sample->color[1], |
| 72 | + .b = sample->color[2], |
| 73 | + .a = sample->color[3], |
| 74 | + }, |
| 75 | + }); |
| 76 | + wlr_render_pass_submit(pass); |
| 77 | + |
| 78 | + wlr_output_commit_state(wlr_output, &state); |
| 79 | + wlr_output_state_finish(&state); |
| 80 | + sample->last_frame = now; |
| 81 | +} |
| 82 | + |
| 83 | +static void output_remove_notify(struct wl_listener *listener, void *data) { |
| 84 | + struct sample_output *sample_output = |
| 85 | + wl_container_of(listener, sample_output, destroy); |
| 86 | + wlr_log(WLR_DEBUG, "Output removed"); |
| 87 | + wl_list_remove(&sample_output->frame.link); |
| 88 | + wl_list_remove(&sample_output->destroy.link); |
| 89 | + free(sample_output); |
| 90 | +} |
| 91 | + |
| 92 | +static void new_output_notify(struct wl_listener *listener, void *data) { |
| 93 | + struct wlr_output *output = data; |
| 94 | + struct sample_state *sample = |
| 95 | + wl_container_of(listener, sample, new_output); |
| 96 | + |
| 97 | + wlr_output_init_render(output, sample->allocator, sample->renderer); |
| 98 | + |
| 99 | + struct sample_output *sample_output = calloc(1, sizeof(*sample_output)); |
| 100 | + sample_output->output = output; |
| 101 | + sample_output->sample = sample; |
| 102 | + wl_signal_add(&output->events.frame, &sample_output->frame); |
| 103 | + sample_output->frame.notify = output_frame_notify; |
| 104 | + wl_signal_add(&output->events.destroy, &sample_output->destroy); |
| 105 | + sample_output->destroy.notify = output_remove_notify; |
| 106 | + |
| 107 | + struct wlr_output_state state; |
| 108 | + wlr_output_state_init(&state); |
| 109 | + wlr_output_state_set_enabled(&state, true); |
| 110 | + struct wlr_output_mode *mode = wlr_output_preferred_mode(output); |
| 111 | + if (mode != NULL) { |
| 112 | + wlr_output_state_set_mode(&state, mode); |
| 113 | + } |
| 114 | + wlr_output_commit_state(output, &state); |
| 115 | + wlr_output_state_finish(&state); |
| 116 | +} |
| 117 | + |
| 118 | +static void keyboard_key_notify(struct wl_listener *listener, void *data) { |
| 119 | + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); |
| 120 | + struct sample_state *sample = keyboard->sample; |
| 121 | + struct wlr_keyboard_key_event *event = data; |
| 122 | + uint32_t keycode = event->keycode + 8; |
| 123 | + const xkb_keysym_t *syms; |
| 124 | + int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state, |
| 125 | + keycode, &syms); |
| 126 | + for (int i = 0; i < nsyms; i++) { |
| 127 | + xkb_keysym_t sym = syms[i]; |
| 128 | + if (sym == XKB_KEY_Escape) { |
| 129 | + wl_display_terminate(sample->display); |
| 130 | + } |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +static void keyboard_destroy_notify(struct wl_listener *listener, void *data) { |
| 135 | + struct sample_keyboard *keyboard = |
| 136 | + wl_container_of(listener, keyboard, destroy); |
| 137 | + wl_list_remove(&keyboard->destroy.link); |
| 138 | + wl_list_remove(&keyboard->key.link); |
| 139 | + free(keyboard); |
| 140 | +} |
| 141 | + |
| 142 | +static void new_input_notify(struct wl_listener *listener, void *data) { |
| 143 | + struct wlr_input_device *device = data; |
| 144 | + struct sample_state *sample = wl_container_of(listener, sample, new_input); |
| 145 | + switch (device->type) { |
| 146 | + case WLR_INPUT_DEVICE_KEYBOARD:; |
| 147 | + struct sample_keyboard *keyboard = calloc(1, sizeof(*keyboard)); |
| 148 | + keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device); |
| 149 | + keyboard->sample = sample; |
| 150 | + wl_signal_add(&device->events.destroy, &keyboard->destroy); |
| 151 | + keyboard->destroy.notify = keyboard_destroy_notify; |
| 152 | + wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key); |
| 153 | + keyboard->key.notify = keyboard_key_notify; |
| 154 | + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); |
| 155 | + if (!context) { |
| 156 | + wlr_log(WLR_ERROR, "Failed to create XKB context"); |
| 157 | + exit(1); |
| 158 | + } |
| 159 | + struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, NULL, |
| 160 | + XKB_KEYMAP_COMPILE_NO_FLAGS); |
| 161 | + if (!keymap) { |
| 162 | + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); |
| 163 | + exit(1); |
| 164 | + } |
| 165 | + wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap); |
| 166 | + xkb_keymap_unref(keymap); |
| 167 | + xkb_context_unref(context); |
| 168 | + break; |
| 169 | + default: |
| 170 | + break; |
| 171 | + } |
| 172 | +} |
| 173 | + |
| 174 | +int main(void) { |
| 175 | + wlr_log_init(WLR_DEBUG, NULL); |
| 176 | + struct wl_display *display = wl_display_create(); |
| 177 | + struct sample_state state = { |
| 178 | + .color = { 1.0, 0.0, 0.0, 1.0 }, |
| 179 | + .dec = 0, |
| 180 | + .last_frame = { 0 }, |
| 181 | + .display = display |
| 182 | + }; |
| 183 | + struct wlr_backend *backend = wlr_backend_autocreate(wl_display_get_event_loop(display), NULL); |
| 184 | + if (!backend) { |
| 185 | + exit(1); |
| 186 | + } |
| 187 | + |
| 188 | + state.renderer = wlr_renderer_autocreate(backend); |
| 189 | + state.allocator = wlr_allocator_autocreate(backend, state.renderer); |
| 190 | + |
| 191 | + wl_signal_add(&backend->events.new_output, &state.new_output); |
| 192 | + state.new_output.notify = new_output_notify; |
| 193 | + wl_signal_add(&backend->events.new_input, &state.new_input); |
| 194 | + state.new_input.notify = new_input_notify; |
| 195 | + clock_gettime(CLOCK_MONOTONIC, &state.last_frame); |
| 196 | + |
| 197 | + if (!wlr_backend_start(backend)) { |
| 198 | + wlr_log(WLR_ERROR, "Failed to start backend"); |
| 199 | + wlr_backend_destroy(backend); |
| 200 | + exit(1); |
| 201 | + } |
| 202 | + wl_display_run(display); |
| 203 | + wl_display_destroy(display); |
| 204 | +} |
| 205 | + |
0 commit comments