#include "../backend.h" #include "../ctxt/theme.h" #include "../ctxt/window.h" #include "../util.h" #include "../util/region.h" #include "../util/functions.h" #include "../concurrent/msgq.h" #include "../concurrent/msg.h" #include #include #include /* ----------------------------------------------------------------------------- * Backend type * -------------------------------------------------------------------------- */ struct window_list; const char* ax__backend_impl_name = "SDL"; size_t ax__backend_desired_region_size = MEDIUM; struct ax_backend { struct rgn* rgn; struct msgq* inbox; bool shutdown; struct window_list* windows; }; /* ----------------------------------------------------------------------------- * Backend functions * -------------------------------------------------------------------------- */ static void backend_cleanup(struct ax_backend* bac); int ax__backend_new( struct rgn* init_rgn, struct ax_backend** out_bac, const char** out_err) { const char* err; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) { err = SDL_GetError(); goto fail; } if (TTF_Init() != 0) { err = TTF_GetError(); goto fail; } struct ax_backend* bac = ralloc_typed(init_rgn, struct ax_backend, 1); rgn_pin(init_rgn, bac, (void*) backend_cleanup); bac->rgn = init_rgn; bac->inbox = msgq_new(init_rgn); bac->shutdown = false; bac->windows = NULL; if (out_bac != NULL) { *out_bac = bac; } printf("hello from SDL\n"); return 0; fail: if (out_err != NULL) { *out_err = err; } return 1; } static void backend_cleanup(struct ax_backend* bac) { TTF_Quit(); SDL_Quit(); printf("bye from SDL\n"); } struct msgq* ax__backend_msgq(struct ax_backend* bac) { return bac->inbox; } bool ax__backend_is_shutdown(struct ax_backend* bac) { return bac->shutdown; } void ax__backend_wait_for_event(struct ax_backend* bac) { (void) bac; usleep(1000 * 1000 / 60); } /* ----------------------------------------------------------------------------- * Event handling * -------------------------------------------------------------------------- */ struct font_list { struct font_list* next; struct ax_theme* thm; size_t cat; }; struct window_args_list { struct window_args_list* next; struct ax_window* win; const char* title; uint32_t width, height; }; static void load_fonts(struct ax_backend* bac, struct font_list* fl); static void make_windows(struct ax_backend* bac, struct window_args_list* wl); static void handle_events(void); static void render_windows(struct window_list* wl); void ax__backend_step(struct ax_backend* bac) { struct rgn tmp_rgn; rgn_init(&tmp_rgn, SMALL); struct font_list* fonts = NULL; struct window_args_list* windows = NULL; size_t nmsg = 0; msgq_begin_recv(bac->inbox); MSGQ_RECV_ALL(bac->inbox) { ON(ax_msg_shutdown, { nmsg++; (void) m; bac->shutdown = true; break; }); ON(ax_msg_load_font, { nmsg++; struct font_list* l = ralloc_typed(&tmp_rgn, struct font_list, 1); l->next = fonts; l->thm = m.theme; l->cat = m.category; fonts = l; break; }); ON(ax_msg_make_window, { nmsg++; struct window_args_list* l = ralloc_typed(&tmp_rgn, struct window_args_list, 1); l->next = windows; l->win = m.dst_win; l->title = rstrdup(&tmp_rgn, m.title); l->width = m.width; l->height = m.height; windows = l; break; }); default: nmsg++; printf("Got a weird message: `%s'\n", ax__msg_name(m_type)); break; } msgq_end_recv(bac->inbox); load_fonts(bac, fonts); make_windows(bac, ax__reverse_list(windows)); render_windows(bac->windows); handle_events(); rgn_cleanup(&tmp_rgn); // printf("ping. %zu message(s)\n", nmsg); } /* ----------------------------------------------------------------------------- * Event handling * -------------------------------------------------------------------------- */ static void handle_events(void) { SDL_Event ev; while (SDL_PollEvent(&ev)) { switch (ev.type) { case SDL_QUIT: printf("pls quit...\n"); break; default: printf("some event of type: %d\n", ev.type); break; } } } /* ----------------------------------------------------------------------------- * Fonts * -------------------------------------------------------------------------- */ struct ax_font_h { TTF_Font* font; }; static int load_font( struct rgn* rgn, const char* path, size_t size, struct ax_font_h** out_fh, const char** out_err) { printf("loading `%s' (size %zu)\n", path, size); struct ax_font_h* fh = ralloc_typed(rgn, struct ax_font_h, 1); if ((fh->font = TTF_OpenFont(path, size)) == NULL) { *out_err = TTF_GetError(); return 1; } *out_fh = fh; return 0; } static void load_fonts(struct ax_backend* bac, struct font_list* fl) { int rv = 0; const char* err; for (; fl != NULL; fl = fl->next) { struct ax_theme* thm = fl->thm; struct ax_font_h* fh; if ((rv = load_font(bac->rgn, thm->font_path[fl->cat], thm->font_size[fl->cat], &fh, &err)) != 0) { goto fail; } ax__theme_set_font_handle(thm, fl->cat, fh); } fail: ASSERT(rv == 0, "error loading font: %s", err); } /* ----------------------------------------------------------------------------- * Window management * -------------------------------------------------------------------------- */ struct window_list { struct window_list* next; struct ax_window* win; struct window_handle* handle; }; struct window_handle { SDL_Window* win; SDL_Renderer* rnd; }; static void window_handle_cleanup(struct window_handle*); static int new_window_handle( struct rgn* rgn, struct window_args_list* args, struct window_handle** out_wh, const char** out_err) { struct window_handle* wh = ralloc_typed(rgn, struct window_handle, 1); wh->win = NULL; wh->rnd = NULL; rgn_pin(rgn, wh, (void*) window_handle_cleanup); int rv; if ((rv = SDL_CreateWindowAndRenderer((int) args->width, (int) args->height, SDL_WINDOW_SHOWN, &wh->win, &wh->rnd)) != 0) { *out_err = SDL_GetError(); return rv; } SDL_SetWindowTitle(wh->win, args->title); *out_wh = wh; return 0; } static void window_handle_cleanup(struct window_handle* wh) { SDL_DestroyRenderer(wh->rnd); SDL_DestroyWindow(wh->win); } static void make_windows(struct ax_backend* bac, struct window_args_list* args) { int rv = 0; const char* err; struct window_handle* wh; struct window_list* wl; for (; args != NULL; args = args->next) { if ((rv = new_window_handle(bac->rgn, args, &wh, &err)) != 0) { goto fail; } wl = ralloc_typed(bac->rgn, struct window_list, 1); wl->win = args->win; wl->handle = wh; wl->next = bac->windows; bac->windows = wl; } fail: ASSERT(rv == 0, "error: %s", SDL_GetError()); } static void render_windows(struct window_list* wl) { for (; wl != NULL; wl = wl->next) { // SDL_Window* sdl_win = wl->handle->win; SDL_Renderer* r = wl->handle->rnd; SDL_SetRenderDrawColor(r, 255, 255, 255, 255); SDL_RenderClear(r); SDL_RenderPresent(r); } }