300 lines
7.4 KiB
C
300 lines
7.4 KiB
C
#include "../backend.h"
|
|
#include "../ctxt/theme.h"
|
|
#include "../ctxt/window.h"
|
|
#include "../util.h"
|
|
#include "../util/region.h"
|
|
#include "../concurrent/msgq.h"
|
|
#include "../concurrent/msg.h"
|
|
#include <unistd.h>
|
|
#include <SDL2/SDL.h>
|
|
#include <SDL2/SDL_ttf.h>
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 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 * 100);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 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 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(mqr__type));
|
|
break;
|
|
}
|
|
msgq_end_recv(bac->inbox);
|
|
|
|
load_fonts(bac, fonts);
|
|
make_windows(bac, windows);
|
|
render_windows(bac->windows);
|
|
|
|
rgn_cleanup(&tmp_rgn);
|
|
// printf("ping. %zu message(s)\n", nmsg);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 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 cleanup_window_handle(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*) cleanup_window_handle);
|
|
|
|
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 cleanup_window_handle(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);
|
|
}
|
|
}
|