Mercurial > molko
view src/libmlk-core-js/core/js-drawable.c @ 363:c74ab1bbedec
js: add drawable bindings
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 24 Oct 2021 09:55:12 +0200 |
parents | |
children | 8ac282bd5935 |
line wrap: on
line source
/* * js-drawable.c -- core drawable binding * * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <assert.h> #include <core/alloc.h> #include <core/drawable.h> #include "js-drawable.h" #define SIGNATURE DUK_HIDDEN_SYMBOL("Mlk.Drawable") struct self { duk_context *ctx; void *ptr; struct drawable dw; unsigned int refc; }; static inline struct self * self(duk_context *ctx) { struct self *sf = NULL; duk_push_this(ctx); duk_get_prop_string(ctx, -1, SIGNATURE); sf = duk_to_pointer(ctx, -1); duk_pop_2(ctx); if (!sf) duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Drawable object"); return sf; } static inline int callable(struct self *s, const char *prop, duk_context **ctx) { int callable; if (!s->ptr) return 0; duk_push_heapptr(s->ctx, s->ptr); duk_get_prop_string(s->ctx, -1, prop); duk_remove(s->ctx, -2); if (duk_is_callable(s->ctx, -1)) { *ctx = s->ctx; callable = 1; } else { *ctx = NULL; callable = 0; duk_pop(s->ctx); } return callable; } static int update(struct drawable *dw, unsigned int ticks) { duk_context *ctx; int ret = 0; if (callable(dw->data, "update", &ctx)) { duk_push_uint(ctx, ticks); duk_call(ctx, 1); ret = duk_to_int(ctx, -1); } return ret; } static void draw(struct drawable *dw) { duk_context *ctx; if (callable(dw->data, "draw", &ctx)) duk_call(ctx, 0); } static void end(struct drawable *dw) { duk_context *ctx; if (callable(dw->data, "end", &ctx)) duk_call(ctx, 0); } static void finish(struct drawable *dw) { struct self *sf = dw->data; if (!--sf->refc) free(sf); } static duk_ret_t Drawable_getX(duk_context *ctx) { duk_push_uint(ctx, self(ctx)->dw.x); return 1; } static duk_ret_t Drawable_setX(duk_context *ctx) { self(ctx)->dw.x = duk_require_uint(ctx, 0); return 0; } static duk_ret_t Drawable_getY(duk_context *ctx) { duk_push_uint(ctx, self(ctx)->dw.y); return 1; } static duk_ret_t Drawable_setY(duk_context *ctx) { self(ctx)->dw.y = duk_require_uint(ctx, 0); return 0; } static duk_ret_t Drawable_constructor(duk_context *ctx) { struct self *self; const int x = duk_require_int(ctx, 0); const int y = duk_require_int(ctx, 1); self = alloc_new0(sizeof (*self)); self->refc = 1; self->ctx = ctx; self->dw.x = x; self->dw.y = y; self->dw.data = self; self->dw.update = update; self->dw.finish = finish; self->dw.draw = draw; self->dw.end = end; duk_push_this(ctx); self->ptr = duk_get_heapptr(ctx, -1); duk_push_pointer(ctx, self); duk_put_prop_string(ctx, -2, SIGNATURE); duk_push_string(ctx, "x"); duk_push_c_function(ctx, Drawable_getX, 0); duk_push_c_function(ctx, Drawable_setX, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); duk_push_string(ctx, "y"); duk_push_c_function(ctx, Drawable_getY, 0); duk_push_c_function(ctx, Drawable_setY, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); duk_pop(ctx); return 0; } static duk_ret_t Drawable_destructor(duk_context *ctx) { struct self *sf; duk_get_prop_string(ctx, 0, SIGNATURE); if ((sf = duk_to_pointer(ctx, -1))) { sf->ptr = NULL; drawable_finish(&sf->dw); } duk_del_prop_string(ctx, 0, SIGNATURE); duk_pop(ctx); return 0; } void js_drawable_bind(duk_context *ctx) { assert(ctx); duk_push_c_function(ctx, Drawable_constructor, 2); duk_push_object(ctx); duk_push_c_function(ctx, Drawable_destructor, 1); duk_set_finalizer(ctx, -2); duk_put_prop_string(ctx, -2, "prototype"); duk_put_global_string(ctx, "Drawable"); } struct drawable * js_drawable_require(duk_context *ctx, duk_idx_t idx) { struct self *sf = NULL; if (duk_is_object(ctx, idx)) { duk_get_prop_string(ctx, idx, SIGNATURE); sf = duk_to_pointer(ctx, -1); duk_pop(ctx); } if (!sf) duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Drawable object"); sf->refc++; return &sf->dw; }