Rudimentary event handling
[clav.git] / ui-sdl.c
blob9d3277754a9d5d7449275ca19160d5d9f68573a9
1 #include <errno.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
6 #include <SDL.h>
8 #include "macros.h"
9 #include "ui.h"
11 #define TICKS_PER_FRAME (1000 / 60)
13 /* The window we'll be using */
14 static SDL_Window *sdl_win;
16 /* The screen surface we'll be using */
17 static SDL_Surface *sdl_surf;
19 /* How to limit the framerate */
20 static Uint32 frame_start_ticks;
22 /* If conf/deny, the message onscreen */
23 static const char *conf_deny_text;
25 /* Buffer for event queue */
26 static struct ui_event *eq_buf;
28 /* Current max length of event queue */
29 static size_t eq_len;
31 /* Current head of queue */
32 static size_t eq_head;
34 /* Current tail of queue */
35 static size_t eq_tail;
37 /* Pop from queue */
38 static void eq_pop(struct ui_event *out)
40 if (eq_head == eq_tail) {
41 *out = (struct ui_event) { 0 };
43 return;
46 memcpy(out, eq_buf + eq_head, sizeof *out);
47 eq_buf[eq_head] = (struct ui_event) { 0 };
48 eq_head = (eq_head + 1) % eq_len;
51 /* Push into queue */
52 static int eq_push(struct ui_event *in)
54 void *newmem;
55 int sv_err;
57 if (((eq_tail + 1) % eq_len) == eq_head) {
58 if ((eq_len * sizeof *in) >= ((size_t) -1) / 2) {
59 fprintf(stderr, L(
60 "eq_push: Impossibly large buffer\n"));
62 return ENOMEM;
65 if (!(newmem = realloc(eq_buf, (eq_len * 2) *
66 sizeof *eq_buf))) {
67 sv_err = errno;
68 perror(L("realloc"));
70 return sv_err;
73 eq_buf = (struct ui_event *) newmem;
74 eq_len *= 2;
77 memcpy(eq_buf + eq_tail, in, sizeof *in);
78 eq_tail = (eq_tail + 1) % eq_len;
80 return 0;
83 /* Initialize SDL */
84 int ui_init(void)
86 int sv_err;
88 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
89 fprintf(stderr, L("SDL_Init(): %s\n"), SDL_GetError());
91 return ENOMEDIUM;
94 sdl_win = SDL_CreateWindow("Cluster Algebra Visualizer",
95 SDL_WINDOWPOS_UNDEFINED,
96 SDL_WINDOWPOS_UNDEFINED, 800, 600,
97 SDL_WINDOW_SHOWN);
99 if (!sdl_win) {
100 fprintf(stderr, L("SDL_CreateWindow(): %s\n"), SDL_GetError());
102 return ENOMEDIUM;
105 sdl_surf = SDL_GetWindowSurface(sdl_win);
107 if (!sdl_surf) {
108 fprintf(stderr, L("SDL_GetWindowSurface(): %s\n"),
109 SDL_GetError());
111 return ENOMEDIUM;
114 SDL_FillRect(sdl_surf, 0, SDL_MapRGB(sdl_surf->format, 0xe2, 0xe2,
115 0xe2));
116 SDL_UpdateWindowSurface(sdl_win);
118 /* Set up queue for returning data */
119 if (!(eq_buf = calloc(2, sizeof *eq_buf))) {
120 sv_err = errno;
121 perror(L("malloc"));
123 return sv_err;
126 eq_len = 2;
127 eq_head = 0;
128 eq_tail = 0;
130 return 0;
133 /* Tear down SDL */
134 int ui_teardown(void)
136 if (sdl_win) {
137 SDL_DestroyWindow(sdl_win);
140 SDL_Quit();
142 return 0;
145 /* Record that a frame has been started */
146 int ui_start_frame(void)
148 frame_start_ticks = SDL_GetTicks();
150 return 0;
153 /* Draw a frame, possibly sleeping for framelimit */
154 int ui_finish_frame(void)
156 Uint32 now = 0;
157 Uint32 elapsed_time = 0;
158 SDL_Event sdl_e = { 0 };
159 struct ui_event ui_e = { 0 };
161 /* Draw the damn thing */
164 * draw();
167 /* Handle user input */
168 while (SDL_PollEvent(&sdl_e) != 0) {
169 switch (sdl_e.type) {
170 case SDL_QUIT:
171 ui_e = (struct ui_event) { .type = ET_FORCE_QUIT };
172 eq_push(&ui_e);
173 break;
174 case SDL_KEYUP:
175 break;
179 /* framelimit */
180 now = SDL_GetTicks();
182 if (frame_start_ticks < now) {
183 elapsed_time = now - frame_start_ticks;
185 if (elapsed_time < TICKS_PER_FRAME) {
186 SDL_Delay(TICKS_PER_FRAME - elapsed_time);
190 return 0;
193 /* Return an event to the main loop */
194 int ui_get_event(struct ui_event *e, uint_fast8_t *more)
196 eq_pop(e);
197 *more = eq_head != eq_tail;
199 return 0;
202 /* Be told to display a confirm dialog */
203 int ui_confirm_deny(const char *s)
205 conf_deny_text = s;
207 return 0;