yutani: basic Kuroko bindings, demo 'app'

This commit is contained in:
K. Lange 2021-01-23 15:31:38 +09:00
parent 946c45312c
commit 5fe8d3b0d1
3 changed files with 235 additions and 1 deletions

View File

@ -46,6 +46,8 @@ APPS_X=$(foreach app,$(APPS),base/bin/$(app))
APPS_Y=$(foreach app,$(APPS),.make/$(app).mak)
APPS_SH=$(patsubst apps/%.sh,%.sh,$(wildcard apps/*.sh))
APPS_SH_X=$(foreach app,$(APPS_SH),base/bin/$(app))
APPS_KRK=$(patsubst apps/%.krk,%.krk,$(wildcard apps/*.krk))
APPS_KRK_X=$(foreach app,$(APPS_KRK),base/bin/$(app))
##
# LIBS = C sources from lib/
@ -63,7 +65,7 @@ tags: $(SOURCE_FILES)
##
# Files that must be present in the ramdisk (apps, libraries)
RAMDISK_FILES= ${APPS_X} ${APPS_SH_X} ${LIBS_X} base/lib/ld.so base/lib/libm.so ${KUROKO_FILES}
RAMDISK_FILES= ${APPS_X} ${APPS_SH_X} ${APPS_KRK_X} ${LIBS_X} base/lib/ld.so base/lib/libm.so ${KUROKO_FILES}
# Kernel / module flags
@ -251,6 +253,10 @@ base/bin/%.sh: apps/%.sh
cp $< $@
chmod +x $@
base/bin/%.krk: apps/%.krk
cp $< $@
chmod +x $@
# Ramdisk
fatbase/ramdisk.img: ${RAMDISK_FILES} $(shell find base) Makefile util/createramdisk.py | dirs
python3 util/createramdisk.py

35
apps/krk_yutani_test.krk Normal file
View File

@ -0,0 +1,35 @@
#!/bin/kuroko
import _yutani
# Connect
let y = _yutani.Yutani()
# Create window
let w = _yutani.Window(300,200,title="Kuroko Demo")
w.move(100,100)
def drawWindow():
w.fill()
_yutani.Decorator.render(w)
w.flip()
drawWindow()
while True:
let msg = y.poll()
if msg.type == _yutani.Message.MSG_SESSION_END:
print("Asked to exit.")
break
else if msg.type == _yutani.Message.MSG_KEY_EVENT:
print("key event")
else if msg.type == _yutani.Message.MSG_WINDOW_FOCUS_CHANGE:
print("focus change")
if msg.wid == w.wid:
w.set_focused(msg.focused)
drawWindow()
else if msg.type == _yutani.Message.MSG_WINDOW_MOUSE_EVENT:
if _yutani.Decorator.handle_event(msg) == 2:
print("Clicked close button")
break
print(f"W({msg.wid}) mouse {msg.new_x},{msg.new_y}")

View File

@ -1,6 +1,7 @@
/* Kuroko bindings for Yutani */
#include <assert.h>
#include <toaru/yutani.h>
#include <toaru/decorations.h>
#include "kuroko/src/kuroko.h"
#include "kuroko/src/vm.h"
#include "kuroko/src/value.h"
@ -8,6 +9,8 @@
static KrkClass * Message;
static KrkClass * Yutani;
static KrkClass * YutaniWindow;
static KrkClass * Decorator;
static KrkInstance * module;
static KrkInstance * yctxInstance = NULL;
@ -163,6 +166,9 @@ static KrkValue _yutani_init(int argc, KrkValue argv[], int hasKw) {
krk_runtimeError(vm.exceptions.ioError, "Failed to connect to compositor.");
return NONE_VAL();
}
init_decorations();
fprintf(stderr, "Attaching field...\n");
((struct YutaniClass*)self)->yctx = yctx;
yctxInstance = self;
@ -214,6 +220,173 @@ static KrkValue _yutani_wait_for(int argc, KrkValue argv[]) {
return krk_pop();
}
struct WindowClass {
KrkInstance inst;
yutani_window_t * window;
gfx_context_t * ctx;
int doubleBuffered;
};
#define GET_ARG(p,name,type) do { \
if (hasKw && krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S(#name)), &name)) { \
if (!krk_isInstanceOf(name,type)) \
return krk_runtimeError(vm.exceptions.typeError, #name " argument should be " #type ", not '%s'", krk_typeName(name)); \
} else if (argc > p) { \
name = argv[p]; \
if (!krk_isInstanceOf(name,type)) \
return krk_runtimeError(vm.exceptions.typeError, #name " argument should be " #type ", not '%s'", krk_typeName(name)); \
} \
} while (0)
static KrkValue _window_init(int argc, KrkValue argv[], int hasKw) {
if (!yctxInstance) return krk_runtimeError(vm.exceptions.valueError, "Compositor is not initialized");
if (argc < 1 || !krk_isInstanceOf(argv[0], YutaniWindow))
return krk_runtimeError(vm.exceptions.typeError, "Failed to initialize window");
if (argc < 3 || !IS_INTEGER(argv[1]) || !IS_INTEGER(argv[2]))
return krk_runtimeError(vm.exceptions.argumentError, "Expected at least two (integer) arguments (width, height)");
if (hasKw) argc--;
KrkInstance * _self = AS_INSTANCE(argv[0]);
struct WindowClass * self = (struct WindowClass*)_self;
krk_integer_type width = AS_INTEGER(argv[1]);
krk_integer_type height = AS_INTEGER(argv[2]);
KrkValue flags = INTEGER_VAL(0), title = NONE_VAL(), icon = NONE_VAL(), doublebuffer = BOOLEAN_VAL(0);
GET_ARG(3, flags, vm.baseClasses.intClass);
GET_ARG(4, title, vm.baseClasses.strClass);
GET_ARG(5, icon, vm.baseClasses.strClass);
GET_ARG(6, doublebuffer, vm.baseClasses.boolClass);
self->window = yutani_window_create_flags(((struct YutaniClass*)yctxInstance)->yctx,
width, height, AS_INTEGER(flags));
self->doubleBuffered = AS_BOOLEAN(doublebuffer);
if (self->doubleBuffered) {
self->ctx = init_graphics_yutani_double_buffer(self->window);
} else {
self->ctx = init_graphics_yutani(self->window);
}
if (!IS_NONE(title)) {
if (!IS_NONE(icon)) {
yutani_window_advertise_icon(((struct YutaniClass*)yctxInstance)->yctx, self->window, AS_CSTRING(title), AS_CSTRING(icon));
} else {
yutani_window_advertise(((struct YutaniClass*)yctxInstance)->yctx, self->window, AS_CSTRING(title));
}
}
krk_attachNamedValue(&_self->fields, "title", title);
krk_attachNamedValue(&_self->fields, "icon", icon);
krk_attachNamedValue(&_self->fields, "closed", BOOLEAN_VAL(0));
return argv[0];
}
static KrkValue _window_fill(int argc, KrkValue argv[]) {
if (argc < 1 || !krk_isInstanceOf(argv[0], YutaniWindow))
return krk_runtimeError(vm.exceptions.typeError, "expected window");
KrkInstance * _self = AS_INSTANCE(argv[0]);
struct WindowClass * self = (struct WindowClass*)_self;
draw_fill(self->ctx, rgba(127,127,127,255));
return NONE_VAL();
}
static KrkValue _window_flip(int argc, KrkValue argv[]) {
if (argc < 1 || !krk_isInstanceOf(argv[0], YutaniWindow))
return krk_runtimeError(vm.exceptions.typeError, "expected window");
KrkInstance * _self = AS_INSTANCE(argv[0]);
struct WindowClass * self = (struct WindowClass*)_self;
if (self->doubleBuffered) {
flip(self->ctx);
}
yutani_flip(((struct YutaniClass*)yctxInstance)->yctx, self->window);
return NONE_VAL();
}
static KrkValue _window_move(int argc, KrkValue argv[]) {
if (argc < 1 || !krk_isInstanceOf(argv[0], YutaniWindow))
return krk_runtimeError(vm.exceptions.typeError, "expected window");
if (argc < 3 || !IS_INTEGER(argv[1]) || !IS_INTEGER(argv[2]))
return krk_runtimeError(vm.exceptions.typeError, "expected two integer arguments");
KrkInstance * _self = AS_INSTANCE(argv[0]);
struct WindowClass * self = (struct WindowClass*)_self;
yutani_window_move(((struct YutaniClass*)yctxInstance)->yctx, self->window, AS_INTEGER(argv[1]), AS_INTEGER(argv[2]));
return NONE_VAL();
}
static KrkValue _window_set_focused(int argc, KrkValue argv[]) {
if (argc < 1 || !krk_isInstanceOf(argv[0], YutaniWindow))
return krk_runtimeError(vm.exceptions.typeError, "expected window");
if (argc < 2 || !IS_INTEGER(argv[1]))
return krk_runtimeError(vm.exceptions.typeError, "expected integer argument");
KrkInstance * _self = AS_INSTANCE(argv[0]);
struct WindowClass * self = (struct WindowClass*)_self;
self->window->focused = AS_INTEGER(argv[1]);
return NONE_VAL();
}
#define WINDOW_PROPERTY(name) \
static KrkValue _window_ ## name (int argc, KrkValue argv[]) { \
KrkInstance * _self = AS_INSTANCE(argv[0]); \
struct WindowClass * self = (struct WindowClass*)_self; \
return INTEGER_VAL(self->window-> name); \
}
WINDOW_PROPERTY(width);
WINDOW_PROPERTY(height);
WINDOW_PROPERTY(wid);
WINDOW_PROPERTY(focused);
static KrkValue _decor_get_bounds(int argc, KrkValue argv[]) {
if (argc > 0 && !krk_isInstanceOf(argv[0], YutaniWindow))
return krk_runtimeError(vm.exceptions.typeError, "expected window");
struct decor_bounds bounds;
decor_get_bounds((argc > 0) ? ((struct WindowClass*)AS_INSTANCE(argv[0]))->window : NULL,
&bounds);
KRK_PAUSE_GC();
KrkValue result = krk_dict_of(6 * 2, (KrkValue[]) {
OBJECT_VAL(S("top_height")), INTEGER_VAL(bounds.top_height),
OBJECT_VAL(S("bottom_height")), INTEGER_VAL(bounds.bottom_height),
OBJECT_VAL(S("left_width")), INTEGER_VAL(bounds.left_width),
OBJECT_VAL(S("right_width")), INTEGER_VAL(bounds.right_width),
OBJECT_VAL(S("width")), INTEGER_VAL(bounds.width),
OBJECT_VAL(S("height")), INTEGER_VAL(bounds.height)
});
KRK_RESUME_GC();
return result;
}
static KrkValue _decor_handle_event(int argc, KrkValue argv[]) {
if (argc < 1 || !krk_isInstanceOf(argv[0], Message))
return krk_runtimeError(vm.exceptions.typeError, "expected message");
return INTEGER_VAL(decor_handle_event(((struct YutaniClass*)yctxInstance)->yctx, ((struct MessageClass*)AS_INSTANCE(argv[0]))->msg));
}
static KrkValue _decor_render(int argc, KrkValue argv[]) {
if (argc < 1 || !krk_isInstanceOf(argv[0], YutaniWindow))
return krk_runtimeError(vm.exceptions.typeError, "expected window");
char * title = (argc > 1 && IS_STRING(argv[1])) ? AS_CSTRING(argv[1]) : NULL;
if (title == NULL) {
KrkValue winTitle;
if (!krk_tableGet(&AS_INSTANCE(argv[0])->fields, OBJECT_VAL(S("title")), &winTitle) || !IS_STRING(winTitle)) {
title = "";
} else {
title = AS_CSTRING(winTitle);
}
}
render_decorations(((struct WindowClass*)AS_INSTANCE(argv[0]))->window,
((struct WindowClass*)AS_INSTANCE(argv[0]))->ctx, title);
return NONE_VAL();
}
KrkValue krk_module_onload__yutani(void) {
fprintf(stderr, "Loading...\n");
module = krk_newInstance(vm.moduleClass);
@ -272,6 +445,26 @@ KrkValue krk_module_onload__yutani(void) {
#endif
krk_finalizeClass(Yutani);
YutaniWindow = krk_createClass(module, "Window", NULL);
YutaniWindow->allocSize = sizeof(struct WindowClass);
krk_defineNative(&YutaniWindow->methods, ".__init__", _window_init);
krk_defineNative(&YutaniWindow->methods, ".fill", _window_fill);
krk_defineNative(&YutaniWindow->methods, ".flip", _window_flip);
krk_defineNative(&YutaniWindow->methods, ".move", _window_move);
krk_defineNative(&YutaniWindow->methods, ".set_focused", _window_set_focused);
/* Properties */
krk_defineNative(&YutaniWindow->methods, ":width", _window_width);
krk_defineNative(&YutaniWindow->methods, ":height", _window_height);
krk_defineNative(&YutaniWindow->methods, ":wid", _window_wid);
krk_defineNative(&YutaniWindow->methods, ":focused", _window_focused);
krk_finalizeClass(YutaniWindow);
Decorator = krk_createClass(module, "Decorator", NULL);
krk_defineNative(&Decorator->fields, "get_bounds", _decor_get_bounds);
krk_defineNative(&Decorator->fields, "render", _decor_render);
krk_defineNative(&Decorator->fields, "handle_event", _decor_handle_event);
krk_finalizeClass(Decorator);
/**
* class MsgKeyEvent(Message):