A lot of stuff...

This commit is contained in:
lda 2024-02-28 21:56:58 +01:00
parent 07ae5a8566
commit 55395ec2cf
26 changed files with 977 additions and 118 deletions

View File

@ -11,6 +11,7 @@ include(Fxconv)
find_package(Gint 2.9 REQUIRED)
find_package(JustUI 1.3.0 REQUIRED)
find_package(LibImg 2.1 REQUIRED)
find_package(cPNG 1.5.30 REQUIRED)
AUX_SOURCE_DIRECTORY(src SOURCES)
# Shared assets, fx-9860G-only assets and fx-CG-50-only assets
@ -31,6 +32,7 @@ set(ASSETS_cg
assets-cg/file.png
assets-cg/tweak.png
assets-cg/tbold.png
assets-cg/bouncer.png
assets-cg/mastrix-print.png
)
@ -38,9 +40,10 @@ fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA)
add_executable(mastrix ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}})
include_directories(src/include)
target_compile_options(mastrix PRIVATE -Wall -Wextra -O0 -g)
target_compile_options(mastrix PRIVATE -Wall -Wextra -O0 -g -finstrument-functions)
target_link_libraries(mastrix Gint::Gint JustUI::JustUI LibImg::LibImg)
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
# honestly i dont have an fx-9860G to test with.
generate_g1a(TARGET mastrix OUTPUT "MyAddin.g1a"

6
TODO
View File

@ -1,2 +1,4 @@
Bug at 8c215e86, apparently related to jwidget_remove_child, when scrolling up it seems...
It happens early on, must be a BAD CHECK.
- Commands (and a catalog system)
- Save user info to be loaded later
- Custom reactions
- ????

View File

@ -10,6 +10,9 @@ hourglass.png:
file.png:
type: bopti-image
name: fileicon
bouncer.png:
type: bopti-image
name: bouncer
cc.png:
type: font
@ -25,7 +28,7 @@ tweak.png:
tbold.png:
type: font
charset: print
grid.size: 10x21
grid.size: 8x18
name: terminus_strong

View File

@ -65,6 +65,24 @@ void utils_array_set(array_t *arr, size_t idx, void *val)
arr->list[idx] = val;
}
void utils_array_pop(array_t *arr)
{
void **newe;
if (!arr)
{
return;
}
if (arr->capacity <= 0)
{
return;
}
/* Remove the latest element */
arr->capacity--;
newe = malloc(sizeof(void *) * arr->capacity);
memcpy(newe, arr->list, sizeof(void *) * arr->capacity);
arr->list = newe;
}
void utils_free_array(array_t *arr)
{

198
src/blurhash.c Normal file
View File

@ -0,0 +1,198 @@
/*#include <utils.h>*/
#include <gint/display.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define PI 3.14152
/* Converts a value to a blurhash */
uint8_t table[256] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,63,64,0,0,0,0,65,66,67,68,69,0,0,1,2,3,4,5,6,7,8,9,70,71,0,72,0,73,74,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,75,0,76,77,78,0,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,79,80,81,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/* Reads a blurhash number */
static uint32_t read_number(char *str, size_t n)
{
uint32_t v = 0;
size_t i;
for (i = 0; i < n; i++)
{
char c = str[i];
if (!c)
{
break;
}
v += table[c];
v *= 83;
}
v /= 83;
return v;
}
uint16_t gco(char *coeff, int i, int j, int nx, int ny)
{
size_t offset;
uint16_t v;
if (i == 0 && j == 0)
{
/* It isn't my job to manage the DC */
return 0;
}
offset = ((nx * j + i) * 2) + 2;
v = read_number(coeff + offset, 2);
return v;
}
float ch_to_float(uint8_t coeff, uint8_t max)
{
int s = coeff < 9 ? -1 : 1;
float max_float = (max + 1) / 166.0;
float coeff_float = s * powf((coeff - 9) / 9.0, 2);
return coeff_float * max_float;
}
typedef struct rgb {
float r, g, b;
} rgb_t;
rgb_t ac_coeff_to_color(uint16_t coeff, uint8_t max)
{
uint8_t r, g, b;
float fr, fg, fb;
r = (coeff / (19*19)) % 19;
g = (coeff / 19 ) % 19;
b = (coeff ) % 19;
fr = ch_to_float(r, max);
fg = ch_to_float(g, max);
fb = ch_to_float(b, max);
return (rgb_t) { .r = fr, .g = fg, .b = fb };
}
/* stolen lol */
static inline float to_linear(int value)
{
float v = (float)value / 255;
if(v <= 0.04045) return v / 12.92;
else return powf((v + 0.055) / 1.055, 2.4);
}
static inline int to_srgb(float value)
{
float v = fmaxf(0, fminf(1, value));
if(v <= 0.0031308) return v * 12.92 * 255 + 0.5;
else return (1.055 * powf(v, 1 / 2.4) - 0.055) * 255 + 0.5;
}
rgb_t dc_coeff_to_color(uint32_t srgb, uint8_t max)
{
float fr, fg, fb;
fr = to_linear(((srgb >> (8 * 2)) & 0xFF));
fg = to_linear(((srgb >> (8 * 1)) & 0xFF));
fb = to_linear(((srgb >> (8 * 0)) & 0xFF));
return (rgb_t) { .r = fr, .g = fg, .b = fb };
}
uint16_t *utils_decode_blurhash(char *str, int *ow, int *oh)
{
uint16_t *buf;
rgb_t *coeffs;
rgb_t *colors;
uint8_t component;
uint8_t nx, ny;
uint8_t max_ac;
size_t x, y;
size_t i, j;
if (!str)
{
return NULL;
}
component = read_number(str, 1);
ny = (component / 9) + 1;
nx = (component % 9) + 1;
if (*ow == 0) *ow = nx;
if (*oh == 0) *oh = nx;
str += 1;
max_ac = read_number(str, 1);
str += 1;
/* Setup coefficients */
coeffs = malloc(nx * ny * sizeof(rgb_t));
for (j = 0; j < ny; j++)
{
for (i = 0; i < nx; i++)
{
uint16_t c;
if (i == 0 && j == 0)
{
/* DC coeff */
coeffs[0] = dc_coeff_to_color(read_number(str, 4), max_ac);
continue;
}
c = gco(str, i, j, nx, ny);
coeffs[j * nx + i] = ac_coeff_to_color(c, max_ac);
}
}
/* Now, it's math time. */
colors = malloc((*ow) * (*oh) * sizeof(rgb_t));
for (y = 0; y < *oh; y++)
{
for (x = 0; x < *ow; x++)
{
size_t i, j;
rgb_t rgb = { .r = 0., .g = 0., .b = 0. };
/* Comical amount of nesting */
for (j = 0; j < ny; j++)
{
for (i = 0; i < nx; i++)
{
rgb_t cij = coeffs[j * nx + i];
float k = cosf(((float)x * i * PI)/ *ow) * cosf((y * j * PI)/ *oh);
rgb.r += cij.r * k;
rgb.g += cij.g * k;
rgb.b += cij.b * k;
}
}
colors[y * *ow + x] = rgb;
}
}
buf = malloc(nx * ny * sizeof(uint16_t));
/* WRITE to buf */
for (y = 0; y < *oh; y++)
{
for (x = 0; x < *ow; x++)
{
rgb_t c = colors[y * *ow + x];
uint8_t cr, cg, cb;
cr = to_srgb(c.r);
cg = to_srgb(c.g);
cb = to_srgb(c.b);
buf[y * *ow + x] = C_RGB(
(31 * cr)/255,
(31 * cg)/255,
(31 * cb)/255
);
}
}
free(coeffs);
free(colors);
return buf;
}

63
src/command.c Normal file
View File

@ -0,0 +1,63 @@
#include <command.h>
#include <stdlib.h>
#include <string.h>
#include <utils.h>
command_t *command_parse(char *str)
{
command_t *ret;
char *name, *argstart;
if (!str)
{
return NULL;
}
if (*str != '/')
{
return NULL;
}
/* TODO */
str++;
argstart = str;
while (*str != ' ' && *str)
{
str++;
}
if (argstart == str)
{
/* Empty name, give up. */
return NULL;
}
name = malloc((size_t) (str - argstart) + 1);
memcpy(name, argstart, (size_t) (str - argstart));
name[(size_t) (str - argstart)] = '\0';
while (*str)
{
while (*str != ' ' && *str)
{
str++;
}
}
return ret;
}
void command_free(command_t *c)
{
size_t i;
if (!c)
{
return;
}
free(c->command);
for (i = 0; i < utils_array_size(c->arguments); i++)
{
free(utils_array_get(c->arguments, i));
}
utils_free_array(c->arguments);
free(c);
}

152
src/dbg.c Normal file
View File

@ -0,0 +1,152 @@
/* Debugging */
#include <dbg.h>
#include <gint/drivers/keydev.h>
#include <gint/usb-ff-bulk.h>
#include <gint/hardware.h>
#include <gint/keyboard.h>
#include <gint/display.h>
#include <gint/gint.h>
#include <gint/exc.h>
#include <gint/usb.h>
#include <string.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <info.h>
volatile static uintptr_t *stacktrace = NULL;
volatile static size_t idx = 0;
volatile static size_t allocated = 0;
static const char *dbg_to_str(uint32_t code)
{
/* Stolen from gint */
const char *name = "";
if(code == 0x040) name = "TLB miss (nonexisting address) on read";
if(code == 0x060) name = "TLB miss (nonexisting address) on write";
if(code == 0x0e0) name = "Read address error (probably alignment)";
if(code == 0x100) name = "Write address error (probably alignment)";
if(code == 0x160) name = "Unconditional trap";
if(code == 0x180) name = "Illegal instruction";
if(code == 0x1a0) name = "Illegal delay slot instruction";
/* Custom gint codes for convenience */
if(code == 0x1020) name = "DMA address error";
if(code == 0x1040) name = "Add-in not fully mapped (too large)";
if(code == 0x1060) name = "Memory initialization failed (heap)";
if(code == 0x1080) name = "Stack overflow during world switch";
return name;
}
static void __attribute__((noreturn,no_instrument_function)) dbg_panic(uint32_t code)
{
uint32_t TEA, TRA;
uint32_t PC;
uint32_t SGR = 0xffffffff;
uint32_t *long_vram;
const char *name;
TEA = *(volatile uint32_t *)0xff00000c;
TRA = *(volatile uint32_t *)0xff000020 >> 2;
__asm__("stc spc, %0" : "=r"(PC));
if(isSH4()) __asm__("stc sgr, %0" : "=r"(SGR));
name = dbg_to_str(code);
/* Display to the user */
dclear(C_WHITE);
dtext(1, 1, C_BLACK, MASTRIX_NAME " has crashed.");
/* gint trick */
long_vram = (void *)gint_vram;
for(int i = 0; i < 198 * 16; i++) long_vram[i] = ~long_vram[i];
dprint(10, 22, C_BLACK, name);
dprint(1, 44, C_BLACK, "PC: %08x", PC);
dprint(1, 55, C_BLACK, "TEA: %08x", TEA);
dprint(1, 66, C_BLACK, "TRA: %#x", TRA);
if (usb_is_open())
{
dprint(1, 88, C_BLACK, "Sending trace over USB.");
}
dupdate();
/* Send trace over USB */
if (usb_is_open())
{
int out = usb_ff_bulk_output();
usb_fxlink_header_t header;
stacktrace[idx++] = (uintptr_t) PC;
usb_fxlink_fill_header(
&header,
"dbg", "crash",
idx * sizeof(uintptr_t)
);
usb_write_sync(out, &header, sizeof(usb_fxlink_header_t), false);
usb_write_sync(out, stacktrace, idx * sizeof(uintptr_t), false);
usb_commit_sync(out);
/* We aren't going to wait for anything here. */
}
dbg_end();
while (true);
}
void dbg_init(void)
{
allocated = 4096;
stacktrace = malloc(allocated * sizeof(uintptr_t));
gint_panic_set(dbg_panic);
}
void dbg_end(void)
{
if (!stacktrace)
{
return;
}
free((void *) stacktrace);
gint_panic_set(NULL);
}
void *dbg_get(size_t off)
{
size_t loc = idx - off;
if (off > idx)
{
return NULL;
}
return (void *) stacktrace[loc];
}
void __attribute__((no_instrument_function)) __cyg_profile_func_enter(void *this, void *callee)
{
if (!stacktrace)
{
return;
}
if (idx >= allocated)
{
/* TODO: Reallocate */
return;
}
stacktrace[idx++] = (uintptr_t) this;
}
void __attribute__((no_instrument_function)) __cyg_profile_func_exit(void *this, void *callee)
{
if (!stacktrace)
{
return;
}
if (idx <= 0)
{
return;
}
stacktrace[--idx] = (uintptr_t) NULL;
}

31
src/dvd.c Normal file
View File

@ -0,0 +1,31 @@
#include <gint/display.h>
#include <gint/image.h>
#include <stdlib.h>
extern bopti_image_t const bouncer;
void easter_dvd_frame(const char *str)
{
static int x = -100, y = -100;
static int dx = 10, dy = 8;
int w = bouncer.width, h = bouncer.height;
if (x == -100 && y == -100)
{
x = rand() % DWIDTH;
y = rand() % DHEIGHT;
}
x += dx;
y += dy;
if (x > DWIDTH - w) dx *= -1;
if (x < 0) dx *= -1;
if (y > DHEIGHT - h) dy *= -1;
if (y < 0) dy *= -1;
dclear(C_BLACK);
dtext(1, 1, C_WHITE, str);
dimage(x, y, &bouncer);
dupdate();
}

View File

@ -16,37 +16,36 @@ extern bopti_image_t fileicon;
extern font_t terminus_weak;
extern font_t terminus_strong;
static void *render_span(void *p, struct DomElement *dom)
typedef struct dom_state {
bool italic, bold;
int bg, fg;
} dom_state_t;
static void *render_span(void *p, struct DomElement *dom, dom_state_t state)
{
jlabel *label;
label = jlabel_create("", p);
jlabel_asprintf(label, "%s", dom->textNode);
if (state.italic)
{
jlabel_set_font(label, &terminus_weak);
}
if (state.bold)
{
jlabel_set_font(label, &terminus_strong);
}
if (state.bg != C_NONE)
{
jwidget_set_background(label, state.bg);
}
if (state.fg != C_NONE)
{
jlabel_set_text_color(label, state.fg);
}
return label;
}
static void *render_i(void *p, struct DomElement *dom)
static jwidget *parse_msg_body_dom(void *p, struct DomElement *dom, dom_state_t s)
{
jlabel *label;
label = jlabel_create("", p);
jlabel_asprintf(label, "%s", dom->textNode);
jlabel_set_font(label, &terminus_weak);
return label;
}
static void *render_strong(void *p, struct DomElement *dom)
{
jlabel *label;
label = jlabel_create("", p);
jlabel_asprintf(label, "%s", dom->textNode);
jlabel_set_font(label, &terminus_strong);
return label;
}
static jwidget *parse_msg_body_html(void *p, char *html)
{
struct el_t *top;
struct DomElement *dom;
char *contained, *cpy;
size_t i;
jwidget *container = jwidget_create(p);
jwidget *line;
@ -57,6 +56,100 @@ static jwidget *parse_msg_body_html(void *p, char *html)
jlayout_set_hbox(line)->spacing = 1;
jwidget_set_stretch(line, 1, 0, false);
for (i = 0; i < dom->childnum; i++)
{
struct DomElement *item = dom->children[i];
if (!strcmp(item->tagName, "span"))
{
render_span(line, item, s);
}
else if (!strcmp(item->tagName, "u"))
{
jwidget *box = jwidget_create(line);
jwidget *ul;
jwidget *l;
jlayout_set_vbox(box)->spacing = 1;
jwidget_set_stretch(box, 1, 0, false);
l = parse_msg_body_dom(box, item, s);
ul = jwidget_create(box);
jwidget_set_stretch(ul, 1, 0, false); /* TODO: Make ul *work* */
jwidget_set_stretch(l, 1, 0, false);
jwidget_set_minimum_width(ul, l->w);
log_text("%s: size=%d", __func__, l->w);
jwidget_set_minimum_height(ul, 1);
jwidget_set_maximum_height(ul, 1);
jwidget_set_border(ul, J_BORDER_SOLID, 1, C_BLACK);
}
else if(!strcmp(item->tagName, "i") ||
!strcmp(item->tagName, "em"))
{
dom_state_t sc = s;
sc.italic = true;
parse_msg_body_dom(line, item, sc);
}
else if (!strcmp(item->tagName, "code"))
{
dom_state_t sc = s;
sc.italic = true;
sc.bg = GRAY;
sc.fg = C_RGB(31, 24, 25);
parse_msg_body_dom(line, item, sc);
}
else if (!strcmp(item->tagName, "strong"))
{
dom_state_t sc = s;
sc.bold = true;
parse_msg_body_dom(line, item, sc);
}
else if (!strcmp(item->tagName, "p"))
{
parse_msg_body_dom(line, item, s);
line = jwidget_create(container);
jlayout_set_hbox(line)->spacing = 1;
}
else if (!strcmp(item->tagName, "h1"))
{
void *w;
dom_state_t sc = s;
sc.bold = true;
sc.fg = GRAY;
w = parse_msg_body_dom(line, item, sc);
line = jwidget_create(container);
jlayout_set_hbox(line)->spacing = 1;
jwidget_set_stretch(line, 1, 0, false);
parse_msg_body_dom(line, item, s);
}
else if (!strcmp(item->tagName, "br"))
{
size_t j;
line = jwidget_create(container);
jlayout_set_hbox(line)->spacing = 1;
jwidget_set_stretch(line, 1, 0, false);
parse_msg_body_dom(line, item, s);
}
else
{
return NULL;
}
}
return container;
}
static jwidget *parse_msg_body_html(void *p, char *html)
{
struct el_t *top;
struct DomElement *dom;
char *contained, *cpy;
jwidget *container;
size_t i;
dom_state_t def = {
.bg = C_NONE, .fg = C_NONE,
.bold = false, .italic = false
};
contained = utils_strcat("<html>", html);
cpy = contained;
contained = utils_strcat(contained, "</html>");
@ -71,50 +164,13 @@ static jwidget *parse_msg_body_html(void *p, char *html)
dom = top->dom;
/* Actually manage the HTML */
for (i = 0; i < dom->childnum; i++)
container = parse_msg_body_dom(p, dom, def);
if (!container)
{
struct DomElement *item = dom->children[i];
if (!strcmp(item->tagName, "span"))
{
render_span(line, item);
}
if (!strcmp(item->tagName, "i") ||
!strcmp(item->tagName, "em"))
{
render_i(line, item->children[0]);
}
if (!strcmp(item->tagName, "code"))
{
jlabel *l = render_i(line, item->children[0]);
log_text("%s: %d children", item->childnum);
jwidget_set_background(l, GRAY);
jlabel_set_text_color(l, C_RGB(31, 24, 25));
}
if (!strcmp(item->tagName, "strong"))
{
render_strong(line, item->children[0]);
}
if (!strcmp(item->tagName, "h1"))
{
jlabel *w = render_strong(line, item->children[0]);
jlabel_set_text_color(w, GRAY);
line = jwidget_create(container);
jlayout_set_hbox(line)->spacing = 1;
jwidget_set_stretch(line, 1, 0, false);
}
if (!strcmp(item->tagName, "br"))
{
line = jwidget_create(container);
jlayout_set_hbox(line)->spacing = 1;
jwidget_set_stretch(line, 1, 0, false);
jlabel *l = jlabel_create("go brrrr", line);
jlabel_asprintf(l, "%d/%d %d", i + 1, dom->childnum, item->childnum);
}
free(contained);
html_clear();
return NULL;
}
free(contained);
html_clear();

15
src/include/command.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef MATRIX_COMMAND_H
#define MATRIX_COMMAND_H
#include <utils.h>
/* TODO */
typedef struct command {
char *command;
array_t *arguments;
} command_t;
extern command_t *command_parse(char *);
extern void command_free(command_t *);
#endif

10
src/include/dbg.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef MATRIX_DBG_H
#define MATRIX_DBG_H
#include <stddef.h>
extern void dbg_init(void);
extern void * dbg_get(size_t);
extern void dbg_end(void);
#endif

View File

@ -2,5 +2,6 @@
#define MATRIX_EASTERS_H
extern void easter_goda(void);
extern void easter_dvd_frame(const char *);
#endif

View File

@ -18,6 +18,6 @@
#define MASTRIX_PLAT "(unknown)"
#endif
#define MASTRIX_UA (MASTRIX_NAME " " MASTRIX_VERS " (" MASTRIX_VERS ")")
#define MASTRIX_UA MASTRIX_NAME " " MASTRIX_VERS " (" MASTRIX_VERS ")"
#endif

View File

@ -111,4 +111,5 @@ extern void matrix_show_event(m_room_t *, m_user_t *, m_event_t *, jwidget *);
extern char *matrix_send_file(m_user_t *, char *, char *);
#endif

View File

@ -55,6 +55,8 @@ typedef struct ui_screen {
screen_setup_t init;
screen_focus_t on_focus;
screen_event_t on_event;
void (*end)(struct ui_screen *that);
} ui_screen_t;
extern ui_session_t * ui_create_session(void);
@ -69,7 +71,7 @@ extern void *ui_get_data(ui_session_t *, char *);
extern void ui_add_data(ui_session_t *, char *, void *, end_value);
extern void ui_session_loop(ui_session_t *);
extern bool ui_manage_event(ui_session_t *, jevent);
extern void ui_destroy_session(ui_session_t *);
extern void ui_destroy_screen(ui_session_t *);
/* == EXTRA JUSTUI TYPES == */
struct jmlist;
@ -108,10 +110,12 @@ extern uint16_t JMLIST_ITEM_NOP;
extern jmlist *jmlist_create(void *, jmlist_set_widget, jmlist_free_data);
extern int jmlist_selected(jmlist *);
extern int jmlist_add_item(jmlist *, void *);
extern int jmlist_prepend_item(jmlist *, void *);
extern int jmlist_select(jmlist *, int);
extern bool jmlist_scroll(jmlist *, jrect);
extern jrect jmlist_scrolled(jmlist *, jrect);
extern jpainted *ui_image(void *, const bopti_image_t *);
extern jpainted *ui_blurhash(void *, char *);
#endif

View File

@ -6,6 +6,7 @@
#include <justui/jscene.h>
extern void * ui_infos_init(ui_screen_t *that);
extern void * ui_infos_event(ui_screen_t *that, jevent e);
extern void * ui_login_init(ui_screen_t *that);
extern void * ui_login_focus(ui_screen_t *that);

View File

@ -33,6 +33,7 @@ extern void utils_array_shift(array_t *, size_t);
extern size_t utils_array_size(array_t *);
extern void * utils_array_get(array_t *, size_t);
extern void utils_array_set(array_t *, size_t, void *);
extern void utils_array_pop(array_t *);
extern void utils_free_array(array_t *);
typedef struct json_value json_value_t;
@ -65,4 +66,6 @@ extern json_value_t * utils_boolean_as_json(bool);
extern json_value_t * utils_null_as_json(void);
extern hashmap_t *utils_json_copy(hashmap_t *);
extern uint16_t *utils_decode_blurhash(char *, int *, int *);
#endif

View File

@ -33,6 +33,7 @@ jmlist *jmlist_create(void *parent, jmlist_set_widget set, jmlist_free_data f)
list->box = jwidget_create(list->frame);
jlayout_set_vbox(list->box)->spacing = 1;
jwidget_set_maximum_width(list->box, DWIDTH);
list->arr = utils_new_array();
list->selected = -1;
@ -76,9 +77,32 @@ int jmlist_add_item(jmlist *list, void *data)
return idx;
}
int jmlist_prepend_item(jmlist *list, void *data)
{
jmlist_item *item;
if (!list)
{
return -1;
}
item = malloc(sizeof(jmlist_item));
item->data = data;
item->widget = jwidget_create(list->box);
item->owner = list;
utils_array_shift(list->arr, 1);
utils_array_set(list->arr, 0, item);
list->set(item, 0);
list->offset_x = -(jwidget_full_width(list->box));
jwidget_emit(list, (jevent){ .type = JMLIST_ITEM_ADDED });
return 0;
}
int jmlist_select(jmlist *list, int idx)
{
jmlist_item *item;
size_t oidx;
if (!list)
{
@ -90,7 +114,9 @@ int jmlist_select(jmlist *list, int idx)
if (item && item->widget)
{
jwidget *w = item->widget;
log_text("%s: unselecting", __func__);
jwidget_set_background(w, C_NONE);
log_text("%s: unselected", __func__);
}
if (idx >= utils_array_size(list->arr))
{
@ -101,11 +127,20 @@ int jmlist_select(jmlist *list, int idx)
idx = 0;
}
log_text("%s: getting", __func__);
item = utils_array_get(list->arr, idx);
if (!item)
{
log_text("%s: got %d items", __func__, utils_array_size(list->arr));
return list->selected;
}
log_text("%s: got", __func__);
list->selected = idx;
log_text("%s: setting bg %p %d", __func__, item, idx);
jwidget_set_background(item->widget, C_RGB(1, 19, 27));
log_text("%s: set bg %p", __func__, item);
jmlist_scroll(
list,
@ -116,7 +151,9 @@ int jmlist_select(jmlist *list, int idx)
.h = jwidget_full_height(item->widget)
}
);
log_text("%s: scrolled", __func__);
jwidget_emit(list, (jevent){ .type = JMLIST_ITEM_CHANGE });
log_text("%s: emitted", __func__);
return idx;
}

View File

@ -558,6 +558,7 @@ static json_value_t *parse_null(json_parser_t *parser)
return utils_null_as_json();
}
static json_value_t *parse_array(json_parser_t *parser)
{
#define get_token_off() utils_array_get(\
@ -630,6 +631,15 @@ fail:
#undef get_token_off
}
/* Under arrest (failed parsing an array midsync)
* The suspect was seen freeing hashmap data(so a failure)
* and then crashing everything.
*
* This is probably a big "oops, uninitialised variable" moment.
*
* I however, can't see a scenario where the object parsing would
* fail with an *uninitialised* hashmap instantly like in the
* traces. :/ */
static json_value_t *parse_object(json_parser_t *parser)
{
#define get_token_off() utils_array_get(\
@ -638,10 +648,7 @@ static json_value_t *parse_object(json_parser_t *parser)
)
json_parser_t copy;
json_token_t *token;
array_t *arr;
hashmap_t *hm;
size_t i = 0;
hashmap_t *hm = NULL;
bool except = true;
bool first_time = true;
@ -659,15 +666,11 @@ static json_value_t *parse_object(json_parser_t *parser)
token = get_token_off();
if (!token || token->type != JSON_TOK_LCB)
{
if (token->type == JSON_TOK_STRING)
{
}
if (token->type == JSON_TOK_NUMBER)
{
}
/* ???? */
return NULL;
}
hm = utils_new_hashmap();
/* ???? */
while ((token = get_token_off()) && token->type != JSON_TOK_RCB)
{
if (!except)

View File

@ -1,7 +1,10 @@
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/usb-ff-bulk.h>
#include <gint/keyboard.h>
#include <gint/hardware.h>
#include <gint/display.h>
#include <gint/kmalloc.h>
#include <gint/usb.h>
#include <gint/rtc.h>
#include <gint/fs.h>
#include <justui/jscene.h>
@ -14,6 +17,7 @@
#include <ui_generators.h>
#include <info.h>
#include <usb.h>
#include <dbg.h>
#include <ui.h>
#include <stdlib.h>
@ -62,6 +66,32 @@ int main(void)
int in, out;
usb_fxlink_header_t reply;
uint8_t major, minor;
short int tmp;
uint32_t self_addr = (uintptr_t) main;
uint32_t top_addr = self_addr & 0xFF000000;
/* Can we use extra memory? Check if this is an fx-CG50 and
* that main isn't in that segment */
srand(rtc_ticks());
if (gint[HWCALC] == HWCALC_FXCG50 && top_addr != 0x8C000000)
{
static kmalloc_arena_t extRAM = { 0 };
extRAM.name = "extram";
extRAM.is_default = true;
extRAM.start = (void*) 0x8c200000;
extRAM.end = (void*) 0x8c500000; // 4MB
kmalloc_init_arena(&extRAM, true);
kmalloc_add_arena(&extRAM);
dclear(C_GREEN);
dtext(1, 1, C_WHITE, "Ma's Trix will take extra memory.");
dupdate();
getkey();
}
dclear(C_WHITE);
dtext(1, 1, C_BLACK, "Waiting for USB link...");
@ -70,6 +100,7 @@ int main(void)
usb_init(&out, &in);
story_of_usb_comm(); /* Greet the user over USB */
dbg_init();
/* Set UI up... */
ui = ui_create_session();
@ -84,6 +115,7 @@ int main(void)
end:
/* End everything... */
dbg_end();
usb_close();
//ui_destroy_session(ui);
return 1;

View File

@ -4,6 +4,8 @@
#include <gint/keyboard.h>
#include <gint/timer.h>
#include <libimg.h>
#include <justui/jscene.h>
#include <justui/jinput.h>
#include <justui/jfkeys.h>
@ -45,7 +47,7 @@ ui_session_t *ui_create_session(void)
ret->stack = jwidget_create(ret->justui_screen);
jlayout_set_stack(ret->stack);
jwidget_set_padding(ret->stack, 0, 0, 0, 0);
jwidget_set_stretch(ret->stack, 1, 1, false);
jwidget_set_stretch(ret->stack, 1, 1, true);
ret->waiting = false;
@ -131,6 +133,7 @@ bool ui_manage_event(ui_session_t *ui, jevent e)
widget = screen->on_event(screen, e);
if (widget)
{
/* This lil' fella has an unusual tendency to crash. */
jscene_set_focused_widget(ui->justui_screen, widget);
return true;
}
@ -178,8 +181,42 @@ ui_screen_t * ui_new_screen(screen_setup_t setup, screen_focus_t focus,
ret->on_focus = focus;
ret->on_event = event;
ret->end = NULL;
return ret;
}
void ui_destroy_screen(ui_session_t *ui)
{
ui_screen_t *screen;
if (!ui)
{
return;
}
screen = utils_array_get(ui->screens, ui->current_screen);
if (screen->end)
{
screen->end(screen);
}
utils_array_pop(ui->screens);
free(screen);
ui->current_screen--;
screen = utils_array_get(ui->screens, ui->current_screen);
if (screen->on_focus)
{
void *w = screen->on_focus(screen);
if (w)
{
jscene_show_and_focus(ui->justui_screen, w);
}
}
dclear(C_WHITE);
jscene_render(ui->justui_screen);
dupdate();
}
static void draw_image(int x, int y, const bopti_image_t *img)
{
@ -202,3 +239,40 @@ jpainted *ui_image(void *parent, const bopti_image_t *img)
return ret;
}
#define SCALE 20
static void draw_blur(int x, int y, char *bh)
{
int w = 0, h = 0;
size_t xp, yp;
uint16_t *colors = utils_decode_blurhash(bh, &w, &h);
for (yp = 0; yp < h; yp++)
{
for (xp = 0; xp < w; xp++)
{
uint16_t c = colors[yp * w + xp];
drect(
xp * SCALE + x, yp * SCALE + y,
xp * SCALE + SCALE, yp * SCALE + SCALE,
c
);
}
}
free(colors);
}
jpainted *ui_blurhash(void *p, char *bh)
{
int w = 0, h = 0;
uint16_t *nothing;
nothing = utils_decode_blurhash(bh, &w, &h);
free(nothing);
return jpainted_create(
draw_blur,
(j_arg_t) (void *) bh,
w * SCALE, h * SCALE,
p
);
}

View File

@ -13,24 +13,33 @@
#include <matrix.h>
#include <utils.h>
#include <info.h>
const char *infos =
"= Ma's Trix\n"
"= Ma's Trix\n"
"A half decent [matrix] client.\n\n\n"
"LICENSE: \n"
"- TBD lol\n\n"
"- CeCILL\n\n"
"WRITTEN BY: \n"
"- LDA <@lda:a.freetards.xyz>\n"
"(pssht KONTRIBUTORS, put your contacts here!)\n\n"
"THANKS TO: \n"
"- Lephe for writing gint, fxlink, libimg and other tools\n"
"- Lephe for writing gint, fxlink, libimg, WebCalc and other tools\n"
"- ari.lt for offering the mastrix.org domain for free!\n"
"- The [matrix] Foundation for providing its specification to "
"the public\n"
"- dav for adding Ma's Trix onto the matrix wiki even though he "
"wasnt supposed to when he did it since i didnt release it\n"
"- Various other open-source contributors "
"for additional software used to create Ma's Trix\n";
"for additional software used to create Ma's Trix\n"
"- plate, just come back please :(\n\n"
"FUN STUFF (press F1 to exit): \n"
"- Program name: " MASTRIX_NAME "\n"
"- Program version: " MASTRIX_VERS "\n"
"- Intended platform: " MASTRIX_PLAT "\n"
"- User-Agent string: " MASTRIX_UA "\n";
void * ui_infos_init(ui_screen_t *that)
{
jframe *info_frame;
@ -45,3 +54,11 @@ void * ui_infos_init(ui_screen_t *that)
return info_frame;
}
void * ui_infos_event(ui_screen_t *that, jevent e)
{
if (e.key.type == KEYEV_UP && e.key.key == KEY_F1)
{
ui_destroy_screen(that->owner);
}
return NULL;
}

View File

@ -13,6 +13,7 @@
#include <easters.h>
#include <matrix.h>
#include <utils.h>
#include <log.h>
extern const bopti_image_t mastrix;
@ -206,9 +207,13 @@ void * ui_login_event(ui_screen_t *that, jevent e)
user->device_id
);
log_text("%s: attempting initial sync", __func__);
matrix_initial_sync(user);
log_text("%s: attempted initial sync, loading room list", __func__);
rooms = ui_new_screen(ui_rooms_init, ui_rooms_focus, ui_rooms_event);
log_text("%s: adding screen", __func__);
ui_add_screen(that->owner, rooms);
log_text("%s: added screen", __func__);
return NULL; /* TODO: Change screen, since we're logged in */
}

View File

@ -10,12 +10,12 @@
#include <justui/jframe.h>
#include <justui/jfkeys.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <matrix.h>
#include <utils.h>
#include <log.h>
#include <usb.h>
typedef struct ui_room_extra {
@ -25,6 +25,7 @@ typedef struct ui_room_extra {
jwidget *tl_widget;
jfkeys *jfk;
jmlist *timeline;
jmlist *charpick;
jfileselect *file;
m_room_t *room;
@ -48,6 +49,31 @@ typedef struct item_extra {
ui_room_extra_t *extra;
} item_extra_t;
static void ui_room_act(item_extra_t *ie)
{
ui_room_extra_t *extra = ie->extra;
m_event_t *event = ie->event;
if (strcmp(event->type, "m.room.message"))
{
/* Do not interact over non-messages for now */
return;
}
/* TODO: Act upon the event(downloading/...) */
}
static void set_chr(jmlist_item *item, int idx)
{
char c = idx + ' ';
jlabel *label;
jwidget_set_stretch(item->widget, 1, 0, false);
jlayout_set_vbox(item->widget)->spacing = 1;
jwidget_set_background(item->widget, C_WHITE);
label = jlabel_create("", item->widget);
jlabel_asprintf(label, "%c", c);
jwidget_set_background(label, C_WHITE);
}
static void set(jmlist_item *item, int idx)
{
item_extra_t *ie = item->data;
@ -63,6 +89,13 @@ static void set(jmlist_item *item, int idx)
matrix_show_event(extra->room, extra->user, e, item->widget);
}
static void screen_free(ui_screen_t *that)
{
ui_room_extra_t *extra = that->data;
jwidget_destroy(extra->main);
timer_stop(extra->timer_id);
free(that->data);
}
void * ui_room_init(ui_screen_t *that)
{
@ -87,6 +120,8 @@ void * ui_room_init(ui_screen_t *that)
jwidget_set_padding(main, 0, 0, 0, 0);
jwidget_set_stretch(main, 15, 15, false);
that->end = screen_free;
user = that->owner->user;
room = that->owner->room;
@ -119,7 +154,6 @@ void * ui_room_init(ui_screen_t *that)
/* TODO: Regularly update history, somehow */
that->data = extra;
that->owner->waiting = true;
matrix_update_room_history(user, room, NULL, 20);
@ -131,7 +165,7 @@ void * ui_room_init(ui_screen_t *that)
jwidget_set_stretch(type_message, 1, 0, false);
jwidget_set_border(type_message, J_BORDER_SOLID, 1, C_BLACK);
jfk = jfkeys_create("@MESG;@ROOM;/FILE;;;@EXIT", main);
jfk = jfkeys_create("@MESG;@ROOM;/FILE;;#CHR;@EXIT", main);
jwidget_set_stretch(jfk, 1, 0, false);
{
@ -144,6 +178,7 @@ void * ui_room_init(ui_screen_t *that)
extra->jfk = jfk;
extra->on_timeline = true;
extra->file = NULL;
extra->charpick = NULL;
extra->timer_id = timer_configure(
TIMER_ANY,
@ -176,29 +211,23 @@ void * ui_room_init(ui_screen_t *that)
static void ui_update_history(ui_screen_t *that)
{
ui_room_extra_t *extra = that->data;
size_t size, i;
size_t lidx, i, size;
lidx = /*utils_array_size(extra->room->timeline)*/0;
matrix_update_room_history(extra->user, extra->room, NULL, 5);
jwidget_destroy(extra->timeline);
jwidget_destroy(extra->file);
jwidget_set_padding(extra->tl_widget, 1, 1, 1, 1);
jwidget_set_stretch(extra->tl_widget, 1, 1, false);
extra->timeline = jmlist_create(extra->tl_widget, set, NULL);
extra->file = jfileselect_create(extra->tl_widget);
jwidget_set_stretch(extra->file, 1, 1, false);
jwidget_set_background(extra->file, C_WHITE);
jwidget_set_stretch(extra->timeline, 1, 1, false);
size = utils_array_size(extra->room->timeline);
for (i = 0; i < size; i++)
for (i = lidx; i < size; i++)
{
m_event_t *e = utils_array_get(extra->room->timeline, size - i - 1);
item_extra_t *ie = malloc(sizeof(item_extra_t));
@ -207,10 +236,12 @@ static void ui_update_history(ui_screen_t *that)
ie->event = e;
ie->screen = that;
ie->extra = extra;
/*jmlist_prepend_item(extra->timeline, ie);*/
jmlist_add_item(extra->timeline, ie);
}
jmlist_select(extra->timeline, 1);
return;
}
#include <string.h>
void emit(void *w0, jevent e)
@ -249,15 +280,10 @@ static int timer_cb(ui_screen_t *that)
((ui_room_extra_t *) that->data)->flag1 = false;
return TIMER_CONTINUE;
}
static void * ui_file_event(ui_screen_t *that, jevent e, bool first)
static void * ui_file_event(ui_screen_t *that, jevent e)
{
ui_room_extra_t *extra = that->data;
/* Yeah, different bit of code */
if (first)
{
jfileselect_browse(extra->file, "/");
return NULL;
}
if (e.type == JFILESELECT_VALIDATED)
{
hashmap_t *msg;
@ -266,9 +292,7 @@ static void * ui_file_event(ui_screen_t *that, jevent e, bool first)
path = (char *) jfileselect_selected_file(extra->file);
base = utils_basename(path);
log_text("%s: path='%s' basename='%s'", __func__, path, base);
mxc = matrix_send_file(extra->user, path, NULL);
log_text("%s: mxc='%s'", __func__, mxc);
msg = utils_new_hashmap();
@ -291,11 +315,46 @@ static void * ui_file_event(ui_screen_t *that, jevent e, bool first)
return extra->timeline;
}
return extra->file;
}
static void * ui_char_event(ui_screen_t *that, jevent e)
{
ui_room_extra_t *extra = that->data;
if (e.type == JMLIST_ITEM_CHOSEN)
{
char c = jmlist_selected(extra->charpick) + ' ';
char cp[2] = { c, '\0' };
char *input = utils_strcat(extra->input->text, cp);
free(extra->input->text);
extra->input->text = input;
extra->input->size++;
extra->input->widget.dirty = 1;
jwidget_destroy(extra->charpick);
extra->charpick = NULL;
return extra->input;
}
return extra->charpick;
}
void * ui_room_event(ui_screen_t *that, jevent e)
{
ui_room_extra_t *extra = that->data;
if (extra->charpick)
{
return ui_char_event(that, e);
}
if (e.type == JMLIST_ITEM_CHOSEN && !extra->file)
{
/* TODO */
int selected = jmlist_selected(extra->timeline);
item_extra_t *ie = utils_array_get(extra->timeline->arr, selected);
if (!ie)
{
return NULL;
}
ui_room_act(ie);
return NULL;
}
if (e.type == JMLIST_ITEM_CHANGE && !extra->file)
{
int selected = jmlist_selected(extra->timeline);
@ -318,7 +377,6 @@ void * ui_room_event(ui_screen_t *that, jevent e)
uint8_t code = extra->input->mode;
jrect rect;
log_text("%s: NOPd", __func__);
e = utils_array_get(extra->room->timeline, 0);
@ -360,6 +418,7 @@ void * ui_room_event(ui_screen_t *that, jevent e)
hashmap_t *msg = utils_new_hashmap();
m_event_t *e;
utils_hashmap_set(
msg,
"body",
@ -403,14 +462,16 @@ void * ui_room_event(ui_screen_t *that, jevent e)
}
if (e.key.key == KEY_F3 && e.key.type == KEYEV_UP && !extra->file)
{
/* TODO: Add a floating filebrowser */
int null;
extra->file = jfileselect_create(that->widget);
jwidget_set_floating(extra->file, true);
jwidget_set_background(extra->file, C_WHITE);
jwidget_set_minimum_size(extra->file, DWIDTH, DHEIGHT);
jwidget_set_maximum_size(extra->file, DWIDTH, DHEIGHT);
jwidget_set_maximum_size(
extra->file,
extra->tl_widget->w, extra->tl_widget->h
);
jwidget_set_minimum_size(extra->file, DWIDTH, DHEIGHT - 30);
jfileselect_set_show_file_size(extra->file, true);
jlayout_get_stack(extra->tl_widget)->active = 1;
@ -421,9 +482,33 @@ void * ui_room_event(ui_screen_t *that, jevent e)
(void) null;
return extra->file;
}
if (e.key.key == KEY_F5 && e.key.type == KEYEV_UP && !extra->file)
{
char i;
extra->charpick = jmlist_create(that->widget, set_chr, NULL);
for (i = ' '; i < 0x7F; i++)
{
jmlist_add_item(extra->charpick, (void *) ((uintptr_t) i));
}
jwidget_set_floating(extra->charpick, true);
jwidget_set_background(extra->charpick, C_WHITE);
jwidget_set_maximum_size(
extra->charpick,
extra->tl_widget->w, extra->tl_widget->h
);
jwidget_set_minimum_size(extra->charpick, DWIDTH, DHEIGHT - 35);
jmlist_select(extra->charpick, 1);
return extra->charpick;
}
if (e.key.key == KEY_F6 && e.key.type == KEYEV_UP && !extra->file)
{
ui_destroy_screen(that->owner);
return NULL;
}
if (extra->file)
{
return ui_file_event(that, e, false);
return ui_file_event(that, e);
}
return NULL;
}

View File

@ -16,7 +16,6 @@
#include <ui_generators.h>
#include <matrix.h>
#include <utils.h>
#include <log.h>
typedef struct ui_userroom {
m_user_t *user;
@ -89,6 +88,7 @@ void * ui_rooms_init(ui_screen_t *that)
jmlist *rooms_list;
jwidget *wid;
jlabel *rooms_text;
jfkeys *jfk;
hashmap_t *rooms;
@ -123,6 +123,9 @@ void * ui_rooms_init(ui_screen_t *that)
jwidget_set_padding(rooms_list, 1, 1, 1, 1);
jwidget_set_stretch(rooms_list, 15, 15, false);
jfk = jfkeys_create("/INFOS;@DIR;;;#ACC;#JOIN", wid);
jwidget_set_stretch(jfk, 1, 0, false);
that->data = rooms_list;
jmlist_select(rooms_list, 0);
@ -144,6 +147,30 @@ void * ui_rooms_event(ui_screen_t *that, jevent e)
chat = ui_new_screen(ui_room_init, NULL, ui_room_event);
ui_add_screen(that->owner, chat);
return NULL;
}
if (e.key.key == KEY_F1)
{
ui_screen_t *infos;
infos = ui_new_screen(ui_infos_init, NULL, ui_infos_event);
ui_add_screen(that->owner, infos);
return NULL;
}
if (e.key.key == KEY_F2 && e.key.type == KEY_UP)
{
/* TODO: Room directory screen */
return NULL;
}
if (e.key.key == KEY_F5 && e.key.type == KEY_UP)
{
/* TODO: Account information screen */
return NULL;
}
if (e.key.key == KEY_F6 && e.key.type == KEY_UP)
{
/* TODO: Room join screen */
return NULL;
}
return NULL;
}

View File

@ -12,6 +12,8 @@
#include <stdlib.h>
#include <string.h>
#include <easters.h>
void usb_init(int *out, int *in)
{
timeout_t tm;
@ -20,18 +22,34 @@ void usb_init(int *out, int *in)
usb_open(intf, GINT_CALL_NULL);
tm = timeout_make_ms(10 * 1000);
while (!usb_is_open() && !timeout_elapsed(&tm));
while (!usb_is_open() && !timeout_elapsed(&tm))
{
timeout_t tm1 = timeout_make_ms(66);
easter_dvd_frame(
"Uplinking with USB (run mastrix on your PC now)..."
);
while (!timeout_elapsed(&tm1));
}
if (!usb_is_open())
{
char *str = "Couldn't open USB: timeout.";
dclear(C_RED);
dtext_opt(
0, 0, C_WHITE, C_RED, DTEXT_CENTER, DTEXT_MIDDLE,
DWIDTH / 2, DHEIGHT / 2,
C_WHITE, C_RED,
DTEXT_CENTER, DTEXT_MIDDLE,
str, strlen(str)
);
dupdate();
while (true) getkey();
while (true)
{
key_event_t e = getkey();
if (e.alpha && e.key == KEY_F1)
{
easter_goda();
}
}
}
*out = usb_ff_bulk_output();