The Great Push (mfw)
|
@ -13,7 +13,3 @@ __pycache__/
|
|||
*.sublime-workspace
|
||||
.vscode
|
||||
.ycm_extra_conf.py
|
||||
|
||||
# Screenshots
|
||||
*.png
|
||||
*.raw
|
||||
|
|
|
@ -12,6 +12,7 @@ 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)
|
||||
find_package(cZlib 1.2.5 REQUIRED)
|
||||
|
||||
AUX_SOURCE_DIRECTORY(src SOURCES)
|
||||
# Shared assets, fx-9860G-only assets and fx-CG-50-only assets
|
||||
|
@ -33,16 +34,19 @@ set(ASSETS_cg
|
|||
assets-cg/tweak.png
|
||||
assets-cg/tbold.png
|
||||
assets-cg/bouncer.png
|
||||
assets-cg/cirno.png
|
||||
assets-cg/marie.png
|
||||
assets-cg/mastrix-print.png
|
||||
assets-cg/house.png
|
||||
assets-cg/uf8x9
|
||||
assets-cg/uf5x7
|
||||
)
|
||||
|
||||
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 -finstrument-functions)
|
||||
target_link_libraries(mastrix Gint::Gint JustUI::JustUI LibImg::LibImg)
|
||||
|
||||
target_compile_options(mastrix PRIVATE -Wall -Wextra -Os -g -finstrument-functions)
|
||||
target_link_libraries(mastrix Gint::Gint JustUI::JustUI LibImg::LibImg cPNG::cPNG cZlib::cZlib)
|
||||
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
|
||||
# honestly i dont have an fx-9860G to test with.
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
Ma's Trix:
|
||||
Copyright (c) 2024 LDA
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
yxml:
|
||||
Copyright (c) 2013-2014 Yoran Heling
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
4
TODO
|
@ -1,4 +0,0 @@
|
|||
- Commands (and a catalog system)
|
||||
- Save user info to be loaded later
|
||||
- Custom reactions
|
||||
- ????
|
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 557 B |
|
@ -4,6 +4,9 @@ mastrix-print.png:
|
|||
user.png:
|
||||
type: bopti-image
|
||||
name: user
|
||||
marie.png:
|
||||
type: libimg-image
|
||||
name: default_pfp
|
||||
hourglass.png:
|
||||
type: bopti-image
|
||||
name: hourglass
|
||||
|
@ -38,3 +41,25 @@ goda.png:
|
|||
goda_full.png:
|
||||
type: libimg-image
|
||||
name: goda_full
|
||||
cirno.png:
|
||||
type: bopti-image
|
||||
name: cirno
|
||||
house.png:
|
||||
type: bopti-image
|
||||
name: credits_image
|
||||
|
||||
|
||||
uf8x9:
|
||||
type: font
|
||||
name: uf8x9
|
||||
charset: unicode
|
||||
grid.size: 8x11
|
||||
grid.padding: 1
|
||||
proportional: true
|
||||
height: 9
|
||||
uf5x7:
|
||||
type: font
|
||||
name: uf5x7
|
||||
charset: unicode
|
||||
grid.size: 5x7
|
||||
grid.padding: 1
|
||||
|
|
After Width: | Height: | Size: 744 B |
After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 781 B |
After Width: | Height: | Size: 632 B |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 672 B |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 270 B |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 831 B |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 1.2 KiB |
554
src/DOM.c
|
@ -1,554 +0,0 @@
|
|||
/*
|
||||
Header inclusions.
|
||||
*/
|
||||
|
||||
#include <WebCalc.h>
|
||||
|
||||
|
||||
|
||||
/*
|
||||
DomStyle manipulation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DomStyle_new
|
||||
*
|
||||
* Dynamically allocates, initializes, and returns a new DomStyle object.
|
||||
* Hexadecimal notation in default value indicate properties that should
|
||||
* be overwritten by the tag nature.
|
||||
*
|
||||
* @return Allocated and initialized object.
|
||||
*/
|
||||
|
||||
struct DomStyle *DomStyle_new(void)
|
||||
{
|
||||
// Storing the size of a structure.
|
||||
const int size = sizeof(struct DomStyle);
|
||||
|
||||
// Using a DomStyle structure pointer and a static default structure.
|
||||
struct DomStyle *pointer = NULL;
|
||||
struct DomStyle style = {
|
||||
// White background and black font color.
|
||||
0, 1,
|
||||
// Automatic overflow on both axes and no resize.
|
||||
3, 3, 0,
|
||||
// No display, static positioning, no floating, and top
|
||||
// vertical alignment.
|
||||
0x0, 0, 0, 0,
|
||||
// Position : top, right, bottom and left.
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
// Default width and width : value, minimum and maximum.
|
||||
0x0, 0, 4095, 0x0, 0, 4095,
|
||||
// Default padding, borders with border radius, and margins.
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0,
|
||||
0x0, 0, 0x0, 0,
|
||||
// Border spacing on x and y.
|
||||
0, 0,
|
||||
// Font size, letter spacing, line height and text indent.
|
||||
0x0, 1, 0x0, 0,
|
||||
// Default cursor, visible and `o` list type.
|
||||
1, 1, 7,
|
||||
// Left text alignment, no decoration, default wrapping
|
||||
// behavior, separate table borders and show empty cells.
|
||||
0, 0, 0, 0, 0,
|
||||
// Tab size and word spacing.
|
||||
4, 0x0
|
||||
};
|
||||
|
||||
// Allocating the needed size in the memory.
|
||||
pointer = (struct DomStyle *)malloc(size);
|
||||
// Returning a NULL pointer on alloc failure.
|
||||
if(!pointer) return NULL;
|
||||
|
||||
// Copying the static data to the reserved location.
|
||||
memcpy(pointer, &style, size);
|
||||
// Returning the allocated pointer.
|
||||
return pointer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
DomAttribute manipulation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DomAttribute_new()
|
||||
*
|
||||
* Allocates a new attribute with the given parameters. If a null
|
||||
* reference is given for at least name or value, nothing is allocated
|
||||
* and an empty structure is returned.
|
||||
*/
|
||||
|
||||
struct DomAttribute *DomAttribute_new(reference_t name, reference_t value)
|
||||
{
|
||||
// Using a DomAttribute structure pointer.
|
||||
struct DomAttribute *at = NULL;
|
||||
|
||||
// Allocating the size of the structure in the memory.
|
||||
at = (struct DomAttribute *)malloc(sizeof(struct DomAttribute));
|
||||
// Returning a NULL pointer on alloc failure.
|
||||
if(!at) return NULL;
|
||||
|
||||
// Returning an empty structure if one of the arguments is null.
|
||||
if(refnull(name) || refnull(value))
|
||||
{
|
||||
// Setting NULL pointers.
|
||||
at->name = NULL;
|
||||
at->value = NULL;
|
||||
// Returning the structure.
|
||||
return at;
|
||||
}
|
||||
|
||||
// If given arguments are valid, extracting the referenced data.
|
||||
at->name = refxtrct(name);
|
||||
at->value = refxtrct(value);
|
||||
// Returning the obtained structure. No alloc failure handling is added
|
||||
// because it could not do anything more that returning the pointer.
|
||||
return at;
|
||||
}
|
||||
|
||||
/**
|
||||
* DomAttribute_free()
|
||||
*
|
||||
* Frees the memory allocated for a DomAttribute object. As a convention,
|
||||
* the structure itself is freed.
|
||||
*
|
||||
* @param at Attribute to free.
|
||||
*/
|
||||
|
||||
void DomAttribute_free(struct DomAttribute *at)
|
||||
{
|
||||
// Returning is the argument is not valid.
|
||||
if(!at) return;
|
||||
|
||||
// Freeing the name and value pointers, if valid.
|
||||
if(at->name) free(at->name);
|
||||
if(at->value) free(at->value);
|
||||
|
||||
// Freeing the structure itself.
|
||||
free(at);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
DomElement object
|
||||
*/
|
||||
|
||||
/**
|
||||
* DomElement_new()
|
||||
*
|
||||
* Allocates and constructs a new DomElement, using the given parameters.
|
||||
*
|
||||
* @param name Element tag name.
|
||||
* @param args Argument string.
|
||||
* @param parent Parent node in DOM tree.
|
||||
* @param previous Previous sibling in DOM tree.
|
||||
*
|
||||
* @return Allocated object, or NULL on failure.
|
||||
*/
|
||||
|
||||
struct DomElement *DomElement_new(reference_t name, reference_t args,
|
||||
struct DomElement *parent, struct DomElement *previous)
|
||||
{
|
||||
// Using a DomElement pointer.
|
||||
struct DomElement *el;
|
||||
// Using a DomStyle pointer to test allocation validity.
|
||||
struct DomStyle *style;
|
||||
|
||||
// Allocating the pointer.
|
||||
el = (struct DomElement *)malloc(sizeof(struct DomElement));
|
||||
// Handling alloc failure by returning NULL without doing anything.
|
||||
if(!el) return NULL;
|
||||
|
||||
// Immediately getting a style structure (to return on failure).
|
||||
style = DomStyle_new();
|
||||
// Handling alloc failure by canceling the operation.
|
||||
if(!style)
|
||||
{
|
||||
// Freeing the allocated element.
|
||||
free(el);
|
||||
// Returning from the function.
|
||||
return NULL;
|
||||
}
|
||||
// Setting the style structure pointer.
|
||||
el->style = style;
|
||||
|
||||
// Extracting the tag name.
|
||||
el->tagName = refxtrct(name);
|
||||
|
||||
// Setting a default textNode (or tex, basically even with the
|
||||
// uncertainty on union manipulation this should be the same).
|
||||
el->textNode = NULL;
|
||||
|
||||
// Setting default values for children.
|
||||
el->children = NULL;
|
||||
el->childnum = 0;
|
||||
|
||||
// Setting default values for attributes.
|
||||
el->attributes = NULL;
|
||||
el->attrnum = 0;
|
||||
|
||||
// Setting the parent and previous sibling.
|
||||
el->parent = parent;
|
||||
el->previous = previous;
|
||||
|
||||
// Returning the allocated structure.
|
||||
return el;
|
||||
}
|
||||
|
||||
/**
|
||||
* DomElement_free()
|
||||
*
|
||||
* Frees a DomElement structure and all the associated allocate data. All
|
||||
* its children are freed. As a convention, the structure itself is also
|
||||
* freed.
|
||||
*
|
||||
* @param el Element structure to free.
|
||||
*/
|
||||
|
||||
void DomElement_free(struct DomElement *el)
|
||||
{
|
||||
// Using an iterator.
|
||||
int i;
|
||||
|
||||
// Freeing the tex node data.
|
||||
/*if(!strcmp(el->tagName, "math")) tex_free(el->tex);*/
|
||||
// Freeing the node content.
|
||||
/*else */if(el->textNode) free(el->textNode);
|
||||
|
||||
// Freeing the tag name, if not NULL.
|
||||
if(el->tagName) free(el->tagName);
|
||||
|
||||
// Freeing the style structure.
|
||||
free(el->style);
|
||||
|
||||
// Freeing the tag attributes and the array.
|
||||
for(i=0; i < el->attrnum; i++) DomAttribute_free(el->attributes[i]);
|
||||
if(el->attributes) free(el->attributes);
|
||||
|
||||
// Freeing the children and the array.
|
||||
for(i=0; i < el->childnum; i++) DomElement_free(el->children[i]);
|
||||
if(el->children) free(el->children);
|
||||
|
||||
// Finally freeing the structure itself.
|
||||
free(el);
|
||||
}
|
||||
|
||||
/**
|
||||
* DomElement_addChild()
|
||||
*
|
||||
* Adds a child to an element. Needs to reallocate the children array.
|
||||
*
|
||||
* @param el Parent element.
|
||||
* @param child Child to add.
|
||||
*
|
||||
* @return Argument `child`, or NULL on failure.
|
||||
*/
|
||||
|
||||
struct DomElement *DomElement_addChild(struct DomElement *el,
|
||||
struct DomElement *child)
|
||||
{
|
||||
// Using a pointer array pointer.
|
||||
struct DomElement **array;
|
||||
// Using a variable to store the number of children.
|
||||
int n;
|
||||
|
||||
// Checking arguments validity. Returning NULL on error.
|
||||
if(!el || !child) return NULL;
|
||||
|
||||
// Getting the number of children.
|
||||
n = el->childnum;
|
||||
|
||||
// Allocating a new array, freeing the old one on success.
|
||||
array = realloc(el->children, (n + 1) * sizeof(struct DomElement *));
|
||||
// Canceling operation on failure.
|
||||
if(!array) return NULL;
|
||||
|
||||
// Adding the new child.
|
||||
array[n] = child;
|
||||
|
||||
// Updating parent information.
|
||||
el->children = array;
|
||||
el->childnum++;
|
||||
|
||||
// Returning the child element.
|
||||
return child;
|
||||
}
|
||||
|
||||
/**
|
||||
* DomElement_getChild()
|
||||
*
|
||||
* Returns the pointer on an element's child, represented by its position
|
||||
* in the parent child list.
|
||||
*
|
||||
* @param el Element whose child is wanted.
|
||||
* @param n Number of wanted child.
|
||||
*
|
||||
* @return Pointer of child element if exists, NULL otherwise.
|
||||
*/
|
||||
|
||||
struct DomElement *DomElement_getChild(struct DomElement *el, int n)
|
||||
{
|
||||
// Using an integer to store the number of children.
|
||||
int children;
|
||||
|
||||
// Checking argument validity.
|
||||
if(!el) return NULL;
|
||||
|
||||
// Getting the number of children.
|
||||
children = el->childnum;
|
||||
if(children == 0)
|
||||
{
|
||||
printf("Oh, so unfortunate %s, for you have no children\n", el->tagName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Adapting range of n.
|
||||
if(n < 0) n += children;
|
||||
n %= children;
|
||||
|
||||
// Returning the wanted child.
|
||||
return el->children[n];
|
||||
}
|
||||
|
||||
/**
|
||||
* DOM_sybl()
|
||||
*/
|
||||
|
||||
static int DOM_sybl(reference_t name)
|
||||
{
|
||||
const char *names[] = { "amp", "lt", "gt", NULL };
|
||||
const char symbols[] = { '&', '<', '>' };
|
||||
const char **ptr = names;
|
||||
|
||||
while(*ptr) if(!refscmp(name, *ptr++)) return symbols[ptr - names - 1];
|
||||
return ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
* DomElement_setTextNode()
|
||||
*
|
||||
* Sets the text node of an element. If a text node already exists, it is
|
||||
* freed. To remove the text node of an element, just call setTextNode(
|
||||
* NULL).
|
||||
*
|
||||
* @param el Element whose text node should be set.
|
||||
* @param text Text content.
|
||||
*/
|
||||
|
||||
void DomElement_setTextNode(struct DomElement *el, reference_t text)
|
||||
{
|
||||
char *txt;
|
||||
const char *ptr;
|
||||
int length = 0, i = 0;
|
||||
|
||||
ptr = text.begin;
|
||||
while(ptr < text.end)
|
||||
{
|
||||
if(*ptr == '&')
|
||||
{
|
||||
while(ptr < text.end && *ptr != ';') ptr++;
|
||||
if(ptr == text.end) break;
|
||||
}
|
||||
|
||||
length++;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
txt = malloc(length + 1);
|
||||
|
||||
ptr = text.begin;
|
||||
while(ptr < text.end)
|
||||
{
|
||||
if(*ptr == '&')
|
||||
{
|
||||
const char *end = ptr;
|
||||
reference_t sybl = { ptr + 1, ptr };
|
||||
|
||||
while(end < text.end && *end != ';') end++;
|
||||
sybl.end = end;
|
||||
|
||||
*(txt + i++) = DOM_sybl(sybl);
|
||||
|
||||
if(end == text.end) break;
|
||||
ptr = end + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
*(txt + i++) = *ptr++;
|
||||
}
|
||||
|
||||
*(txt + i) = 0;
|
||||
|
||||
/*if(!strcmp(el->tagName, "math"))
|
||||
{
|
||||
el->tex = tex_load_pointer(txt, txt + i);
|
||||
free(txt);
|
||||
return;
|
||||
}*/
|
||||
|
||||
el->textNode = txt;
|
||||
}
|
||||
|
||||
/**
|
||||
* DomElement_getAttribute()
|
||||
*
|
||||
* Returns the value associated to a given attribute name.
|
||||
*
|
||||
* @param el Concerned element.
|
||||
* @param name Attribute name.
|
||||
*
|
||||
* @return Attribute value if exists, NULL otherwise.
|
||||
*/
|
||||
|
||||
const char *DomElement_getAttribute(struct DomElement *el, const char *name)
|
||||
{
|
||||
// Using an attribute pointer.
|
||||
struct DomAttribute *attribute;
|
||||
// Using an iterator.
|
||||
int i;
|
||||
|
||||
// Checking arguments validity.
|
||||
if(!el || !name) return NULL;
|
||||
|
||||
// Seeking the wanted attribute.
|
||||
for(i=0; i < el->attrnum; i++)
|
||||
{
|
||||
// Getting the current attribute.
|
||||
attribute = el->attributes[i];
|
||||
|
||||
// Returning the value if the name corresponds.
|
||||
if(!strcmp(attribute->name, name)) return attribute->value;
|
||||
}
|
||||
|
||||
// If nothing is found, returning NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* DomElement_resolve()
|
||||
*
|
||||
* Recursively computes width and height of an element and all its
|
||||
* children.
|
||||
* Top and left coordinates indicate the position where the element is
|
||||
* placed, including padding, borders and margins.
|
||||
* Basic information (position, maximum width, etc.) of the current
|
||||
* element should be set by the parent call of DomElement_resolve(). As
|
||||
* a consequence, it is advised to use only this function on the html
|
||||
* element, that is, by calling document_resolve().
|
||||
*/
|
||||
|
||||
/* This is probably the kinds of affairs to be managed by JustUI tbh */
|
||||
#if 0
|
||||
void DomElement_resolve(struct DomElement *el)
|
||||
{
|
||||
// Using a DomElement structure pointer for iterating over children.
|
||||
struct DomElement *child;
|
||||
// Using two variables for coordinates handling and an iterator.
|
||||
int x, y, i;
|
||||
// Using an integer to store the maximum width of children.
|
||||
int mw;
|
||||
|
||||
// Resolving math elements.
|
||||
/*if(!strcmp(el->tagName,"math"))
|
||||
{
|
||||
// Setting the dimensions given by the natural display module.
|
||||
el->style->width = el->tex->width;
|
||||
el->style->height = el->tex->height;
|
||||
}*/
|
||||
// Resolving other text elements.
|
||||
/*else if(el->textNode) Disp_text(el,1,0,0);*/
|
||||
|
||||
// Applying special behavior for each display style.
|
||||
switch(el->style->display)
|
||||
{
|
||||
// Block elements.
|
||||
case 0:
|
||||
el->style->width = el->style->maxWidth;
|
||||
}
|
||||
|
||||
// Returning immediately if the element hasn't any child.
|
||||
if(!el->childnum) return;
|
||||
|
||||
// Resolving childrens.
|
||||
for(i=0; i < el->childnum; i++)
|
||||
{
|
||||
// Getting the current child.
|
||||
child = el->children[i];
|
||||
|
||||
// Calculating child's maximum width.
|
||||
mw = el->style->maxWidth - DOMElement_tokenWidth(child);
|
||||
|
||||
// Setting its maximum width.
|
||||
if(!child->style->maxWidth || child->style->maxWidth > mw)
|
||||
child->style->maxWidth = mw;
|
||||
|
||||
// Resolving it. Then, width and height should exist.
|
||||
DomElement_resolve(child);
|
||||
}
|
||||
|
||||
// Initializing cursor position.
|
||||
x = 0, y = 0;
|
||||
|
||||
// Positioning children.
|
||||
for(i=0;i<el->childnum;i++)
|
||||
{
|
||||
// Getting the next child.
|
||||
child = el->children[i];
|
||||
|
||||
// If next child is a block.
|
||||
if(child->style->display == 0)
|
||||
{
|
||||
// Add child's total height.
|
||||
child->style->left = x;
|
||||
child->style->top = y;
|
||||
|
||||
y += DOMElement_totalHeight(child);
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Getting new information.
|
||||
el->style->height = y;
|
||||
}
|
||||
#endif
|
||||
|
||||
//#############################################################################################################################
|
||||
//
|
||||
// D O M E l e m e n t O b j e c t
|
||||
//
|
||||
//#############################################################################################################################
|
||||
|
||||
int DomElement_get(struct DomElement *el, int n)
|
||||
{
|
||||
/*
|
||||
** This function returns various informations about an element.
|
||||
** n return value
|
||||
** 1 total width
|
||||
** 2 total height
|
||||
** 3 border, padding, margin width
|
||||
** 4 border, padding, margin height
|
||||
*/
|
||||
|
||||
switch(n)
|
||||
{
|
||||
case 1:
|
||||
return el->style->marginLeft + el->style->borderLeft + el->style->paddingLeft + el->style->width
|
||||
+ el->style->paddingRight + el->style->borderRight + el->style->marginRight;
|
||||
case 2:
|
||||
return el->style->marginTop + el->style->borderTop + el->style->paddingTop + el->style->height
|
||||
+ el->style->paddingBottom + el->style->borderBottom + el->style->marginBottom;
|
||||
case 3:
|
||||
return el->style->marginLeft + el->style->borderLeft + el->style->paddingLeft
|
||||
+ el->style->paddingRight + el->style->borderRight + el->style->marginRight;
|
||||
case 4:
|
||||
return el->style->marginTop + el->style->borderTop + el->style->paddingTop
|
||||
+ el->style->paddingBottom + el->style->borderBottom + el->style->marginBottom;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
18
src/array.c
|
@ -119,3 +119,21 @@ void utils_array_shift(array_t *arr, size_t by)
|
|||
arr->capacity = new->capacity;
|
||||
free(new);
|
||||
}
|
||||
void utils_array_invert(array_t *arr)
|
||||
{
|
||||
size_t pivot, i;
|
||||
void *left, *right;
|
||||
if (!arr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
pivot = arr->capacity / 2;
|
||||
for (i = 0; i < pivot; i++)
|
||||
{
|
||||
left = arr->list[i];
|
||||
right = arr->list[arr->capacity - i - 1];
|
||||
|
||||
arr->list[i] = right;
|
||||
arr->list[arr->capacity - i - 1] = left;
|
||||
}
|
||||
}
|
||||
|
|
198
src/blurhash.c
|
@ -1,198 +0,0 @@
|
|||
/*#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;
|
||||
}
|
||||
|
|
@ -4,10 +4,11 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <utils.h>
|
||||
#include <log.h>
|
||||
|
||||
command_t *command_parse(char *str)
|
||||
{
|
||||
command_t *ret;
|
||||
command_t *ret = NULL;
|
||||
char *name, *argstart;
|
||||
|
||||
if (!str)
|
||||
|
@ -19,7 +20,6 @@ command_t *command_parse(char *str)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* TODO */
|
||||
str++;
|
||||
argstart = str;
|
||||
while (*str != ' ' && *str)
|
||||
|
@ -29,19 +29,37 @@ command_t *command_parse(char *str)
|
|||
if (argstart == str)
|
||||
{
|
||||
/* Empty name, give up. */
|
||||
log_text("command failure because empty...");
|
||||
return NULL;
|
||||
}
|
||||
name = malloc((size_t) (str - argstart) + 1);
|
||||
memcpy(name, argstart, (size_t) (str - argstart));
|
||||
name[(size_t) (str - argstart)] = '\0';
|
||||
|
||||
ret = malloc(sizeof(command_t));
|
||||
ret->command = name;
|
||||
ret->arguments = utils_new_array();
|
||||
|
||||
while (*str)
|
||||
{
|
||||
size_t length;
|
||||
char *substr;
|
||||
/* TODO: string args that allow spaces */
|
||||
while (*str == ' ' && *str)
|
||||
{
|
||||
str++;
|
||||
}
|
||||
argstart = str;
|
||||
while (*str != ' ' && *str)
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
length = (size_t)(str - argstart)/sizeof(char);
|
||||
substr = malloc((length + 2) * sizeof(char));
|
||||
memcpy(substr, argstart, length);
|
||||
substr[length] = '\0';
|
||||
utils_array_add(ret->arguments, substr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
24
src/dbg.c
|
@ -11,15 +11,14 @@
|
|||
#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 volatile uintptr_t *stacktrace = NULL;
|
||||
static volatile size_t idx = 0;
|
||||
static volatile size_t allocated = 0;
|
||||
|
||||
static const char *dbg_to_str(uint32_t code)
|
||||
{
|
||||
|
@ -89,8 +88,18 @@ static void __attribute__((noreturn,no_instrument_function)) dbg_panic(uint32_t
|
|||
"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_write_sync(
|
||||
out,
|
||||
&header,
|
||||
sizeof(usb_fxlink_header_t),
|
||||
false
|
||||
);
|
||||
usb_write_sync(
|
||||
out,
|
||||
(void *) stacktrace,
|
||||
idx * sizeof(uintptr_t),
|
||||
false
|
||||
);
|
||||
usb_commit_sync(out);
|
||||
/* We aren't going to wait for anything here. */
|
||||
}
|
||||
|
@ -136,6 +145,7 @@ void __attribute__((no_instrument_function)) __cyg_profile_func_enter(void *this
|
|||
return;
|
||||
}
|
||||
stacktrace[idx++] = (uintptr_t) this;
|
||||
(void) callee;
|
||||
}
|
||||
void __attribute__((no_instrument_function)) __cyg_profile_func_exit(void *this, void *callee)
|
||||
{
|
||||
|
@ -148,5 +158,7 @@ void __attribute__((no_instrument_function)) __cyg_profile_func_exit(void *this,
|
|||
return;
|
||||
}
|
||||
stacktrace[--idx] = (uintptr_t) NULL;
|
||||
(void) this;
|
||||
(void) callee;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
#include "dom.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "yxml.h"
|
||||
|
||||
#define YXML_BUFFER 4096
|
||||
|
||||
static html_elem_t *create_element(char *name, html_elem_t *parent);
|
||||
static html_elem_t *create_text(char *text, html_elem_t *parent);
|
||||
static void add_attr(html_elem_t *e, char *key, char *value);
|
||||
static void concat_str(char **initial, char *add);
|
||||
|
||||
html_elem_t *dom_parse_element(char *buf)
|
||||
{
|
||||
#define push(e) utils_array_add(stack, e)
|
||||
#define peek() utils_array_get(stack, utils_array_size(stack) - 1)
|
||||
#define pop() utils_array_pop(stack)
|
||||
yxml_t *x = NULL;
|
||||
html_elem_t *ret = NULL;
|
||||
html_elem_t *top = NULL;
|
||||
|
||||
char *str_attr = NULL;
|
||||
char *str_cntr = NULL;
|
||||
|
||||
array_t *stack;
|
||||
if (!buf)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
x = malloc(sizeof(*x) + YXML_BUFFER);
|
||||
yxml_init(x, &x[1], YXML_BUFFER);
|
||||
|
||||
stack = utils_new_array();
|
||||
|
||||
for (; *buf; buf++)
|
||||
{
|
||||
yxml_ret_t r = yxml_parse(x, *buf);
|
||||
if (r < 0)
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
if (r == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We have a token, check how to deal with it */
|
||||
switch (r)
|
||||
{
|
||||
case YXML_ELEMSTART:
|
||||
if (str_cntr)
|
||||
{
|
||||
/* We have to add a text element to our top */
|
||||
create_text(str_cntr, peek());
|
||||
free(str_cntr);
|
||||
str_cntr = NULL;
|
||||
}
|
||||
/* Create a new element that will populated. */
|
||||
top = create_element(x->elem, peek());
|
||||
if (!ret)
|
||||
{
|
||||
/* If we didn't have any element before, this one is
|
||||
* going to be our top of the stack */
|
||||
ret = top;
|
||||
}
|
||||
push(top);
|
||||
/* Fallthrough */
|
||||
case YXML_ATTRSTART:
|
||||
if (str_attr)
|
||||
{
|
||||
free(str_attr);
|
||||
str_attr = NULL;
|
||||
}
|
||||
break;
|
||||
case YXML_ATTRVAL:
|
||||
concat_str(&str_attr, x->data);
|
||||
break;
|
||||
case YXML_ATTREND:
|
||||
add_attr(top, x->attr, str_attr);
|
||||
free(str_attr);
|
||||
str_attr = NULL;
|
||||
break;
|
||||
case YXML_CONTENT:
|
||||
concat_str(&str_cntr, x->data);
|
||||
break;
|
||||
case YXML_ELEMEND:
|
||||
/* Pop out an element out of the DOM. */
|
||||
if (str_cntr)
|
||||
{
|
||||
/* We have to add a text element to our top */
|
||||
create_text(str_cntr, peek());
|
||||
free(str_cntr);
|
||||
str_cntr = NULL;
|
||||
}
|
||||
pop();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
free(x);
|
||||
utils_free_array(stack);
|
||||
return ret;
|
||||
cleanup:
|
||||
if (x)
|
||||
{
|
||||
free(x);
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
dom_free_element(ret);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void dom_free_element(html_elem_t *e)
|
||||
{
|
||||
char *key, *val;
|
||||
if (!e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
free(e->name);
|
||||
while (utils_hashmap_list(e->attrs, &key, (void **) &val))
|
||||
{
|
||||
free(val);
|
||||
}
|
||||
utils_free_hashmap(e->attrs);
|
||||
|
||||
if (e->has_text)
|
||||
{
|
||||
free(e->children.text);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t i, children;
|
||||
children = utils_array_size(e->children.elems);
|
||||
for (i = 0; i < children; i++)
|
||||
{
|
||||
html_elem_t *c = utils_array_get(e->children.elems, i);
|
||||
dom_free_element(c);
|
||||
}
|
||||
utils_free_array(e->children.elems);
|
||||
}
|
||||
free(e);
|
||||
}
|
||||
|
||||
static html_elem_t *create_text(char *text, html_elem_t *parent)
|
||||
{
|
||||
html_elem_t *ret;
|
||||
if (!text)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = create_element("[<text>]", parent);
|
||||
utils_free_array(ret->children.elems);
|
||||
ret->has_text = true;
|
||||
ret->children.text = utils_strcpy(text);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static html_elem_t *create_element(char *name, html_elem_t *parent)
|
||||
{
|
||||
html_elem_t *ret;
|
||||
if (!name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
ret = malloc(sizeof(*ret));
|
||||
ret->name = utils_strcpy(name);
|
||||
ret->children.elems = utils_new_array();
|
||||
ret->has_text = false;
|
||||
ret->attrs = utils_new_hashmap();
|
||||
ret->parent = parent;
|
||||
|
||||
if (parent && !parent->has_text)
|
||||
{
|
||||
utils_array_add(parent->children.elems, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
static void add_attr(html_elem_t *e, char *key, char *value)
|
||||
{
|
||||
if (!e || !key || !value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
utils_hashmap_add(e->attrs, key, utils_strcpy(value));
|
||||
}
|
||||
static void concat_str(char **initial, char *add)
|
||||
{
|
||||
char *new;
|
||||
if (!initial || !add)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!*initial)
|
||||
{
|
||||
*initial = utils_strcpy(add);
|
||||
return;
|
||||
}
|
||||
new = utils_strcat(*initial, add);
|
||||
free(*initial);
|
||||
*initial = new;
|
||||
}
|
|
@ -13,8 +13,8 @@ void easter_dvd_frame(const char *str)
|
|||
|
||||
if (x == -100 && y == -100)
|
||||
{
|
||||
x = rand() % DWIDTH;
|
||||
y = rand() % DHEIGHT;
|
||||
x = rand() % (DWIDTH - w);
|
||||
y = rand() % (DHEIGHT - h);
|
||||
}
|
||||
|
||||
x += dx;
|
||||
|
|
78
src/event.c
|
@ -1,3 +1,4 @@
|
|||
#include "http.h"
|
||||
#include <matrix.h>
|
||||
|
||||
#include <justui/jlabel.h>
|
||||
|
@ -72,6 +73,7 @@ extern m_event_t *matrix_parse_event(hashmap_t *json, bool strict)
|
|||
event->sender = sender;
|
||||
event->state_key = state_key;
|
||||
event->type = type;
|
||||
event->redacted = false;
|
||||
|
||||
return event;
|
||||
fail:
|
||||
|
@ -105,3 +107,79 @@ void matrix_free_event(m_event_t *event)
|
|||
end_val(type, free);
|
||||
#undef end_val
|
||||
}
|
||||
|
||||
hashmap_t *matrix_event_to_json(m_user_t *user, m_event_t *event)
|
||||
{
|
||||
http_transfer_t *trans;
|
||||
hashmap_t *ret;
|
||||
char *path;
|
||||
if (!event || !user)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = utils_sprintf(
|
||||
"/_matrix/client/v3/rooms/%s/event/%s",
|
||||
event->room_id, event->event_id
|
||||
);
|
||||
trans = http_transfer_create(HTTP_GET, user->server, path);
|
||||
matrix_set_token(trans, user);
|
||||
free(path);
|
||||
http_transfer_send(trans);
|
||||
if (http_transfer_code(trans) != 200)
|
||||
{
|
||||
http_transfer_free(trans);
|
||||
return NULL;
|
||||
}
|
||||
ret = http_get_reply_json(trans);
|
||||
http_transfer_free(trans);
|
||||
|
||||
return ret;
|
||||
}
|
||||
json_value_t *matrix_get_relation_property(m_event_t *e, char *k)
|
||||
{
|
||||
json_value_t *rel_v;
|
||||
hashmap_t *rel;
|
||||
if (!e || !k)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rel_v = utils_hashmap_get(e->content, "m.relates_to");
|
||||
if (!rel_v)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
rel = utils_json_as_object(rel_v);
|
||||
return utils_hashmap_get(rel, k);
|
||||
}
|
||||
char *matrix_get_relation_type(m_event_t *event)
|
||||
{
|
||||
return utils_json_as_string(
|
||||
matrix_get_relation_property(event, "rel_type")
|
||||
);
|
||||
}
|
||||
char *matrix_get_relation_source(m_event_t *event)
|
||||
{
|
||||
return utils_json_as_string(
|
||||
matrix_get_relation_property(event, "event_id")
|
||||
);
|
||||
}
|
||||
void matrix_add_relation(char *id, m_room_t *room, m_event_t *event)
|
||||
{
|
||||
array_t *relations;
|
||||
if (!id || !room || !event)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
relations = utils_hashmap_get(room->relations, id);
|
||||
if (!relations)
|
||||
{
|
||||
relations = utils_new_array();
|
||||
utils_hashmap_add(room->relations, id, relations);
|
||||
}
|
||||
log_text("adding relation to event %s", id);
|
||||
|
||||
utils_array_add(relations, event);
|
||||
}
|
||||
|
|
391
src/event_ui.c
|
@ -1,31 +1,40 @@
|
|||
#include <matrix.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <justui/jlabel.h>
|
||||
|
||||
#include <utils.h>
|
||||
#include <log.h>
|
||||
#include <ui.h>
|
||||
|
||||
#include <WebCalc.h>
|
||||
#include <DOM.h>
|
||||
#include <dom.h>
|
||||
|
||||
#define GRAY C_RGB(20, 20, 20)
|
||||
extern bopti_image_t fileicon;
|
||||
extern font_t terminus_weak;
|
||||
extern font_t terminus_strong;
|
||||
extern font_t uf8x9;
|
||||
extern font_t uf5x7;
|
||||
|
||||
typedef struct dom_state {
|
||||
bool italic, bold;
|
||||
int bg, fg;
|
||||
m_event_t *event;
|
||||
m_room_t *room;
|
||||
} dom_state_t;
|
||||
static void *render_span(void *p, struct DomElement *dom, dom_state_t state)
|
||||
static void *render_text(void *p, html_elem_t *elem, dom_state_t state)
|
||||
{
|
||||
jlabel *label;
|
||||
|
||||
if (!elem->has_text)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
label = jlabel_create("", p);
|
||||
jlabel_asprintf(label, "%s", dom->textNode);
|
||||
jlabel_asprintf(label, "%s", elem->children.text);
|
||||
jlabel_set_font(label, &uf5x7);
|
||||
if (state.italic)
|
||||
{
|
||||
jlabel_set_font(label, &terminus_weak);
|
||||
|
@ -44,26 +53,30 @@ static void *render_span(void *p, struct DomElement *dom, dom_state_t state)
|
|||
}
|
||||
return label;
|
||||
}
|
||||
static jwidget *parse_msg_body_dom(void *p, struct DomElement *dom, dom_state_t s)
|
||||
static jwidget *parse_msg_body_dom(void *p, html_elem_t *elem, dom_state_t s)
|
||||
{
|
||||
size_t i;
|
||||
size_t i, children;
|
||||
jwidget *container = jwidget_create(p);
|
||||
jwidget *line;
|
||||
jwidget_set_stretch(container, 1, 0, false);
|
||||
jlayout_set_vbox(container)->spacing = 1;
|
||||
jwidget_set_stretch(container, 1, 0, false);
|
||||
|
||||
line = jwidget_create(container);
|
||||
jlayout_set_hbox(line)->spacing = 1;
|
||||
jwidget_set_stretch(line, 1, 0, false);
|
||||
jlayout_set_hbox(line)->spacing = 0;
|
||||
jwidget_set_stretch(line, 1, 1, false);
|
||||
|
||||
for (i = 0; i < dom->childnum; i++)
|
||||
children = utils_array_size(elem->children.elems);
|
||||
|
||||
for (i = 0; i < children; i++)
|
||||
{
|
||||
struct DomElement *item = dom->children[i];
|
||||
if (!strcmp(item->tagName, "span"))
|
||||
html_elem_t *item = utils_array_get(elem->children.elems, i);
|
||||
bool has_reply = false;
|
||||
has_reply = !!matrix_get_relation_property(s.event, "m.in_reply_to");
|
||||
if (item->has_text)
|
||||
{
|
||||
render_span(line, item, s);
|
||||
render_text(line, item, s);
|
||||
}
|
||||
else if (!strcmp(item->tagName, "u"))
|
||||
else if (!strcmp(item->name, "u"))
|
||||
{
|
||||
jwidget *box = jwidget_create(line);
|
||||
jwidget *ul;
|
||||
|
@ -75,19 +88,18 @@ static jwidget *parse_msg_body_dom(void *p, struct DomElement *dom, dom_state_t
|
|||
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"))
|
||||
else if(!strcmp(item->name, "i") ||
|
||||
!strcmp(item->name, "em"))
|
||||
{
|
||||
dom_state_t sc = s;
|
||||
sc.italic = true;
|
||||
parse_msg_body_dom(line, item, sc);
|
||||
}
|
||||
else if (!strcmp(item->tagName, "code"))
|
||||
else if (!strcmp(item->name, "code"))
|
||||
{
|
||||
dom_state_t sc = s;
|
||||
sc.italic = true;
|
||||
|
@ -96,58 +108,79 @@ static jwidget *parse_msg_body_dom(void *p, struct DomElement *dom, dom_state_t
|
|||
|
||||
parse_msg_body_dom(line, item, sc);
|
||||
}
|
||||
else if (!strcmp(item->tagName, "strong"))
|
||||
else if (!strcmp(item->name, "strong"))
|
||||
{
|
||||
dom_state_t sc = s;
|
||||
sc.bold = true;
|
||||
parse_msg_body_dom(line, item, sc);
|
||||
}
|
||||
else if (!strcmp(item->tagName, "p"))
|
||||
else if (!strcmp(item->name, "p"))
|
||||
{
|
||||
parse_msg_body_dom(line, item, s);
|
||||
line = jwidget_create(container);
|
||||
jlayout_set_hbox(line)->spacing = 1;
|
||||
jlayout_set_vbox(line)->spacing = 0;
|
||||
}
|
||||
else if (!strcmp(item->tagName, "h1"))
|
||||
else if (!strcmp(item->name, "h1"))
|
||||
{
|
||||
void *w;
|
||||
dom_state_t sc = s;
|
||||
|
||||
sc.bold = true;
|
||||
sc.fg = GRAY;
|
||||
w = parse_msg_body_dom(line, item, sc);
|
||||
parse_msg_body_dom(line, item, sc);
|
||||
|
||||
line = jwidget_create(container);
|
||||
jlayout_set_hbox(line)->spacing = 1;
|
||||
jwidget_set_stretch(line, 1, 0, false);
|
||||
jlayout_set_vbox(line)->spacing = 0;
|
||||
jwidget_set_stretch(line, 1, 1, false);
|
||||
}
|
||||
else if (!strcmp(item->name, "a"))
|
||||
{
|
||||
dom_state_t sc = s;
|
||||
|
||||
sc.fg = C_RGB(4, 17, 26);
|
||||
sc.bg = GRAY;
|
||||
parse_msg_body_dom(line, item, sc);
|
||||
}
|
||||
else if (!strcmp(item->name, "blockquote"))
|
||||
{
|
||||
dom_state_t sc = s;
|
||||
|
||||
sc.italic = true;
|
||||
sc.fg = GRAY;
|
||||
sc.bg = C_NONE;
|
||||
parse_msg_body_dom(line, item, sc);
|
||||
|
||||
line = jwidget_create(container);
|
||||
jlayout_set_vbox(line)->spacing = 0;
|
||||
jwidget_set_stretch(line, 1, 1, false);
|
||||
}
|
||||
else if (!strcmp(item->name, "br"))
|
||||
{
|
||||
line = jwidget_create(container);
|
||||
jlayout_set_vbox(line)->spacing = 0;
|
||||
jwidget_set_stretch(line, 1, 1, false);
|
||||
parse_msg_body_dom(line, item, s);
|
||||
}
|
||||
else if (!strcmp(item->tagName, "br"))
|
||||
else if (!strcmp(item->name, "mx-reply") && has_reply)
|
||||
{
|
||||
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);
|
||||
/* Do nothing. TODO: Render in separate. */
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
/* Try your best rendering. */
|
||||
parse_msg_body_dom(line, item, s);
|
||||
}
|
||||
}
|
||||
return container;
|
||||
}
|
||||
static jwidget *parse_msg_body_html(void *p, char *html)
|
||||
static jwidget *parse_msg_body_html(void *p, char *html, m_room_t *r, m_event_t *e)
|
||||
{
|
||||
struct el_t *top;
|
||||
struct DomElement *dom;
|
||||
html_elem_t *elem;
|
||||
char *contained, *cpy;
|
||||
jwidget *container;
|
||||
size_t i;
|
||||
dom_state_t def = {
|
||||
.bg = C_NONE, .fg = C_NONE,
|
||||
.bold = false, .italic = false
|
||||
.bold = false, .italic = false,
|
||||
.room = r, .event = e
|
||||
};
|
||||
|
||||
contained = utils_strcat("<html>", html);
|
||||
|
@ -155,25 +188,24 @@ static jwidget *parse_msg_body_html(void *p, char *html)
|
|||
contained = utils_strcat(contained, "</html>");
|
||||
free(cpy);
|
||||
|
||||
html_parse(contained, contained + strlen(contained));
|
||||
top = html_elem();
|
||||
if (!top)
|
||||
elem = dom_parse_element(contained);
|
||||
if (!elem)
|
||||
{
|
||||
free(contained);
|
||||
return NULL;
|
||||
}
|
||||
dom = top->dom;
|
||||
|
||||
/* Actually manage the HTML */
|
||||
container = parse_msg_body_dom(p, dom, def);
|
||||
container = parse_msg_body_dom(p, elem, def);
|
||||
if (!container)
|
||||
{
|
||||
free(contained);
|
||||
html_clear();
|
||||
dom_free_element(elem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free(contained);
|
||||
html_clear();
|
||||
dom_free_element(elem);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
@ -184,15 +216,60 @@ static jwidget *parse_msg_body_plain(void *p, char *plain)
|
|||
jwidget_set_stretch(container, 1, 0, false);
|
||||
|
||||
label = jlabel_create("", container);
|
||||
jlabel_set_font(label, &uf5x7);
|
||||
jlabel_asprintf(label, "%s", plain);
|
||||
|
||||
return container;
|
||||
}
|
||||
static jwidget *parse_msg_body(hashmap_t *body, void *p)
|
||||
static jwidget *parse_msg_body(hashmap_t *body, void *p, m_room_t *r, m_event_t *e, m_user_t *u)
|
||||
{
|
||||
char *formatted_as = utils_json_as_string(
|
||||
utils_hashmap_get(body, "format")
|
||||
);
|
||||
json_value_t *reply_val = matrix_get_relation_property(e, "m.in_reply_to");
|
||||
|
||||
if (reply_val)
|
||||
{
|
||||
|
||||
hashmap_t *reply_obj = utils_json_as_object(reply_val);
|
||||
json_value_t *id = utils_hashmap_get(reply_obj, "event_id");
|
||||
char *id_str = utils_json_as_string(id);
|
||||
m_event_t *reply_event = utils_array_get(
|
||||
r->timeline, is_in_timeline(r, id_str)
|
||||
);
|
||||
|
||||
uint16_t color = reply_event ? matrix_hash(reply_event->sender) : 0;
|
||||
|
||||
if (color)
|
||||
{
|
||||
jwidget *bar_and_reply = jwidget_create(p);
|
||||
jwidget *reply_and_content = jwidget_create(bar_and_reply);
|
||||
jwidget *b_reply = jwidget_create(reply_and_content);
|
||||
jwidget *bar = jwidget_create(b_reply);
|
||||
jwidget *reply = jwidget_create(b_reply);
|
||||
|
||||
p = jwidget_create(reply_and_content);
|
||||
|
||||
jlayout_set_hbox(bar_and_reply)->spacing = 1;
|
||||
jwidget_set_stretch(bar_and_reply, 1, 0, false);
|
||||
|
||||
jlayout_set_hbox(b_reply)->spacing = 1;
|
||||
jwidget_set_stretch(b_reply, 1, 0, false);
|
||||
|
||||
jwidget_set_fixed_width(bar, 5);
|
||||
jwidget_set_minimum_height(bar, 30);
|
||||
jwidget_set_stretch(bar, 1, 1, false);
|
||||
jwidget_set_background(bar, color);
|
||||
jwidget_set_border(bar, J_BORDER_SOLID, 1, GRAY);
|
||||
|
||||
jlayout_set_vbox(reply_and_content)->spacing = 0;
|
||||
jwidget_set_stretch(reply_and_content, 1, 0, false);
|
||||
jwidget_set_stretch(reply, 1, 0, false);
|
||||
jwidget_set_stretch(p, 1, 0, false);
|
||||
matrix_show_event(r, u, reply_event, reply);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!formatted_as || strcmp(formatted_as, "org.matrix.custom.html"))
|
||||
{
|
||||
|
@ -206,7 +283,7 @@ static jwidget *parse_msg_body(hashmap_t *body, void *p)
|
|||
jwidget *w = parse_msg_body_html(p,
|
||||
utils_json_as_string(
|
||||
utils_hashmap_get(body, "formatted_body")
|
||||
)
|
||||
), r, e
|
||||
);
|
||||
if (!w)
|
||||
{
|
||||
|
@ -226,9 +303,26 @@ static void show_msg(m_room_t *r, m_user_t *u, m_event_t *e, jwidget *w)
|
|||
utils_hashmap_get(e->content, "msgtype")
|
||||
);
|
||||
|
||||
if (e->redacted)
|
||||
{
|
||||
/* Don't even try. */
|
||||
jlabel *content;
|
||||
|
||||
content = jlabel_create("[Redacted]", w);
|
||||
jlabel_set_text_color(content, GRAY);
|
||||
jwidget_set_stretch(content, 1, 0, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(subtype, "m.text"))
|
||||
{
|
||||
parse_msg_body(e->content, w);
|
||||
parse_msg_body(e->content, w, r, e, u);
|
||||
return;
|
||||
}
|
||||
if (!strcmp(subtype, "m.notice"))
|
||||
{
|
||||
/* TODO: Indicate that the message comes from a brobot */
|
||||
parse_msg_body(e->content, w, r, e, u);
|
||||
return;
|
||||
}
|
||||
if (!strcmp(subtype, "m.emote"))
|
||||
|
@ -250,18 +344,31 @@ static void show_msg(m_room_t *r, m_user_t *u, m_event_t *e, jwidget *w)
|
|||
);
|
||||
}
|
||||
jwidget_set_stretch(content, 1, 0, false);
|
||||
return;
|
||||
}
|
||||
if (!strcmp(subtype, "m.image"))
|
||||
{
|
||||
json_value_t *url_val;
|
||||
jmimage *img;
|
||||
|
||||
url_val = utils_hashmap_get(e->content, "url");
|
||||
img = matrix_image_from_mxc(
|
||||
w, u,
|
||||
utils_json_as_string(url_val), 96
|
||||
);
|
||||
jwidget_set_stretch(img, 1, 0, false);
|
||||
return;
|
||||
}
|
||||
if (!strcmp(subtype, "m.file"))
|
||||
{
|
||||
char *body;
|
||||
jwidget *contentf;
|
||||
jpainted *fi;
|
||||
jlabel *content;
|
||||
|
||||
contentf = jwidget_create(w);
|
||||
jwidget_set_stretch(contentf, 1, 0, false);
|
||||
jlayout_set_hbox(contentf)->spacing = 2;
|
||||
fi = ui_image(contentf, &fileicon);
|
||||
ui_image(contentf, &fileicon);
|
||||
|
||||
body = utils_json_as_string(utils_hashmap_get(e->content, "body"));
|
||||
content = jlabel_create("", contentf);
|
||||
|
@ -283,12 +390,104 @@ static void show_msg(m_room_t *r, m_user_t *u, m_event_t *e, jwidget *w)
|
|||
jwidget_set_stretch(content, 1, 0, false);
|
||||
}
|
||||
}
|
||||
extern img_t default_pfp;
|
||||
#define default_msg_head() \
|
||||
img = matrix_image_from_room_user(\
|
||||
content_box, \
|
||||
u, \
|
||||
utils_hashmap_get(u->rooms, e->room_id),\
|
||||
e->sender\
|
||||
);\
|
||||
if (!img)\
|
||||
{\
|
||||
img = jmimage_create(content_box, default_pfp);\
|
||||
}\
|
||||
wbox = jwidget_create(content_box);\
|
||||
jwidget_set_stretch(wbox, 1, 0, false);\
|
||||
jlayout_set_vbox(wbox)->spacing = 1;\
|
||||
nick = matrix_resolve_nick(u, e->sender, r);\
|
||||
sender = jlabel_create("", wbox);\
|
||||
jlabel_set_font(sender, &uf5x7);\
|
||||
jlabel_asprintf(sender, "%s", nick);\
|
||||
jlabel_set_text_color(sender, matrix_hash(e->sender));\
|
||||
jwidget_set_stretch(sender, 1, 0, false);\
|
||||
content = jwidget_create(wbox);\
|
||||
jwidget_set_stretch(content, 1, 0, false);\
|
||||
jlayout_set_vbox(content)->spacing = 1
|
||||
|
||||
void show_member(m_room_t *r, m_user_t *u, m_event_t *e, jwidget *content_box)
|
||||
{
|
||||
char *membership = utils_json_as_string(
|
||||
utils_hashmap_get(e->content, "membership")
|
||||
);
|
||||
char *name = utils_json_as_string(
|
||||
utils_hashmap_get(e->content, "displayname")
|
||||
);
|
||||
char *reason = utils_json_as_string(
|
||||
utils_hashmap_get(e->content, "reason")
|
||||
);
|
||||
jlabel *label;
|
||||
|
||||
if (!name)
|
||||
{
|
||||
name = e->state_key;
|
||||
}
|
||||
label = jlabel_create("", content_box);
|
||||
jwidget_set_stretch(label, 1, 0, false);
|
||||
jlabel_set_font(label, &uf8x9);
|
||||
jlabel_set_text_color(label, GRAY);
|
||||
if (!strcmp(membership, "join"))
|
||||
{
|
||||
jlabel_asprintf(label, "%s joined.", name);
|
||||
}
|
||||
if (!strcmp(membership, "leave"))
|
||||
{
|
||||
if (!reason)
|
||||
{
|
||||
jlabel_asprintf(label, "%s left.", name);
|
||||
return;
|
||||
}
|
||||
jlabel_asprintf(label, "%s left: %s", name, reason);
|
||||
}
|
||||
if (!strcmp(membership, "invite"))
|
||||
{
|
||||
char *who;
|
||||
if (!(who = matrix_resolve_nick(u, e->sender, r)))
|
||||
{
|
||||
who = e->sender;
|
||||
}
|
||||
jlabel_asprintf(label, "%s was invited by %s.", name, who);
|
||||
}
|
||||
if (!strcmp(membership, "ban"))
|
||||
{
|
||||
char *who;
|
||||
if (!(who = matrix_resolve_nick(u, e->sender, r)))
|
||||
{
|
||||
who = e->sender;
|
||||
}
|
||||
if (!reason)
|
||||
{
|
||||
jlabel_asprintf(
|
||||
label,
|
||||
"%s was banned by %s.", name, who
|
||||
);
|
||||
return;
|
||||
}
|
||||
jlabel_asprintf(
|
||||
label,
|
||||
"%s was banned by %s: %s", name, who, reason
|
||||
);
|
||||
}
|
||||
}
|
||||
void matrix_show_event(m_room_t *r, m_user_t *u, m_event_t *e, jwidget *w)
|
||||
{
|
||||
char *event_type;
|
||||
char *nick;
|
||||
|
||||
jwidget *wbox;
|
||||
jwidget *content;
|
||||
jwidget *content_box;
|
||||
jmimage *img;
|
||||
jlabel *sender;
|
||||
if (!r || !u || !e || !w)
|
||||
{
|
||||
|
@ -296,26 +495,92 @@ void matrix_show_event(m_room_t *r, m_user_t *u, m_event_t *e, jwidget *w)
|
|||
}
|
||||
|
||||
|
||||
jlayout_set_vbox(w)->spacing = 2;
|
||||
jwidget_set_stretch(w, 1, 0, false);
|
||||
jlayout_set_vbox(w)->spacing = 1;
|
||||
content_box = jwidget_create(w);
|
||||
jwidget_set_stretch(content_box, 1, 0, false);
|
||||
jlayout_set_hbox(content_box)->spacing = 1;
|
||||
|
||||
/* Set nickname properly */
|
||||
nick = matrix_resolve_nick(u, e->sender, r);
|
||||
sender = jlabel_create("", w);
|
||||
jlabel_asprintf(sender, "%s", nick);
|
||||
jlabel_set_text_color(sender, matrix_hash(e->sender));
|
||||
jwidget_set_stretch(sender, 1, 0, false);
|
||||
|
||||
content = jwidget_create(w);
|
||||
jwidget_set_stretch(content, 1, 0, false);
|
||||
jlayout_set_vbox(content)->spacing = 1;
|
||||
|
||||
event_type = e->type;
|
||||
|
||||
if (!strcmp(event_type, "m.room.message"))
|
||||
{
|
||||
default_msg_head();
|
||||
show_msg(r, u, e, content);
|
||||
return;
|
||||
}
|
||||
if (!strcmp(event_type, "m.sticker"))
|
||||
{
|
||||
json_value_t *url_val;
|
||||
jmimage *img;
|
||||
|
||||
default_msg_head();
|
||||
|
||||
url_val = utils_hashmap_get(e->content, "url");
|
||||
img = matrix_image_from_mxc(
|
||||
content,
|
||||
u,
|
||||
utils_json_as_string(url_val),
|
||||
32
|
||||
);
|
||||
jwidget_set_stretch(img, 1, 0, false);
|
||||
}
|
||||
if (!strcmp(event_type, "m.room.member"))
|
||||
{
|
||||
show_member(r, u, e, content_box);
|
||||
}
|
||||
if (!strcmp(event_type, "m.reaction"))
|
||||
{
|
||||
jlabel *label;
|
||||
char *key = utils_json_as_string(
|
||||
matrix_get_relation_property(e, "key")
|
||||
);
|
||||
char *nick = matrix_resolve_nick(u, e->sender, r);
|
||||
if (!nick)
|
||||
{
|
||||
nick = e->sender;
|
||||
}
|
||||
|
||||
label = jlabel_create("", content_box);
|
||||
jlabel_asprintf(label, "%s reacted with '%s'", nick, key);
|
||||
if (!key)
|
||||
{
|
||||
jlabel_asprintf(label, "[Redacted]");
|
||||
}
|
||||
jwidget_set_stretch(label, 1, 0, false);
|
||||
jlabel_set_font(label, &uf8x9);
|
||||
jlabel_set_text_color(label, GRAY);
|
||||
}
|
||||
{
|
||||
array_t *relations = utils_hashmap_get(r->relations, e->event_id);
|
||||
size_t i;
|
||||
jwidget *reactions;
|
||||
if (!relations)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
reactions = jwidget_create(w);
|
||||
jwidget_set_stretch(reactions, 1, 0, false);
|
||||
jlayout_set_hbox(reactions)->spacing = 3;
|
||||
|
||||
for (i = 0; i < utils_array_size(relations); i++)
|
||||
{
|
||||
m_event_t *child = utils_array_get(relations, i);
|
||||
char *rel_type = matrix_get_relation_type(child);
|
||||
|
||||
|
||||
if (!strcmp(rel_type, "m.annotation"))
|
||||
{
|
||||
jlabel *label = jlabel_create("", reactions);
|
||||
char *key = utils_json_as_string(
|
||||
matrix_get_relation_property(child, "key")
|
||||
);
|
||||
|
||||
jlabel_asprintf(label, "[%s]", key);
|
||||
jlabel_set_font(label, &uf5x7);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* TODO: Other message types */
|
||||
}
|
||||
|
|
125
src/file.c
|
@ -1,18 +1,26 @@
|
|||
#include <utils.h>
|
||||
|
||||
#include <gint/gint.h>
|
||||
#include <gint/fs.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <usb.h>
|
||||
|
||||
static volatile char *data;
|
||||
static volatile size_t len;
|
||||
static volatile bool fine;
|
||||
|
||||
|
||||
static void os_get(char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "r");
|
||||
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f)
|
||||
{
|
||||
fine = false;
|
||||
return;
|
||||
}
|
||||
fseek(f, 0L, SEEK_END);
|
||||
len = ftell(f);
|
||||
rewind(f);
|
||||
|
@ -27,12 +35,125 @@ char * utils_get_file(char *path, size_t *l)
|
|||
int null;
|
||||
|
||||
usb_close();
|
||||
fine = true;
|
||||
gint_world_switch(GINT_CALL(os_get, path));
|
||||
*l = len;
|
||||
usb_init(&null, &null);
|
||||
|
||||
if (!fine)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void) null;
|
||||
|
||||
return (char *) data;
|
||||
}
|
||||
|
||||
static void os_put(char *path, char *data, uint32_t l)
|
||||
{
|
||||
FILE *f = fopen(path, "wb");
|
||||
fwrite(data, l, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
void utils_write_file(char *path, char *data, size_t l)
|
||||
{
|
||||
int null;
|
||||
if (!path || !data || l == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
usb_close();
|
||||
gint_world_switch(GINT_CALL(os_put, path, data, (uint32_t) l));
|
||||
usb_init(&null, &null);
|
||||
|
||||
(void) null;
|
||||
}
|
||||
|
||||
void utils_delete_file(char *path)
|
||||
{
|
||||
int null;
|
||||
if (!path)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
usb_close();
|
||||
gint_world_switch(GINT_CALL(remove, path));
|
||||
usb_init(&null, &null);
|
||||
|
||||
(void) null;
|
||||
}
|
||||
|
||||
typedef struct memory_info {
|
||||
void *buffer;
|
||||
size_t size;
|
||||
|
||||
off_t pos;
|
||||
} memory_info_t;
|
||||
|
||||
static ssize_t r(void *data, void *buf, size_t size)
|
||||
{
|
||||
memory_info_t *info = data;
|
||||
ssize_t left = ((ssize_t) (info->size)) - ((ssize_t) info->pos);
|
||||
ssize_t min = left < (ssize_t) size ? left : (ssize_t) size;
|
||||
if (left <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
memcpy(buf, (char *) (info->buffer) + info->pos, min);
|
||||
info->pos += min;
|
||||
return min;
|
||||
}
|
||||
|
||||
off_t s(void *data, off_t offset, int whence)
|
||||
{
|
||||
memory_info_t *info = data;
|
||||
if (whence == SEEK_SET)
|
||||
{
|
||||
info->pos = offset;
|
||||
}
|
||||
if (whence == SEEK_CUR)
|
||||
{
|
||||
info->pos += offset;
|
||||
}
|
||||
if (whence == SEEK_END)
|
||||
{
|
||||
info->pos = info->size + offset;
|
||||
}
|
||||
|
||||
return info->pos;
|
||||
}
|
||||
int c(void *data)
|
||||
{
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fs_descriptor_type_t mem_type = {
|
||||
.read = r,
|
||||
.write = NULL,
|
||||
.lseek = s,
|
||||
.close = c,
|
||||
};
|
||||
int utils_openmem(void *buf, size_t size)
|
||||
{
|
||||
memory_info_t *info;
|
||||
if (!buf || !size)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
info = malloc(sizeof(memory_info_t));
|
||||
info->buffer = buf;
|
||||
info->size = size;
|
||||
info->pos = 0;
|
||||
|
||||
return open_generic(&mem_type, info, -1);
|
||||
}
|
||||
FILE *utils_fopenmem(void *buf, size_t size)
|
||||
{
|
||||
/* You can't write there. */
|
||||
return fdopen(utils_openmem(buf, size), "rb");
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ __attribute((noreturn)) void goda_panic(uint32_t code)
|
|||
dtext(50, 61, C_WHITE, "How do you even fucking find this any funny?");
|
||||
dupdate();
|
||||
|
||||
(void) code;
|
||||
|
||||
while (true);
|
||||
}
|
||||
|
||||
|
@ -38,7 +40,7 @@ void easter_goda(void)
|
|||
img_t goda_decal;
|
||||
size_t i;
|
||||
size_t ex, ey;
|
||||
int x;
|
||||
size_t x;
|
||||
timeout_t tm;
|
||||
|
||||
const char *godatxt =
|
||||
|
@ -114,7 +116,7 @@ void easter_goda(void)
|
|||
}
|
||||
dupdate();
|
||||
x++;
|
||||
if (x >= (godatxtw + 60))
|
||||
if (x >= (size_t) (godatxtw + 60))
|
||||
{
|
||||
x = -DWIDTH;
|
||||
i++;
|
||||
|
|
|
@ -30,7 +30,7 @@ static size_t string_hash(char *str)
|
|||
size_t hash = 5381;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < strlen(str); i++)
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
hash = (hash << 5) + hash + str[i];
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ void * utils_hashmap_get(hashmap_t *hm, char *key)
|
|||
size_t hash, probing;
|
||||
size_t lhsh;
|
||||
|
||||
bool found = false;
|
||||
|
||||
|
||||
if (!hm || !key || hm->on_it)
|
||||
{
|
||||
|
@ -135,8 +135,6 @@ void * utils_hashmap_set(hashmap_t *hm, char *key, void *value)
|
|||
|
||||
void *prev = NULL;
|
||||
|
||||
size_t i;
|
||||
|
||||
if (!hm || !key || !value)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -170,8 +168,6 @@ void * utils_hashmap_del(hashmap_t *hm, char *key)
|
|||
size_t hash, probing;
|
||||
size_t lhsh;
|
||||
|
||||
bool found = false;
|
||||
|
||||
if (!hm || !key || !hm->on_it)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -246,5 +242,6 @@ bool utils_hashmap_list(hashmap_t *hm, char **kp, void **vp)
|
|||
}
|
||||
size_t utils_hashmap_elems(hashmap_t *hm)
|
||||
{
|
||||
|
||||
(void) hm;
|
||||
return 0;
|
||||
}
|
||||
|
|
456
src/html.c
|
@ -1,456 +0,0 @@
|
|||
#include <WebCalc.h>
|
||||
|
||||
#include <log.h>
|
||||
|
||||
int isvalid(int c)
|
||||
{
|
||||
return (c>='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z')
|
||||
|| c=='-';
|
||||
}
|
||||
|
||||
#define isspecs(c) ((c)=='/' || (c)=='!')
|
||||
#define isspace(c) ((c)==' ' || (c)=='\t' || (c)=='\n')
|
||||
|
||||
// Block type enumeration definition.
|
||||
enum block_t
|
||||
{
|
||||
block_tag = 0,
|
||||
block_text = 1
|
||||
};
|
||||
|
||||
|
||||
static struct el_t *top = NULL;
|
||||
static struct el_t *tiff = NULL;
|
||||
|
||||
|
||||
struct el_t *html_elem(void)
|
||||
{
|
||||
return tiff;
|
||||
}
|
||||
|
||||
/**
|
||||
* html_text()
|
||||
*
|
||||
* Indicates if the given tag name is associated with a text content, or
|
||||
* not.
|
||||
*
|
||||
* @param name Reference on tag name.
|
||||
*
|
||||
* @return 1 if the tag is supposed to have a text content, 0
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
static int html_text(reference_t name)
|
||||
{
|
||||
const char *texts[] = { "p", "h1", "h2", "h3", "h4", "h5", "h6",
|
||||
"math", "center", "right", NULL };
|
||||
const char **ptr = texts;
|
||||
|
||||
/*while(*ptr) if(!refscmp(name,*ptr++)) return 1;*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int html_conf(reference_t name)
|
||||
{
|
||||
const char *confs[] = { "head", "link", NULL };
|
||||
const char **ptr = confs;
|
||||
|
||||
while(*ptr) if(!refscmp(name,*ptr++)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void html_configure(reference_t name, reference_t args)
|
||||
{
|
||||
html_args(&args, NULL);
|
||||
reference_t arg, value;
|
||||
|
||||
/* Let's not add CSS like that. */
|
||||
/*if(!refscmp(name,"link"))
|
||||
{
|
||||
reference_t rel = { 0,0 }, href = { 0,0 };
|
||||
|
||||
while(1)
|
||||
{
|
||||
html_args(&arg, &value);
|
||||
if(refnull(arg)) break;
|
||||
else if(!refscmp(arg, "rel")) rel = value;
|
||||
else if(!refscmp(arg, "href")) href = value;
|
||||
}
|
||||
|
||||
if(refnull(rel) || refnull(href)) return;
|
||||
if(!refscmp(rel, "stylesheet")) Window_addStylesheet(href);
|
||||
}*/
|
||||
}
|
||||
|
||||
static void html_create(struct el_t *el)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
|
||||
// Debugging the tag parameters.
|
||||
fputs("{\n\t", stdout);
|
||||
ptr = el->name.begin;
|
||||
while(ptr < el->name.end) fputc(*ptr++, stdout);
|
||||
if(!refnull(el->args))
|
||||
{
|
||||
fputs("\n\t", stdout);
|
||||
ptr = el->args.begin;
|
||||
while(ptr < el->args.end) fputc(*ptr++, stdout);
|
||||
}
|
||||
if(!refnull(el->text))
|
||||
{
|
||||
fputs("\n\t\"", stdout);
|
||||
ptr = el->text.begin;
|
||||
while(ptr < el->text.end) fputc(*ptr++, stdout);
|
||||
fputc('"', stdout);
|
||||
}
|
||||
fputs("\n}\n\n", stdout);
|
||||
|
||||
|
||||
struct el_t *parent = el->down;
|
||||
|
||||
if(parent)
|
||||
{
|
||||
el->dom = DomElement_new(el->name, el->args, parent->dom,
|
||||
DomElement_getChild(parent->dom, -1));
|
||||
DomElement_addChild(parent->dom, el->dom);
|
||||
}
|
||||
else el->dom = DomElement_new(el->name, el->args, NULL, NULL);
|
||||
if (!strncmp(el->name.begin, "html", 4))
|
||||
{
|
||||
tiff = el;
|
||||
}
|
||||
|
||||
if(!refnull(el->text)) DomElement_setTextNode(el->dom, el->text);
|
||||
|
||||
/*if(!refscmp(el->name, "html")) Window_setHTML(el->dom);*/
|
||||
}
|
||||
|
||||
/**
|
||||
* html_event()
|
||||
*
|
||||
* Treats an event that concerns the given block with the given type. An
|
||||
* event may lead to one of the following operations :
|
||||
* - adding an element to the stack
|
||||
* - removing an element from the stack, creating the dom object
|
||||
* - setting parameters of the top object
|
||||
*
|
||||
* @param block Reference on the event block.
|
||||
* @param type Type of the given block.
|
||||
*
|
||||
* @return Expected type for the next block.
|
||||
*/
|
||||
|
||||
static enum block_t html_event(reference_t *b, enum block_t type)
|
||||
{
|
||||
// Using a temporary name and arguments references for validity tests.
|
||||
reference_t name, args, block1, block;
|
||||
// Using a common pointer and a common integer.
|
||||
const char *ptr;
|
||||
int x;
|
||||
|
||||
block = *b;
|
||||
|
||||
// Receiving an event for text content.
|
||||
if(type == block_text)
|
||||
{
|
||||
// Setting the content reference.
|
||||
if(top) top->text = block;
|
||||
// Returning block_tag as nature of next expected element.
|
||||
return block_tag;
|
||||
}
|
||||
|
||||
|
||||
// Only tag events reach this point.
|
||||
// Extracting the tag name.
|
||||
block1 = block;
|
||||
while(!isvalid(*block.begin) && !isspecs(*block.begin) &&
|
||||
block.begin < block.end) block.begin++;
|
||||
if (block1.begin == block.begin)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
block1.end = block1.begin;
|
||||
while(*block1.end != '<') block1.end++;
|
||||
len = block1.end - block1.begin;
|
||||
|
||||
/* Create a fake element(span) with our text */
|
||||
struct el_t *el = (struct el_t *)malloc(sizeof(struct el_t));
|
||||
el->down = top;
|
||||
|
||||
// Setting element parameters.
|
||||
el->name.begin = "span";
|
||||
el->name.end = el->name.begin + strlen(el->name.begin);
|
||||
el->args.begin = "";
|
||||
el->args.end = el->args.begin;
|
||||
el->text = block1;
|
||||
log_text("%s: Spanning", __func__);
|
||||
|
||||
b->end = block1.end;
|
||||
|
||||
// Creating non-textual tags to ensure stack order.
|
||||
html_create(el);
|
||||
/*top = top->down;*/
|
||||
|
||||
// Returning the correct expected data type.
|
||||
return block_tag;
|
||||
}
|
||||
// Handling empty tags.
|
||||
if(block.begin == block.end) return block_tag;
|
||||
// Getting the name end.
|
||||
ptr = block.begin + isspecs(*block.begin);
|
||||
while(isvalid(*ptr)) ptr++;
|
||||
// Setting name reference.
|
||||
name.begin = block.begin;
|
||||
name.end = ptr;
|
||||
// Initializing tag validity checking operation.
|
||||
x = 0;
|
||||
ptr = name.begin + isspecs(*name.begin);
|
||||
// Checking tag validity. (e.g. '<//tag>', '<! >'). x is validity.
|
||||
while(ptr < name.end)
|
||||
{
|
||||
// Warning ! isvalid() is a macro, using *ptr++ would repeat
|
||||
// pointer incrementation !
|
||||
if(isvalid(*ptr)) x = 1;
|
||||
// Incrementing pointer.
|
||||
ptr++;
|
||||
}
|
||||
// A tag name is valid if it contains at least one valid character.
|
||||
if(!x) return block_tag;
|
||||
|
||||
// Looking for a parameter string.
|
||||
args.begin = name.end;
|
||||
args.end = block.end - 1;
|
||||
args = reftrim(args);
|
||||
|
||||
// Handling interpreter directives.
|
||||
if(*name.begin == '!')
|
||||
{
|
||||
/* Log is disabled.
|
||||
// Outputting a string.
|
||||
fputc('#', output);
|
||||
ptr = name.begin + 1;
|
||||
while(ptr < name.end) fputc(*ptr++, output);
|
||||
fputs(" ", output);
|
||||
ptr = args.begin;
|
||||
while(ptr < args.end) fputc(*ptr++, output);
|
||||
fputs("\n\n", output);
|
||||
*/
|
||||
// Returning a proper data type.
|
||||
return block_tag;
|
||||
}
|
||||
|
||||
if(html_conf(name))
|
||||
{
|
||||
html_configure(name, args);
|
||||
return block_tag;
|
||||
}
|
||||
|
||||
// Handling closing tags.
|
||||
if(*name.begin == '/')
|
||||
{
|
||||
name.begin++;
|
||||
if(html_conf(name)) return block_tag;
|
||||
|
||||
struct el_t *el = top->down;
|
||||
// Non-textual tags are created when opened.
|
||||
if (el)
|
||||
{
|
||||
if(!top->dom) html_create(top);
|
||||
free(top);
|
||||
top = el; /* Wouldn't that be the opposite? */
|
||||
}
|
||||
|
||||
return block_tag;
|
||||
}
|
||||
|
||||
|
||||
// Only opening tag events reach this point.
|
||||
// Allocating an object.
|
||||
struct el_t *el = (struct el_t *)malloc(sizeof(struct el_t));
|
||||
el->down = top;
|
||||
top = el;
|
||||
|
||||
// Setting element parameters.
|
||||
log_text("%s: %s (%p-%p)", __func__, name, name.end, name.begin);
|
||||
el->name = name;
|
||||
el->args = args;
|
||||
el->text.begin = el->text.end = NULL;
|
||||
|
||||
// Creating non-textual tags to ensure stack order.
|
||||
if(!html_text(name)) html_create(el);
|
||||
else el->dom = NULL;
|
||||
|
||||
// Returning the correct expected data type.
|
||||
return html_text(name) ? block_text : block_tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* html_next()
|
||||
*
|
||||
* Returns a reference on the next element of the given type in the given
|
||||
* code, defined by a begin and an end pointer.
|
||||
* An element may be empty, particularly when a text element (such as <p>)
|
||||
* does not contain any text.
|
||||
*
|
||||
* @param begin Pointer on code.
|
||||
* @param limit Pointer on the first byte that is outside the code.
|
||||
* @param type Type of expected element.
|
||||
*
|
||||
* @return Reference on the element.
|
||||
*/
|
||||
|
||||
static reference_t html_next(const char *begin, const char *limit,
|
||||
enum block_t type)
|
||||
{
|
||||
// Using a reference.
|
||||
reference_t ref = { begin, begin };
|
||||
|
||||
// Getting the next tag opening element.
|
||||
while(ref.end < limit && *ref.end != '<') ref.end++;
|
||||
// Returning if the given block type has the calculated limits.
|
||||
if(type == block_text) return ref;
|
||||
|
||||
// Otherwise, skipping the first text prevents returning empty blocks.
|
||||
while(ref.end < limit && *ref.end != '>') ref.end++;
|
||||
// Increasing ref.end to comply with program conventions on references.
|
||||
if(ref.end != limit) ref.end++;
|
||||
// Returning the computed reference.
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* html_parse()
|
||||
*
|
||||
* Parses the given html code, defined by a beginning and an end pointer.
|
||||
* The end pointer must point to the first byte outside the code. In other
|
||||
* words, it is supposed to be equal to `data + data_length`.
|
||||
* The generated DOM is stored in an element tree whose entry point is
|
||||
* global. All data is copied so the loaded code can be freed afterwards.
|
||||
*
|
||||
* @param data Pointer on code data.
|
||||
* @param limit Pointer on first byte outside the code data.
|
||||
*/
|
||||
/* TODO: Consider returning a new DOM everytime instead of having a global
|
||||
* one. */
|
||||
|
||||
void html_parse(const char *data, const char *limit)
|
||||
{
|
||||
// Parsing pointer.
|
||||
const char *ptr = data;
|
||||
// Element reference.
|
||||
reference_t ref;
|
||||
// Block type.
|
||||
enum block_t type = block_tag;
|
||||
|
||||
// Looping on elements until limit is reached.
|
||||
while(ptr < limit)
|
||||
{
|
||||
// Getting a reference on the next element.
|
||||
ref = html_next(ptr, limit, type);
|
||||
|
||||
// Updating main pointer.
|
||||
ptr = ref.end;
|
||||
|
||||
// Removing leading and ending spaces for tags.
|
||||
if(type == block_tag) ref = reftrim(ref);
|
||||
|
||||
// Generating an event.
|
||||
type = html_event(&ref, type);
|
||||
ptr = ref.end;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* html_args()
|
||||
*
|
||||
* Argument string interpreter. Meant to be used in several calls. A first
|
||||
* call as html_args(&ref,NULL) initializes the operation, and every
|
||||
* subsequent calls with two non-null pointers extracts an argument.
|
||||
*
|
||||
* @param name Reference pointer. Arguments at initialization, address
|
||||
* of argument name when extracting.
|
||||
* @param value Reference pointer. NULL at initialization, address of
|
||||
* argument value when extracting.
|
||||
*/
|
||||
|
||||
void html_args(reference_t *name, reference_t *value)
|
||||
{
|
||||
// Static reference for multiple calls.
|
||||
static reference_t args;
|
||||
// Parsing pointer.
|
||||
const char *ptr = args.begin;
|
||||
|
||||
// Initialization.
|
||||
if(name && !value)
|
||||
{
|
||||
// Actually, name is meant to be the full argument string.
|
||||
args = *name;
|
||||
// Immediatly returning.
|
||||
return;
|
||||
}
|
||||
|
||||
// Setting name. This code automatically handles empty names, etc.
|
||||
while(!isvalid(*ptr) && ptr < args.end) ptr++;
|
||||
name->begin = ptr;
|
||||
while(isvalid(*ptr) && ptr < args.end) ptr++;
|
||||
name->end = ptr;
|
||||
|
||||
// Skipping spaces before '=' symbol, if existing.
|
||||
while(isspace(*ptr) && ptr < args.end) ptr++;
|
||||
if(ptr == args.end || *ptr != '=')
|
||||
{
|
||||
value->begin = value->end = ptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// Skipping '='.
|
||||
ptr++;
|
||||
// Skipping spaces after '='.
|
||||
while(isspace(*ptr) && ptr < args.end) ptr++;
|
||||
if(ptr == args.end)
|
||||
{
|
||||
value->begin = value->end = ptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// Getting the value.
|
||||
if(*ptr == '"')
|
||||
{
|
||||
value->begin = ++ptr;
|
||||
while(*ptr != '"' && ptr < args.end) ptr++;
|
||||
value->end = ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!isvalid(*ptr) && ptr < args.end) ptr++;
|
||||
value->begin = ptr;
|
||||
while(isvalid(*ptr) && ptr < args.end) ptr++;
|
||||
value->end = ptr;
|
||||
}
|
||||
|
||||
args.begin = ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* html_clear()
|
||||
*
|
||||
* Clears the html module, that is, re-initializing all static pointers
|
||||
* and previously kept data to ensure interpretation safety.
|
||||
*/
|
||||
|
||||
void html_clear(void)
|
||||
{
|
||||
// Using a stack element structure, and a temporary one.
|
||||
struct el_t *el = top, *tmp;
|
||||
|
||||
// Clearing the stack.
|
||||
while(el)
|
||||
{
|
||||
tmp = el->down;
|
||||
free(el);
|
||||
el = tmp;
|
||||
}
|
||||
// Setting the top pointer.
|
||||
top = NULL;
|
||||
}
|
38
src/http.c
|
@ -15,6 +15,8 @@
|
|||
#include <usb.h>
|
||||
#include <log.h>
|
||||
|
||||
static const char *prev_url = NULL;
|
||||
|
||||
struct http_transfer {
|
||||
char *url;
|
||||
char *path;
|
||||
|
@ -129,6 +131,15 @@ void http_transfer_set_file(http_transfer_t *trans, char *file)
|
|||
|
||||
trans->request = utils_get_file(file, &trans->req_length);
|
||||
}
|
||||
hashmap_t * http_get_reply_json(http_transfer_t *trans)
|
||||
{
|
||||
if (!trans || !trans->completed)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return utils_json_parse(trans->reply, trans->rep_length);
|
||||
}
|
||||
|
||||
static void *buffer = NULL;
|
||||
static size_t size;
|
||||
|
@ -215,10 +226,19 @@ void http_transfer_send(http_transfer_t *t)
|
|||
while (true)
|
||||
{
|
||||
int code;
|
||||
usb_fxlink_fill_header(&head, "matrix", "url", strlen(t->url));
|
||||
usb_write_sync(out, &head, sizeof(usb_fxlink_header_t), false);
|
||||
usb_write_sync(out, t->url, strlen(t->url), false);
|
||||
usb_commit_sync(out);
|
||||
if (!prev_url || strcmp(t->url, prev_url))
|
||||
{
|
||||
usb_fxlink_fill_header(&head, "matrix", "url", strlen(t->url));
|
||||
usb_write_sync(out, &head, sizeof(usb_fxlink_header_t), false);
|
||||
usb_write_sync(out, t->url, strlen(t->url), false);
|
||||
usb_commit_sync(out);
|
||||
|
||||
if (prev_url)
|
||||
{
|
||||
free(prev_url);
|
||||
}
|
||||
prev_url = utils_strcpy(t->url);
|
||||
}
|
||||
|
||||
usb_fxlink_fill_header(&head, "matrix", "http", len);
|
||||
usb_write_sync(out, &head, sizeof(usb_fxlink_header_t), false);
|
||||
|
@ -329,12 +349,18 @@ void http_transfer_send(http_transfer_t *t)
|
|||
|
||||
int http_transfer_code(http_transfer_t *trans)
|
||||
{
|
||||
if (!trans || !trans->completed) return 0;
|
||||
if (!trans || !trans->completed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return trans->code;
|
||||
}
|
||||
char * http_get_reply_header(http_transfer_t *trans, char *key)
|
||||
{
|
||||
if (!trans) return NULL;
|
||||
if (!trans)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return utils_hashmap_get(trans->rep_header, key);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
#include <libimg.h>
|
||||
|
||||
#include <utils.h>
|
||||
#include <log.h>
|
||||
|
||||
img_t utils_downscale(img_t img, int scale)
|
||||
{
|
||||
int dw = img.width / scale;
|
||||
int dh = img.height / scale;
|
||||
int x, y;
|
||||
img_t ret = img_create(dw, dh);
|
||||
|
||||
for (y = 0; y < dh; y++)
|
||||
{
|
||||
for (x = 0; x < dw; x++)
|
||||
{
|
||||
int ox, oy;
|
||||
|
||||
ox = x * scale;
|
||||
oy = y * scale;
|
||||
ret.pixels[y * ret.stride + x] = img.pixels[oy * img.stride + ox];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
img_t load_png(char *buf, size_t len)
|
||||
{
|
||||
img_t img;
|
||||
int w, h, ch, x, y;
|
||||
const stbi_uc *stbi = stbi_load_from_memory((const stbi_uc *) buf, len, &w, &h, &ch, 4);
|
||||
if (!stbi)
|
||||
{
|
||||
return img_create(65536, 65536);
|
||||
}
|
||||
|
||||
if (ch != 3 && ch != 4)
|
||||
{
|
||||
return img_create(65536, 65536);
|
||||
}
|
||||
|
||||
img = img_create(w, h);
|
||||
img_clear(img);
|
||||
for (y = 0; y < h; y++)
|
||||
{
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
const unsigned char *rgbi = &stbi[(y * w + x) * 4];
|
||||
uint8_t r = rgbi[0];
|
||||
uint8_t g = rgbi[1];
|
||||
uint8_t b = rgbi[2];
|
||||
uint8_t a = ch == 4 ? rgbi[3] : 255;
|
||||
|
||||
img.pixels[img.stride * y + x] = 0x0001;
|
||||
if (a >= 0x80)
|
||||
{
|
||||
img.pixels[img.stride * y + x] = C_RGB(r >> 3, g >> 3, b >> 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
stbi_image_free((void *) stbi);
|
||||
return img;
|
||||
}
|
|
@ -1,251 +0,0 @@
|
|||
#ifndef _DOM_H
|
||||
#define _DOM_H
|
||||
|
||||
/*
|
||||
Header inclusions.
|
||||
*/
|
||||
|
||||
#include <stdref.h>
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Type declarations.
|
||||
*/
|
||||
|
||||
// Just lightening following declarations.
|
||||
#ifndef _UINT
|
||||
#define _UINT
|
||||
typedef unsigned uint;
|
||||
#endif // _UINT
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Composed type definitions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DomStyle
|
||||
*
|
||||
* This structure handles everything that has to do with styling.
|
||||
* Comments represent the possible values for the property, in order of
|
||||
* values. When there is no comment, then the corresponding property is
|
||||
* associated a numeric value or pointer.
|
||||
*
|
||||
* TODO
|
||||
* - Define DomStyle as an union so that simple tags do not carry
|
||||
* useless style information.
|
||||
* - Use a 12-bit bit field for border parameters handling.
|
||||
*/
|
||||
|
||||
struct DomStyle
|
||||
{
|
||||
|
||||
/* TODO: Allow arbitrary colors(this is an fx-**CG**50, damnit!) */
|
||||
uint background :1; // white, black
|
||||
uint color :1; // white, black
|
||||
|
||||
uint overflowX :2; // visible, hidden, scroll, auto
|
||||
uint overflowY :2; // visible, hidden, scroll, auto
|
||||
uint resize :2; // none, horizontal, vertical, both
|
||||
|
||||
uint display :2; // none, inline, block, inline-block
|
||||
uint position :2; // static, absolute, fixed, relative
|
||||
uint cssFloat :2; // none, left, right
|
||||
uint verticalAlign :2; // top, middle, bottom
|
||||
|
||||
uint top :12;
|
||||
uint right :12;
|
||||
uint bottom :12;
|
||||
uint left :12;
|
||||
|
||||
uint width :12;
|
||||
uint minWidth :12;
|
||||
uint maxWidth :12;
|
||||
uint height :12;
|
||||
uint minHeight :12;
|
||||
uint maxHeight :12;
|
||||
|
||||
uint paddingTop :8;
|
||||
uint paddingRight :8;
|
||||
uint paddingBottom :8;
|
||||
uint paddingLeft :8;
|
||||
|
||||
uint borderTop :8;
|
||||
uint borderRight :8;
|
||||
uint borderBottom :8;
|
||||
uint borderLeft :8;
|
||||
uint borderRadius :8;
|
||||
|
||||
uint marginTop :8;
|
||||
uint marginRight :8;
|
||||
uint marginBottom :8;
|
||||
uint marginLeft :8;
|
||||
|
||||
uint borderSpacingX :8;
|
||||
uint borderSpacingY :8;
|
||||
|
||||
uint fontSize :8;
|
||||
int letterSpacing :8;
|
||||
uint lineHeight :8;
|
||||
int textIndent :8;
|
||||
|
||||
uint cursor :3; // crosshair, default, help, move,
|
||||
// none, pointer, progress, text
|
||||
uint visibility :1; // hidden, visible
|
||||
uint listStyle :4; // 1 01 a A i I x o . - --
|
||||
|
||||
uint textAlign :2; // left, center, right, justify
|
||||
uint textDecoration :2; // none, underline, overline,
|
||||
// line-trough
|
||||
uint whiteSpace :2; // normal (wrap), nowrap, pre, pre-wrap
|
||||
uint borderCollapse :1; // separate, collapse
|
||||
uint emptyCells :1; // show, hide
|
||||
|
||||
uint tabSize :4;
|
||||
uint wordSpacing :4;
|
||||
|
||||
/*
|
||||
Other elements.
|
||||
|
||||
char *backgroundImage;
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* DomAttribute
|
||||
*
|
||||
* This simple structure stores the content of a tag attribute, by name
|
||||
* and value.
|
||||
*/
|
||||
|
||||
struct DomAttribute
|
||||
{
|
||||
char *name;
|
||||
char *value;
|
||||
};
|
||||
|
||||
/**
|
||||
* DomElement
|
||||
*
|
||||
* This structure represents a node in the DOM element tree. This is the
|
||||
* mainly manipulated structure in the interpreter.
|
||||
*/
|
||||
|
||||
struct DomElement
|
||||
{
|
||||
/*
|
||||
Basic element properties.
|
||||
*/
|
||||
|
||||
// NUL-terminated tag name (dynamically allocated).
|
||||
char *tagName;
|
||||
// Style structure pointer (dynamically allocated).
|
||||
struct DomStyle *style;
|
||||
// Node data.
|
||||
union
|
||||
{
|
||||
// Text content, dynamically allocated.
|
||||
char *textNode;
|
||||
// Loaded Tex expression (the code is not saved).
|
||||
/*struct Tex_Expression *tex;*/
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Children and attributes.
|
||||
*/
|
||||
|
||||
// Children and attribute pointer arrays.
|
||||
struct DomElement **children;
|
||||
struct DomAttribute **attributes;
|
||||
|
||||
// Children and attribute numbers counters.
|
||||
uint attrnum :8;
|
||||
uint childnum :8;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Relations.
|
||||
*/
|
||||
|
||||
// Parent node.
|
||||
struct DomElement *parent;
|
||||
// Previous sibling.
|
||||
struct DomElement *previous;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Possible useful data for later.
|
||||
|
||||
unsigned short accessKey;
|
||||
|
||||
uint scrollWidth :12;
|
||||
uint scrollHeight :12;
|
||||
uint scrollTop :12;
|
||||
uint scrollLeft :12;
|
||||
*/
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct DomElement *html;
|
||||
uint width :8;
|
||||
uint height :8;
|
||||
|
||||
const char *directory;
|
||||
const char *stylesheets[10];
|
||||
int stylesheet :8;
|
||||
} Window;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Some useful information... (WH = Width/Height, TL = Top/Left)
|
||||
clientWH = inner + padding - scrollbars.
|
||||
offsetWH = inner + padding + border.
|
||||
offsetTL = coords + margin.
|
||||
scrollWH = overflow + padding - scrollbars.
|
||||
scrollTL = scrollbars offset.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Function prototypes.
|
||||
*/
|
||||
|
||||
// DomStyle manipulation functions.
|
||||
struct DomStyle *DomStyle_new(void);
|
||||
|
||||
// DomAttribute manipulation functions.
|
||||
struct DomAttribute *DomAttribute_new(reference_t name, reference_t value);
|
||||
void DomAttribute_free(struct DomAttribute *attribute);
|
||||
|
||||
// DomElement manipulation functions.
|
||||
struct DomElement *DomElement_new(reference_t name, reference_t args,
|
||||
struct DomElement *parent, struct DomElement *previous);
|
||||
void DomElement_free(struct DomElement *element);
|
||||
struct DomElement *DomElement_addChild(struct DomElement *element,
|
||||
struct DomElement *child);
|
||||
struct DomElement *DomElement_getChild(struct DomElement *element, int index);
|
||||
void DomElement_setTextNode(struct DomElement *element, reference_t text);
|
||||
const char *DomElement_getAttribute(struct DomElement *element,
|
||||
const char *attribute_name);
|
||||
/*void DomElement_resolve(struct DomElement *element);*/
|
||||
|
||||
int DomElement_get(struct DomElement *element, int value);
|
||||
|
||||
// Non-recursive tree parser.
|
||||
struct DomElement *Dom_parse(int initialize);
|
||||
|
||||
#define DOMElement_totalWidth(e) DomElement_get(e,1)
|
||||
#define DOMElement_totalHeight(e) DomElement_get(e,2)
|
||||
#define DOMElement_tokenWidth(e) DomElement_get(e,3)
|
||||
#define DOMElement_tokenHeight(e) DomElement_get(e,4)
|
||||
|
||||
#endif // _DOM_H
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef _WEBCALC_H
|
||||
#define _WEBCALC_H
|
||||
|
||||
// Some headers.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
/*#include "fxlib.h"*/
|
||||
|
||||
// Limiting constants definition.
|
||||
#define CHILD_NUM 20
|
||||
#define ATTRS_NUM 5
|
||||
|
||||
// Project headers.
|
||||
/*#include "memory.h"
|
||||
#include "libfont-3.1.h"
|
||||
#include "tex-0.9.h"*/
|
||||
#include "DOM.h"
|
||||
|
||||
/*#include <display.h>*/
|
||||
#include <stdref.h>
|
||||
|
||||
// Element structure definition.
|
||||
struct el_t
|
||||
{
|
||||
// Opening tag name reference (closing tag carries no info).
|
||||
reference_t name;
|
||||
// Tag arguments.
|
||||
reference_t args;
|
||||
// Text content, if needed.
|
||||
reference_t text;
|
||||
// Associated element.
|
||||
struct DomElement *dom;
|
||||
// Linked stack pointer.
|
||||
struct el_t *down;
|
||||
};
|
||||
|
||||
char *itoa(int n, char *str, int base);
|
||||
|
||||
// HTML module functions.
|
||||
void html_parse(const char *code, const char *end);
|
||||
void html_args(reference_t *name_or_string, reference_t *value);
|
||||
struct el_t *html_elem(void);
|
||||
void html_clear(void);
|
||||
|
||||
// CSS module functions.
|
||||
void css_parse_all(void);
|
||||
void css_parse(const char *stylesheet_data);
|
||||
void css_target(reference_t selector, reference_t property, reference_t value);
|
||||
int css_matches(struct DomElement *element, reference_t target);
|
||||
void css_apply(struct DomElement *element, reference_t property, reference_t value);
|
||||
int css_index(reference_t value, int strings, ...);
|
||||
|
||||
#endif // _WEBCALC_H
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef MATRIX_DOM_H
|
||||
#define MATRIX_DOM_H
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
typedef struct html_elem {
|
||||
char *name;
|
||||
hashmap_t *attrs;
|
||||
|
||||
struct html_elem *parent; /* NULL if non-existent */
|
||||
|
||||
bool has_text;
|
||||
union {
|
||||
/* Determined by has_text */
|
||||
array_t *elems;
|
||||
char *text;
|
||||
} children;
|
||||
} html_elem_t;
|
||||
|
||||
extern html_elem_t *dom_parse_element(char *);
|
||||
extern void dom_free_element(html_elem_t *);
|
||||
|
||||
#endif
|
|
@ -3,5 +3,9 @@
|
|||
|
||||
extern void easter_goda(void);
|
||||
extern void easter_dvd_frame(const char *);
|
||||
extern void easter_strongest(void);
|
||||
|
||||
/* This one's a fool's errand. */
|
||||
extern void easter_credit(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,6 +27,7 @@ extern void http_transfer_send(http_transfer_t *);
|
|||
extern int http_transfer_code(http_transfer_t *);
|
||||
extern char * http_get_reply_header(http_transfer_t *, char *);
|
||||
extern void * http_get_reply_data(http_transfer_t *, size_t *);
|
||||
extern hashmap_t * http_get_reply_json(http_transfer_t *);
|
||||
|
||||
extern void http_transfer_free(http_transfer_t *);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <utils.h>
|
||||
#include <http.h>
|
||||
|
||||
|
||||
typedef enum m_delegation {
|
||||
/* Terms used in 3. Server Discovery */
|
||||
DELEG_PROMPT,
|
||||
|
@ -32,6 +33,7 @@ typedef struct m_event {
|
|||
|
||||
char *state_key;
|
||||
|
||||
bool redacted;
|
||||
/* TODO: Unsigned data */
|
||||
} m_event_t;
|
||||
typedef struct m_room {
|
||||
|
@ -40,6 +42,7 @@ typedef struct m_room {
|
|||
size_t joined;
|
||||
|
||||
array_t *timeline;
|
||||
hashmap_t *relations;
|
||||
|
||||
hashmap_t *nicks;
|
||||
} m_room_t;
|
||||
|
@ -53,7 +56,21 @@ typedef struct m_user {
|
|||
|
||||
char *sync_next;
|
||||
hashmap_t *rooms;
|
||||
hashmap_t *images;
|
||||
hashmap_t *mxcs;
|
||||
} m_user_t;
|
||||
typedef struct m_room_chunk {
|
||||
char *avatar_url;
|
||||
char *canonical_alias;
|
||||
bool guest_can_join;
|
||||
char *join_rule;
|
||||
char *name;
|
||||
int num_joined_members;
|
||||
char *room_id;
|
||||
char *room_type;
|
||||
char *topic;
|
||||
bool world_readable;
|
||||
} m_room_chunk_t;
|
||||
|
||||
/* Tries to find a delegation point with well-known */
|
||||
extern m_delegation_t matrix_delegate(char *, char **);
|
||||
|
@ -64,6 +81,12 @@ extern bool matrix_supports_password(char *);
|
|||
/* Tries to login to a specific server with a password*/
|
||||
extern m_user_t *matrix_login(char *, char *, char *);
|
||||
|
||||
/* Saves a user into Flash memory */
|
||||
extern void matrix_save(m_user_t *);
|
||||
extern m_user_t * matrix_load(void);
|
||||
|
||||
extern void matrix_logout(m_user_t *);
|
||||
|
||||
/* Attempts a *basic* initial sync request to get the barebone
|
||||
* information. */
|
||||
extern void matrix_initial_sync(m_user_t *);
|
||||
|
@ -72,17 +95,24 @@ extern void matrix_initial_sync(m_user_t *);
|
|||
* mind you!) */
|
||||
extern m_event_t *matrix_parse_event(hashmap_t *, bool);
|
||||
|
||||
/* Retrieves an event from the server given its ID */
|
||||
extern hashmap_t *matrix_event_to_json(m_user_t *, m_event_t *);
|
||||
|
||||
/* Frees data associated with the event. */
|
||||
extern void matrix_free_event(m_event_t *);
|
||||
|
||||
/* Fetch a (state_type,state_key) pair for the room */
|
||||
extern hashmap_t *matrix_state_fetch(m_user_t *, m_room_t *, char *, char *);
|
||||
|
||||
/* Sets a state element in the room if possible. */
|
||||
extern bool matrix_state_set(m_user_t *, m_room_t *, char *, char *, hashmap_t *);
|
||||
|
||||
/* Finds the room's actual name from its state.
|
||||
*
|
||||
* Please mind that it is stored on the heap, and as such, needs to be freed.
|
||||
*/
|
||||
extern char *matrix_resolve_name(m_user_t *, m_room_t *);
|
||||
extern char *matrix_resolve_avatar(m_user_t *, m_room_t *);
|
||||
|
||||
extern char *matrix_resolve_topic(m_user_t *, m_room_t *);
|
||||
|
||||
|
@ -90,6 +120,16 @@ extern char *matrix_resolve_topic(m_user_t *, m_room_t *);
|
|||
*/
|
||||
extern char *matrix_resolve_nick(m_user_t *, char *, m_room_t *);
|
||||
|
||||
/* Sets a user's global displayname */
|
||||
extern void matrix_set_displayname(m_user_t *, char *);
|
||||
|
||||
/* Gets a user's global displayname */
|
||||
extern char * matrix_get_displayname(m_user_t *);
|
||||
extern char * matrix_get_avatar(m_user_t *);
|
||||
|
||||
/* Gets a user's local avatar */
|
||||
extern char * matrix_get_lavatar(m_user_t *, char *);
|
||||
|
||||
/* Attaches a token to a HTTP transfer*/
|
||||
extern void matrix_set_token(http_transfer_t *, m_user_t *);
|
||||
|
||||
|
@ -101,6 +141,8 @@ extern uint16_t matrix_hash(char *);
|
|||
*
|
||||
* Returns true if anything has changed. */
|
||||
extern bool matrix_update_room_history(m_user_t *, m_room_t *, m_event_t *e, int);
|
||||
/* Uses /messages to start populating a timeline from scratch */
|
||||
extern void matrix_populate_messages(m_user_t *, m_room_t *, int);
|
||||
|
||||
extern ssize_t is_in_timeline(m_room_t *, char *);
|
||||
|
||||
|
@ -108,8 +150,32 @@ extern ssize_t is_in_timeline(m_room_t *, char *);
|
|||
extern void matrix_send_event(m_user_t *, m_room_t *, char *, hashmap_t *);
|
||||
|
||||
extern void matrix_show_event(m_room_t *, m_user_t *, m_event_t *, jwidget *);
|
||||
extern void matrix_redact(m_user_t *, m_event_t *, char *);
|
||||
|
||||
|
||||
extern char *matrix_send_file(m_user_t *, char *, char *);
|
||||
extern char *matrix_get_file(m_user_t *, char *, size_t *);
|
||||
|
||||
/* Get public rooms in a server's directory(defaults to the user's) */
|
||||
extern array_t *matrix_get_directory(m_user_t *, char *, int);
|
||||
extern void matrix_free_directory(array_t *);
|
||||
extern bool matrix_set_nick(m_user_t *, m_room_t *, char *);
|
||||
|
||||
extern char *matrix_get_mxc_avatar(m_user_t *, char *, size_t *, int);
|
||||
extern void *matrix_image_from_mxc(void *, m_user_t *, char *, int);
|
||||
extern void *matrix_image_from_user(void *, m_user_t *, char *);
|
||||
extern void *matrix_image_from_room_user(void *,m_user_t *,m_room_t *,char *);
|
||||
|
||||
/* Fetches the public room list for a server(and stores/loads a batch) */
|
||||
extern array_t *matrix_fetch_roomdir(m_user_t *, int, char *, char **);
|
||||
|
||||
/* Joins a room with a given room ID */
|
||||
extern m_room_t * matrix_join_room(m_user_t *, char *);
|
||||
|
||||
|
||||
extern char *matrix_get_relation_source(m_event_t *);
|
||||
extern char *matrix_get_relation_type(m_event_t *);
|
||||
extern json_value_t *matrix_get_relation_property(m_event_t *, char *);
|
||||
extern void matrix_add_relation(char *, m_room_t *, m_event_t *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
#ifndef _STDREF_H
|
||||
#define _STDREF_H 1
|
||||
|
||||
/*
|
||||
Header inclusions.
|
||||
*/
|
||||
|
||||
/* We actually *do* have those! */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
/*#include "fxlib.h"*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Composed types definitions.
|
||||
*/
|
||||
|
||||
// reference_t structure definition.
|
||||
typedef struct
|
||||
{
|
||||
// Beginning of referenced area. Included.
|
||||
const char *begin;
|
||||
// End of referenced area. Excluded.
|
||||
const char *end;
|
||||
} reference_t;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Function prototypes.
|
||||
*/
|
||||
|
||||
// Tests if a reference is invalid or null.
|
||||
int refnull(reference_t ref);
|
||||
// Extracts the referenced text in an allocated pointer.
|
||||
char *refxtrct(reference_t ref);
|
||||
// Unreferences the spaces at the beginning and end of the referenced area.
|
||||
reference_t reftrim(reference_t ref);
|
||||
// Compares a reference and a string.
|
||||
int refscmp(reference_t ref, const char *str);
|
||||
// Compares a reference and a string, in the limit of `length` characters.
|
||||
int refsncmp(reference_t ref, const char *str, int length);
|
||||
|
||||
#endif // _STDREF_H
|
|
@ -2,6 +2,7 @@
|
|||
#define MATRIX_UI_H
|
||||
|
||||
#include <utils.h>
|
||||
#include <matrix.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
@ -10,9 +11,7 @@
|
|||
#include <justui/jfkeys.h>
|
||||
#include <justui/jframe.h>
|
||||
|
||||
#include <gint/display.h>
|
||||
|
||||
#include <matrix.h>
|
||||
#include <libimg.h>
|
||||
|
||||
|
||||
/* A value, with a function to free said value */
|
||||
|
@ -40,6 +39,8 @@ typedef struct ui_session {
|
|||
/* Public data for everyone! */
|
||||
m_user_t *user;
|
||||
m_room_t *room;
|
||||
bool rooms_dirty;
|
||||
char *new_id;
|
||||
} ui_session_t;
|
||||
|
||||
struct ui_screen;
|
||||
|
@ -102,6 +103,7 @@ typedef struct jmlist {
|
|||
jrect rect;
|
||||
} jmlist;
|
||||
|
||||
extern uint16_t JMLIST_ITEM_OVERFLEW;
|
||||
extern uint16_t JMLIST_ITEM_CHOSEN;
|
||||
extern uint16_t JMLIST_ITEM_CHANGE;
|
||||
extern uint16_t JMLIST_ITEM_ADDED;
|
||||
|
@ -114,8 +116,15 @@ 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 void jmlist_redo(jmlist *, int);
|
||||
|
||||
typedef struct jmimage {
|
||||
jwidget widget;
|
||||
|
||||
img_t img;
|
||||
} jmimage;
|
||||
|
||||
extern jmimage *jmimage_create(void *, img_t);
|
||||
extern jpainted *ui_image(void *, const bopti_image_t *);
|
||||
extern jpainted *ui_blurhash(void *, char *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,7 +16,14 @@ extern void * ui_rooms_init(ui_screen_t *that);
|
|||
extern void * ui_rooms_focus(ui_screen_t *that);
|
||||
extern void * ui_rooms_event(ui_screen_t *that, jevent e);
|
||||
|
||||
|
||||
extern void * ui_room_init(ui_screen_t *that);
|
||||
extern void * ui_room_event(ui_screen_t *that, jevent e);
|
||||
|
||||
|
||||
extern void * ui_roomdir_init(ui_screen_t *that);
|
||||
extern void * ui_roomdir_event(ui_screen_t *that, jevent e);
|
||||
|
||||
extern void * ui_accinfo_init(ui_screen_t *that);
|
||||
extern void * ui_accinfo_focus(ui_screen_t *that);
|
||||
extern void * ui_accinfo_event(ui_screen_t *that, jevent e);
|
||||
#endif
|
||||
|
|
|
@ -1,18 +1,39 @@
|
|||
#ifndef MATRIX_UTILS_H
|
||||
#define MATRIX_UTILS_H
|
||||
|
||||
#include <libimg.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define B * 1
|
||||
#define KB * (1024 B)
|
||||
#define MB * (1024 KB)
|
||||
|
||||
|
||||
/* Copies a string into a new heap-allocated string */
|
||||
extern char * utils_strcpy(char *);
|
||||
extern char * utils_strcat(char *, char *);
|
||||
extern char * utils_itoa(int i);
|
||||
extern char * utils_basename(char *);
|
||||
extern int utils_htov(char c);
|
||||
extern char * utils_unitoutf(uint16_t);
|
||||
extern char * utils_sprintf(char *, ...);
|
||||
|
||||
/* Creates a fd/FILE * that maps to memory */
|
||||
extern int utils_openmem(void *, size_t);
|
||||
extern FILE *utils_fopenmem(void *, size_t);
|
||||
|
||||
extern char * utils_get_file(char *, size_t *);
|
||||
extern void utils_write_file(char *, char *, size_t);
|
||||
extern void utils_delete_file(char *);
|
||||
|
||||
extern uint32_t utils_total_mem(void);
|
||||
extern uint32_t utils_used_mem(void);
|
||||
|
||||
extern img_t load_png(char *buf, size_t len);
|
||||
extern img_t utils_downscale(img_t, int);
|
||||
|
||||
typedef struct hashmap hashmap_t;
|
||||
|
||||
|
@ -30,6 +51,7 @@ typedef struct array array_t;
|
|||
extern array_t * utils_new_array(void);
|
||||
extern size_t utils_array_add(array_t *, void *);
|
||||
extern void utils_array_shift(array_t *, size_t);
|
||||
extern void utils_array_invert(array_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 *);
|
||||
|
@ -47,7 +69,7 @@ typedef enum json_value_type {
|
|||
} json_value_type_t;
|
||||
|
||||
extern hashmap_t * utils_json_parse(char *, size_t);
|
||||
extern char * utils_json_write(hashmap_t *, size_t *);
|
||||
extern char * utils_json_write (hashmap_t *, size_t *);
|
||||
extern json_value_type_t utils_json_value_type(json_value_t *);
|
||||
extern void utils_free_json_value(json_value_t *);
|
||||
extern void utils_free_json(hashmap_t *);
|
||||
|
@ -66,6 +88,4 @@ 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
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
/* Copyright (c) 2013-2014 Yoran Heling
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef YXML_H
|
||||
#define YXML_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__cplusplus) && !defined(inline)
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
/* Full API documentation for this library can be found in the "yxml.md" file
|
||||
* in the yxml git repository, or online at http://dev.yorhel.nl/yxml/man */
|
||||
|
||||
typedef enum {
|
||||
YXML_EEOF = -5, /* Unexpected EOF */
|
||||
YXML_EREF = -4, /* Invalid character or entity reference (&whatever;) */
|
||||
YXML_ECLOSE = -3, /* Close tag does not match open tag (<Tag> .. </OtherTag>) */
|
||||
YXML_ESTACK = -2, /* Stack overflow (too deeply nested tags or too long element/attribute name) */
|
||||
YXML_ESYN = -1, /* Syntax error (unexpected byte) */
|
||||
YXML_OK = 0, /* Character consumed, no new token present */
|
||||
YXML_ELEMSTART = 1, /* Start of an element: '<Tag ..' */
|
||||
YXML_CONTENT = 2, /* Element content */
|
||||
YXML_ELEMEND = 3, /* End of an element: '.. />' or '</Tag>' */
|
||||
YXML_ATTRSTART = 4, /* Attribute: 'Name=..' */
|
||||
YXML_ATTRVAL = 5, /* Attribute value */
|
||||
YXML_ATTREND = 6, /* End of attribute '.."' */
|
||||
YXML_PISTART = 7, /* Start of a processing instruction */
|
||||
YXML_PICONTENT = 8, /* Content of a PI */
|
||||
YXML_PIEND = 9 /* End of a processing instruction */
|
||||
} yxml_ret_t;
|
||||
|
||||
/* When, exactly, are tokens returned?
|
||||
*
|
||||
* <TagName
|
||||
* '>' ELEMSTART
|
||||
* '/' ELEMSTART, '>' ELEMEND
|
||||
* ' ' ELEMSTART
|
||||
* '>'
|
||||
* '/', '>' ELEMEND
|
||||
* Attr
|
||||
* '=' ATTRSTART
|
||||
* "X ATTRVAL
|
||||
* 'Y' ATTRVAL
|
||||
* 'Z' ATTRVAL
|
||||
* '"' ATTREND
|
||||
* '>'
|
||||
* '/', '>' ELEMEND
|
||||
*
|
||||
* </TagName
|
||||
* '>' ELEMEND
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* PUBLIC (read-only) */
|
||||
|
||||
/* Name of the current element, zero-length if not in any element. Changed
|
||||
* after YXML_ELEMSTART. The pointer will remain valid up to and including
|
||||
* the next non-YXML_ATTR* token, the pointed-to buffer will remain valid
|
||||
* up to and including the YXML_ELEMEND for the corresponding element. */
|
||||
char *elem;
|
||||
|
||||
/* The last read character(s) of an attribute value (YXML_ATTRVAL), element
|
||||
* data (YXML_CONTENT), or processing instruction (YXML_PICONTENT). Changed
|
||||
* after one of the respective YXML_ values is returned, and only valid
|
||||
* until the next yxml_parse() call. Usually, this string only consists of
|
||||
* a single byte, but multiple bytes are returned in the following cases:
|
||||
* - "<?SomePI ?x ?>": The two characters "?x"
|
||||
* - "<![CDATA[ ]x ]]>": The two characters "]x"
|
||||
* - "<![CDATA[ ]]x ]]>": The three characters "]]x"
|
||||
* - "&#N;" and "&#xN;", where dec(n) > 127. The referenced Unicode
|
||||
* character is then encoded in multiple UTF-8 bytes.
|
||||
*/
|
||||
char data[8];
|
||||
|
||||
/* Name of the current attribute. Changed after YXML_ATTRSTART, valid up to
|
||||
* and including the next YXML_ATTREND. */
|
||||
char *attr;
|
||||
|
||||
/* Name/target of the current processing instruction, zero-length if not in
|
||||
* a PI. Changed after YXML_PISTART, valid up to (but excluding)
|
||||
* the next YXML_PIEND. */
|
||||
char *pi;
|
||||
|
||||
/* Line number, byte offset within that line, and total bytes read. These
|
||||
* values refer to the position _after_ the last byte given to
|
||||
* yxml_parse(). These are useful for debugging and error reporting. */
|
||||
uint64_t byte;
|
||||
uint64_t total;
|
||||
uint32_t line;
|
||||
|
||||
|
||||
/* PRIVATE */
|
||||
int state;
|
||||
unsigned char *stack; /* Stack of element names + attribute/PI name, separated by \0. Also starts with a \0. */
|
||||
size_t stacksize, stacklen;
|
||||
unsigned reflen;
|
||||
unsigned quote;
|
||||
int nextstate; /* Used for '@' state remembering and for the "string" consuming state */
|
||||
unsigned ignore;
|
||||
unsigned char *string;
|
||||
} yxml_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void yxml_init(yxml_t *, void *, size_t);
|
||||
|
||||
|
||||
yxml_ret_t yxml_parse(yxml_t *, int);
|
||||
|
||||
|
||||
/* May be called after the last character has been given to yxml_parse().
|
||||
* Returns YXML_OK if the XML document is valid, YXML_EEOF otherwise. Using
|
||||
* this function isn't really necessary, but can be used to detect documents
|
||||
* that don't end correctly. In particular, an error is returned when the XML
|
||||
* document did not contain a (complete) root element, or when the document
|
||||
* ended while in a comment or processing instruction. */
|
||||
yxml_ret_t yxml_eof(yxml_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Returns the length of the element name (x->elem), attribute name (x->attr),
|
||||
* or PI name (x->pi). This function should ONLY be used directly after the
|
||||
* YXML_ELEMSTART, YXML_ATTRSTART or YXML_PISTART (respectively) tokens have
|
||||
* been returned by yxml_parse(), calling this at any other time may not give
|
||||
* the correct results. This function should also NOT be used on strings other
|
||||
* than x->elem, x->attr or x->pi. */
|
||||
static inline size_t yxml_symlen(yxml_t *x, const char *s) {
|
||||
return (x->stack + x->stacklen) - (const unsigned char*)s;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* vim: set noet sw=4 ts=4: */
|
|
@ -0,0 +1,73 @@
|
|||
#include <ui.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <log.h>
|
||||
|
||||
static int jmimage_type_id = -1;
|
||||
|
||||
jmimage *jmimage_create(void *parent, img_t img)
|
||||
{
|
||||
jmimage *image;
|
||||
|
||||
if (jmimage_type_id < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image = malloc(sizeof(jmimage));
|
||||
jwidget_init(&image->widget, jmimage_type_id, parent);
|
||||
jwidget_set_fixed_size(image, img.width, img.height);
|
||||
jwidget_set_clipped(image, true);
|
||||
image->img = img;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
static void jmimage_poly_render(void *i, int x, int y)
|
||||
{
|
||||
jmimage *image = i;
|
||||
|
||||
int px, py;
|
||||
|
||||
for (py = 0; py < image->img.height; py++)
|
||||
{
|
||||
for (px = 0; px < image->img.width; px++)
|
||||
{
|
||||
int X = px + x;
|
||||
int Y = py + y;
|
||||
unsigned int pxl = image->img.pixels[image->img.stride * py + px];
|
||||
if (pxl != 0x0001)
|
||||
{
|
||||
dpixel(X, Y, pxl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static void jmimage_poly_csize(void *i)
|
||||
{
|
||||
jmimage *image = i;
|
||||
image->widget.w = image->img.width;
|
||||
image->widget.h = image->img.height;
|
||||
}
|
||||
|
||||
static void jmimage_poly_destroy(void *i)
|
||||
{
|
||||
jmimage *image = i;
|
||||
|
||||
/*img_destroy(image->img);*/
|
||||
(void) image; /* TODO: Delete if flag is set */
|
||||
}
|
||||
static jwidget_poly type_jmimage = {
|
||||
.name = "jmlist",
|
||||
.csize = jmimage_poly_csize,
|
||||
.render = jmimage_poly_render,
|
||||
.event = NULL,
|
||||
.destroy = jmimage_poly_destroy,
|
||||
};
|
||||
|
||||
__attribute__((constructor(2001)))
|
||||
static void j_register_jmimage(void)
|
||||
{
|
||||
jmimage_type_id = j_register_widget(&type_jmimage, "jwidget");
|
||||
}
|
67
src/jmlist.c
|
@ -6,10 +6,10 @@
|
|||
#include <justui/jwidget-api.h>
|
||||
|
||||
#include <utils.h>
|
||||
#include <log.h>
|
||||
|
||||
static int jmlist_type_id = -1;
|
||||
|
||||
uint16_t JMLIST_ITEM_OVERFLEW;
|
||||
uint16_t JMLIST_ITEM_CHOSEN;
|
||||
uint16_t JMLIST_ITEM_CHANGE;
|
||||
uint16_t JMLIST_ITEM_ADDED;
|
||||
|
@ -33,15 +33,14 @@ 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);
|
||||
jwidget_set_fixed_width(list->box, DWIDTH);
|
||||
jframe_set_align(list->frame, J_ALIGN_LEFT, J_ALIGN_TOP);
|
||||
|
||||
list->arr = utils_new_array();
|
||||
list->selected = -1;
|
||||
list->set = set;
|
||||
list->end = f;
|
||||
|
||||
jframe_set_align(list->frame, J_ALIGN_LEFT, J_ALIGN_TOP);
|
||||
|
||||
jwidget_set_stretch(list->frame, 1, 1, false);
|
||||
jwidget_set_stretch(list->box, 1, 1, false);
|
||||
|
||||
|
@ -93,7 +92,6 @@ int jmlist_prepend_item(jmlist *list, void *data)
|
|||
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 });
|
||||
|
||||
|
@ -102,7 +100,6 @@ int jmlist_prepend_item(jmlist *list, void *data)
|
|||
int jmlist_select(jmlist *list, int idx)
|
||||
{
|
||||
jmlist_item *item;
|
||||
size_t oidx;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
|
@ -114,11 +111,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))
|
||||
if ((size_t) idx >= utils_array_size(list->arr))
|
||||
{
|
||||
idx = utils_array_size(list->arr) - 1;
|
||||
}
|
||||
|
@ -127,47 +122,43 @@ 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,
|
||||
(jrect){
|
||||
.x = list->offset_x,
|
||||
.x = list->frame->scroll_x,
|
||||
.y = (item->widget->y + list->box->y) - list->frame->widget.y,
|
||||
.w = jwidget_content_width(item->widget),
|
||||
.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;
|
||||
}
|
||||
extern bool jmlist_scroll(jmlist *list, jrect rect)
|
||||
{
|
||||
int16_t oldscroll;
|
||||
if (!list)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
oldscroll = list->frame->scroll_x;
|
||||
jframe_scroll_to_region(
|
||||
list->frame,
|
||||
rect,
|
||||
false
|
||||
);
|
||||
list->frame->scroll_x = oldscroll;
|
||||
list->rect = rect;
|
||||
list->widget.dirty = 1;
|
||||
return true;
|
||||
|
@ -177,10 +168,6 @@ extern bool jmlist_scroll(jmlist *list, jrect rect)
|
|||
static bool jmlist_poly_event(void *ml0, jevent e)
|
||||
{
|
||||
jmlist *list = ml0;
|
||||
|
||||
|
||||
jevent ret;
|
||||
|
||||
int key;
|
||||
|
||||
if (e.type != JWIDGET_KEY || list->selected < 0)
|
||||
|
@ -193,19 +180,30 @@ static bool jmlist_poly_event(void *ml0, jevent e)
|
|||
{
|
||||
case KEY_UP:
|
||||
if (e.key.type == KEYEV_HOLD) return false;
|
||||
if (jmlist_selected(list) <= 0)
|
||||
{
|
||||
jwidget_emit(list, (jevent){ .type = JMLIST_ITEM_OVERFLEW });
|
||||
return true;
|
||||
}
|
||||
jmlist_select(list, jmlist_selected(list) - 1);
|
||||
return true;
|
||||
case KEY_DOWN:
|
||||
if (e.key.type == KEYEV_HOLD) return false;
|
||||
if (jmlist_selected(list) + 1 >= (int) utils_array_size(list->arr))
|
||||
{
|
||||
jwidget_emit(list, (jevent){ .type = JMLIST_ITEM_OVERFLEW });
|
||||
return true;
|
||||
}
|
||||
jmlist_select(list, jmlist_selected(list) + 1);
|
||||
return true;
|
||||
case KEY_LEFT:
|
||||
list->offset_x -= DWIDTH / 10;
|
||||
list->frame->scroll_x -= DWIDTH / 10;
|
||||
if (list->frame->scroll_x < 0) list->frame->scroll_x = 0;
|
||||
list->widget.dirty = 1;
|
||||
jmlist_select(list, jmlist_selected(list));
|
||||
return true;
|
||||
case KEY_RIGHT:
|
||||
list->offset_x += DWIDTH / 10;
|
||||
list->frame->scroll_x += DWIDTH / 10;
|
||||
list->widget.dirty = 1;
|
||||
jmlist_select(list, jmlist_selected(list));
|
||||
return true;
|
||||
|
@ -217,6 +215,28 @@ static bool jmlist_poly_event(void *ml0, jevent e)
|
|||
|
||||
return false;
|
||||
}
|
||||
void jmlist_redo(jmlist *list, int selected)
|
||||
{
|
||||
jmlist_item *item;
|
||||
if (!list)
|
||||
{
|
||||
return;
|
||||
}
|
||||
item = utils_array_get(list->arr, selected);
|
||||
if (item->widget)
|
||||
{
|
||||
/* Destroy it's children */
|
||||
size_t i;
|
||||
size_t children = item->widget->child_count;
|
||||
|
||||
for (i = 0; i < children; i++)
|
||||
{
|
||||
jwidget_destroy(item->widget->children[0]);
|
||||
}
|
||||
}
|
||||
/* ... then put everything back in Ordung */
|
||||
list->set(item, selected);
|
||||
}
|
||||
static void jmlist_poly_destroy(void *ml0)
|
||||
{
|
||||
jmlist *list = ml0;
|
||||
|
@ -248,6 +268,7 @@ __attribute__((constructor(2001)))
|
|||
static void j_register_jmlist(void)
|
||||
{
|
||||
jmlist_type_id = j_register_widget(&type_jmlist, "jwidget");
|
||||
JMLIST_ITEM_OVERFLEW = j_register_event();
|
||||
JMLIST_ITEM_CHOSEN = j_register_event();
|
||||
JMLIST_ITEM_CHANGE = j_register_event();
|
||||
JMLIST_ITEM_ADDED = j_register_event();
|
||||
|
|
50
src/json.c
|
@ -7,8 +7,6 @@
|
|||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <log.h>
|
||||
|
||||
typedef union val_as {
|
||||
hashmap_t *object;
|
||||
array_t *array;
|
||||
|
@ -188,16 +186,18 @@ json_token_t *next_token(json_tokeniser_t *tokeniser)
|
|||
{
|
||||
json_token_t *token = NULL;
|
||||
int c, escape;
|
||||
char *str = NULL, *strcpy = NULL;
|
||||
char *str = NULL, *strcpy = NULL, *str1;
|
||||
float number = 0;
|
||||
size_t off;
|
||||
size_t off = 0;
|
||||
|
||||
int neg = 1;
|
||||
int deci;
|
||||
int deci = 0;
|
||||
ssize_t expidx = 0;
|
||||
|
||||
bool negative_exp = false;
|
||||
bool have_to_ungetch = true;
|
||||
|
||||
uint16_t unicode;
|
||||
if (!tokeniser)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -224,10 +224,26 @@ loop:
|
|||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
case 'u': /* TODO: Implement UNICODE */
|
||||
strcpy = utils_strcat(str, to_string(escape));
|
||||
if (str) free(str);
|
||||
str = strcpy;
|
||||
break;
|
||||
case 'u': /* TODO: Implement UNICODE(16-bit codepoints) */
|
||||
unicode = 0x0000;
|
||||
unicode += utils_htov(tokeniser_getch(tokeniser));
|
||||
unicode <<= 4;
|
||||
unicode += utils_htov(tokeniser_getch(tokeniser));
|
||||
unicode <<= 4;
|
||||
unicode += utils_htov(tokeniser_getch(tokeniser));
|
||||
unicode <<= 4;
|
||||
unicode += utils_htov(tokeniser_getch(tokeniser));
|
||||
|
||||
str1 = utils_unitoutf(unicode);
|
||||
strcpy = utils_strcat(str, str1);
|
||||
if (str) free(str);
|
||||
free(str1);
|
||||
str = strcpy;
|
||||
|
||||
break;
|
||||
case 'b':
|
||||
strcpy = utils_strcat(str, to_string('\b'));
|
||||
|
@ -297,6 +313,7 @@ loop:
|
|||
goto loop;
|
||||
}
|
||||
tokeniser_ungetc(tokeniser);
|
||||
/* Fallthrough */ /* gcc stop being a dumbass */
|
||||
case JSON_STATE_NUMBER_MAIN:
|
||||
c = tokeniser_getch(tokeniser);
|
||||
if (isdigit(c))
|
||||
|
@ -367,7 +384,10 @@ loop:
|
|||
deci *= 10;
|
||||
goto loop;
|
||||
}
|
||||
deci /= 10;
|
||||
if (deci != 0)
|
||||
{
|
||||
deci /= 10;
|
||||
}
|
||||
number *= powf(10, (negative_exp ? -1 : 1) * deci);
|
||||
|
||||
number *= neg;
|
||||
|
@ -464,7 +484,6 @@ static json_parser_t *parser_create(json_tokeniser_t *tokeniser)
|
|||
static void parser_free(json_parser_t *parser)
|
||||
{
|
||||
size_t i;
|
||||
json_token_t *token;
|
||||
array_t *arr;
|
||||
|
||||
if (!parser)
|
||||
|
@ -861,7 +880,7 @@ void utils_free_json_value(json_value_t *value)
|
|||
/* == WRITE ==
|
||||
* Functions to *write* JSON.
|
||||
*/
|
||||
static char *json_write_value(char *in, size_t *size, json_value_t *val);
|
||||
static char *json_write_value(char *i,size_t *s,json_value_t *v);
|
||||
|
||||
static char *json_write_null(char *in, size_t *size, json_value_t *val)
|
||||
{
|
||||
|
@ -924,7 +943,7 @@ static char *json_write_boolean(char *in, size_t *size, json_value_t *val)
|
|||
|
||||
return incpy;
|
||||
}
|
||||
static char *json_write_array(char *in, size_t *size, json_value_t *val)
|
||||
static char *json_write_array(char *in, size_t *size,json_value_t *val)
|
||||
{
|
||||
char *incpy;
|
||||
size_t i;
|
||||
|
@ -973,7 +992,7 @@ static char *json_write_array(char *in, size_t *size, json_value_t *val)
|
|||
|
||||
return incpy;
|
||||
}
|
||||
static char *json_write_object(char *in, size_t *size, json_value_t *val)
|
||||
static char *json_write_object(char *in, size_t *size,json_value_t *val)
|
||||
{
|
||||
char *incpy;
|
||||
char *key;
|
||||
|
@ -1008,6 +1027,7 @@ static char *json_write_object(char *in, size_t *size, json_value_t *val)
|
|||
in = incpy;
|
||||
(*size)++;
|
||||
}
|
||||
|
||||
incpy = utils_strcat(in, "\"");
|
||||
free(in);
|
||||
in = incpy;
|
||||
|
@ -1038,9 +1058,6 @@ static char *json_write_string(char *in, size_t *size, json_value_t *val)
|
|||
char *string;
|
||||
char chr[3];
|
||||
|
||||
bool first = true;
|
||||
|
||||
json_value_t *value;
|
||||
if (!size || !val)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -1157,7 +1174,7 @@ char * json_write_value(char *in, size_t *size, json_value_t *val)
|
|||
char * utils_json_write(hashmap_t *obj, size_t *size)
|
||||
{
|
||||
size_t len = 0;
|
||||
char *str = NULL, *str_copy;
|
||||
char *str = NULL;
|
||||
|
||||
json_value_t *val = NULL;
|
||||
|
||||
|
@ -1263,8 +1280,6 @@ void utils_free_json(hashmap_t *hm)
|
|||
}
|
||||
json_value_t *json_copy_value(json_value_t *val)
|
||||
{
|
||||
json_value_t *copied;
|
||||
|
||||
array_t *arr_copy;
|
||||
size_t i;
|
||||
if (!val)
|
||||
|
@ -1293,6 +1308,7 @@ json_value_t *json_copy_value(json_value_t *val)
|
|||
case JSON_NULL:
|
||||
return utils_null_as_json();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hashmap_t *utils_json_copy(hashmap_t *json)
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/* INTERNAL, DO NOT USE INSIDE HEADER */
|
||||
|
||||
#include <gint/keyboard.h>
|
||||
|
||||
static int key_id(int keycode)
|
||||
{
|
||||
uint col = (keycode & 0x0f) - 1;
|
||||
uint row = 9 - ((keycode & 0xf0) >> 4);
|
||||
|
||||
if(col > 5 || row > 8) return -1;
|
||||
return 6 * row + col;
|
||||
}
|
||||
|
||||
static uint16_t map_flat[48] = {
|
||||
0,0x2468, 0, 0, 0, 0,
|
||||
0, 0xB2 , '^', 0, 0, 0,
|
||||
|
||||
0xE9,0xC9, 0, '~', 0, 0,
|
||||
0xE8,0xC8,'(', ')', ',', '=',
|
||||
|
||||
'7', '8', '9', 0, 0, 0,
|
||||
'4', '5', '6', '*', '/', 0,
|
||||
'1', '2', '3', '+', '-', 0,
|
||||
'0', '.', 'e', '-', 0, 0,
|
||||
};
|
||||
static uint16_t map_alpha[36] = {
|
||||
'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o', 0, 0, 0,
|
||||
'p', 'q', 'r', 's', 't', 0,
|
||||
'u', 'v', 'w', 'x', 'y', 0,
|
||||
'z', ' ', '"', 0, 0, 0,
|
||||
};
|
||||
|
||||
uint32_t uni_keymap_translate(int key, bool shift, bool alpha)
|
||||
{
|
||||
int id = key_id(key);
|
||||
if (key >= KEY_F1 && key <= KEY_F6)
|
||||
{
|
||||
return 0x0000;
|
||||
}
|
||||
if(id < 0) return 0;
|
||||
|
||||
if(!shift && !alpha) {
|
||||
return map_flat[id - 6];
|
||||
}
|
||||
if(shift && !alpha) {
|
||||
if(key == KEY_MUL) return '{';
|
||||
if(key == KEY_DIV) return '}';
|
||||
if(key == KEY_ADD) return '[';
|
||||
if(key == KEY_SUB) return ']';
|
||||
if(key == KEY_DOT) return '=';
|
||||
if(key == KEY_EXP) return 0x3c0; // 'π'
|
||||
if(key == KEY_0) return '!';
|
||||
if(key == KEY_6) return '<';
|
||||
if(key == KEY_3) return '>';
|
||||
if(key == KEY_5) return '!';
|
||||
if(key == KEY_2) return '?';
|
||||
if(key == KEY_4) return ':';
|
||||
if(key == KEY_1) return ';';
|
||||
}
|
||||
if(!shift && alpha) {
|
||||
/* The first 3 rows have no useful characters */
|
||||
if (key == KEY_X2) return 0x2468;
|
||||
if (key == KEY_CARET) return 0x03B8;
|
||||
return (id < 18) ? 0 : map_alpha[id - 18];
|
||||
}
|
||||
if(shift && alpha) {
|
||||
int c = uni_keymap_translate(key, false, true);
|
||||
if (key == KEY_X2) return 0x2468;
|
||||
if (key == KEY_CARET) return 0x0398;
|
||||
return (c >= 'a' && c <= 'z') ? (c & ~0x20) : c;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
195
src/login.c
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <utils.h>
|
||||
#include <http.h>
|
||||
#include <log.h>
|
||||
|
||||
bool matrix_supports_password(char *server)
|
||||
{
|
||||
|
@ -67,6 +68,62 @@ end:
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
void matrix_save(m_user_t *user)
|
||||
{
|
||||
#define save_string(n, v) utils_hashmap_add(serialised, #n, utils_string_as_json(utils_strcpy(v)))
|
||||
hashmap_t *serialised;
|
||||
char *data;
|
||||
size_t len;
|
||||
if (!user)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
serialised = utils_new_hashmap();
|
||||
save_string(id, user->id);
|
||||
save_string(token, user->access_token);
|
||||
save_string(did, user->device_id);
|
||||
save_string(server, user->server);
|
||||
|
||||
data = utils_json_write(serialised, &len);
|
||||
utils_write_file("user.json", data, len);
|
||||
|
||||
utils_free_json(serialised);
|
||||
}
|
||||
m_user_t * matrix_load(void)
|
||||
{
|
||||
#define retrieve_string(v, k) v = utils_strcpy(utils_json_as_string(utils_hashmap_get(json, #k)))
|
||||
m_user_t *user = NULL;
|
||||
hashmap_t *json;
|
||||
char *data;
|
||||
size_t len;
|
||||
|
||||
log_text("loading...");
|
||||
|
||||
if (!(data = utils_get_file("user.json", &len)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
json = utils_json_parse(data, len);
|
||||
|
||||
user = malloc(sizeof(m_user_t));
|
||||
retrieve_string(user->id, id);
|
||||
retrieve_string(user->access_token, token);
|
||||
retrieve_string(user->device_id, did);
|
||||
retrieve_string(user->server, server);
|
||||
user->rooms = utils_new_hashmap();
|
||||
user->images = utils_new_hashmap();
|
||||
user->mxcs = utils_new_hashmap();
|
||||
|
||||
log_text("server='%s'", user->server);
|
||||
log_text("id='%s'", user->id);
|
||||
log_text("device_id='%s'", user->device_id);
|
||||
|
||||
utils_free_json(json);
|
||||
free(data);
|
||||
|
||||
return user;
|
||||
}
|
||||
m_user_t *matrix_login(char *server, char *user, char *password)
|
||||
{
|
||||
m_user_t *ret;
|
||||
|
@ -132,7 +189,6 @@ m_user_t *matrix_login(char *server, char *user, char *password)
|
|||
|
||||
if (http_transfer_code(trans) != 200)
|
||||
{
|
||||
char *msg = http_get_reply_data(trans, &data_len);
|
||||
ret = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
@ -155,6 +211,8 @@ m_user_t *matrix_login(char *server, char *user, char *password)
|
|||
|
||||
ret->sync_next = NULL;
|
||||
ret->rooms = utils_new_hashmap();
|
||||
ret->images = utils_new_hashmap();
|
||||
ret->mxcs = utils_new_hashmap();
|
||||
end:
|
||||
if (trans)
|
||||
{
|
||||
|
@ -162,6 +220,33 @@ end:
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
void matrix_logout(m_user_t *user)
|
||||
{
|
||||
http_transfer_t *trans;
|
||||
if (!user)
|
||||
{
|
||||
return;
|
||||
}
|
||||
trans = http_transfer_create(
|
||||
HTTP_POST,
|
||||
user->server, "/_matrix/client/v3/logout"
|
||||
);
|
||||
matrix_set_token(trans, user);
|
||||
http_transfer_send(trans);
|
||||
http_transfer_free(trans);
|
||||
|
||||
free(user->access_token);
|
||||
free(user->device_id);
|
||||
free(user->id);
|
||||
free(user->server);
|
||||
if (user->sync_next)
|
||||
{
|
||||
free(user->sync_next);
|
||||
}
|
||||
/* TODO: End with user->rooms */
|
||||
free(user);
|
||||
utils_delete_file("user.json");
|
||||
}
|
||||
void matrix_set_token(http_transfer_t *trans, m_user_t *user)
|
||||
{
|
||||
char *bearer;
|
||||
|
@ -182,6 +267,113 @@ void matrix_set_token(http_transfer_t *trans, m_user_t *user)
|
|||
http_transfer_add_header(trans, "Authorization", bearer);
|
||||
free(bearer);
|
||||
}
|
||||
void matrix_set_displayname(m_user_t *user, char *dname)
|
||||
{
|
||||
char *path;
|
||||
size_t len;
|
||||
|
||||
http_transfer_t *trans;
|
||||
hashmap_t *dn;
|
||||
|
||||
if (!user || !dname)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
len = snprintf(
|
||||
NULL, 0,
|
||||
"/_matrix/client/v3/profile/%s/displayname", user->id
|
||||
);
|
||||
path = malloc(len + 1);
|
||||
snprintf(
|
||||
path, len + 1,
|
||||
"/_matrix/client/v3/profile/%s/displayname", user->id
|
||||
);
|
||||
|
||||
trans = http_transfer_create(HTTP_PUT, user->server, path);
|
||||
free(path);
|
||||
matrix_set_token(trans, user);
|
||||
dn = utils_new_hashmap();
|
||||
utils_hashmap_add(
|
||||
dn,
|
||||
"displayname", utils_string_as_json(utils_strcpy(dname))
|
||||
);
|
||||
http_transfer_set_json(trans, dn);
|
||||
http_transfer_send(trans);
|
||||
http_transfer_free(trans);
|
||||
|
||||
}
|
||||
char * matrix_get_displayname(m_user_t *user)
|
||||
{
|
||||
char *displayname;
|
||||
char *path;
|
||||
http_transfer_t *trans;
|
||||
hashmap_t *reply;
|
||||
if (!user)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = utils_sprintf("/_matrix/client/v3/profile/%s", user->id);
|
||||
trans = http_transfer_create(HTTP_GET, user->server, path);
|
||||
free(path);
|
||||
http_transfer_send(trans);
|
||||
|
||||
if (http_transfer_code(trans) != 200)
|
||||
{
|
||||
http_transfer_free(trans);
|
||||
return NULL;
|
||||
}
|
||||
reply = http_get_reply_json(trans);
|
||||
displayname = utils_json_as_string(
|
||||
utils_hashmap_get(reply, "displayname")
|
||||
);
|
||||
displayname = utils_strcpy(displayname);
|
||||
utils_free_json(reply);
|
||||
http_transfer_free(trans);
|
||||
|
||||
return displayname;
|
||||
}
|
||||
char * matrix_get_lavatar(m_user_t *user, char *id)
|
||||
{
|
||||
char *displayname;
|
||||
char *path;
|
||||
http_transfer_t *trans;
|
||||
hashmap_t *reply;
|
||||
if (!user)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = utils_sprintf("/_matrix/client/v3/profile/%s", id);
|
||||
trans = http_transfer_create(HTTP_GET, user->server, path);
|
||||
free(path);
|
||||
http_transfer_send(trans);
|
||||
|
||||
if (http_transfer_code(trans) != 200)
|
||||
{
|
||||
http_transfer_free(trans);
|
||||
return NULL;
|
||||
}
|
||||
reply = http_get_reply_json(trans);
|
||||
displayname = utils_json_as_string(
|
||||
utils_hashmap_get(reply, "avatar_url")
|
||||
);
|
||||
displayname = utils_strcpy(displayname);
|
||||
utils_free_json(reply);
|
||||
http_transfer_free(trans);
|
||||
|
||||
return displayname;
|
||||
|
||||
}
|
||||
char * matrix_get_avatar(m_user_t *user)
|
||||
{
|
||||
if (!user)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return matrix_get_lavatar(user, user->id);
|
||||
}
|
||||
|
||||
#define COLORS 6
|
||||
const uint16_t palette[COLORS] = {
|
||||
|
@ -194,7 +386,6 @@ const uint16_t palette[COLORS] = {
|
|||
};
|
||||
uint16_t matrix_hash(char *id)
|
||||
{
|
||||
uint16_t i;
|
||||
uint32_t hash = 4373;
|
||||
if (!id)
|
||||
{
|
||||
|
|
50
src/main.c
|
@ -3,6 +3,7 @@
|
|||
#include <gint/hardware.h>
|
||||
#include <gint/display.h>
|
||||
#include <gint/kmalloc.h>
|
||||
#include <gint/clock.h>
|
||||
#include <gint/usb.h>
|
||||
#include <gint/rtc.h>
|
||||
#include <gint/fs.h>
|
||||
|
@ -56,6 +57,8 @@ static void story_of_usb_comm(void)
|
|||
log_text("=============================");
|
||||
}
|
||||
|
||||
extern font_t uf8x9;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ui_session_t *ui;
|
||||
|
@ -63,57 +66,68 @@ int main(void)
|
|||
|
||||
int key = 0;
|
||||
|
||||
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;
|
||||
|
||||
dfont(&uf8x9);
|
||||
srand(rtc_ticks());
|
||||
|
||||
/* 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
|
||||
extRAM.start = (void*) 0x8C200000;
|
||||
extRAM.end = (void*) (0x8C200000 + (4 MB));
|
||||
dclear(C_GREEN);
|
||||
dprint(1, 11, C_WHITE, "%p-%p of extmem", extRAM.start, extRAM.end);
|
||||
dupdate();
|
||||
getkey();
|
||||
|
||||
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();
|
||||
clock_set_speed(CLOCK_SPEED_F5);
|
||||
}
|
||||
dclear(C_GREEN);
|
||||
dtext(1, 11, C_WHITE, "UTF-8: Mémé a mangé des pommes, des belles pommes ! àè");
|
||||
dupdate();
|
||||
getkey();
|
||||
|
||||
|
||||
dclear(C_WHITE);
|
||||
dtext(1, 1, C_BLACK, "Waiting for USB link...");
|
||||
dupdate();
|
||||
|
||||
usb_init(&out, &in);
|
||||
|
||||
usb_init(&key, &key); /* using key as a trash var here */
|
||||
|
||||
story_of_usb_comm(); /* Greet the user over USB */
|
||||
dbg_init();
|
||||
|
||||
/* Set UI up... */
|
||||
ui = ui_create_session();
|
||||
ui->user = matrix_load();
|
||||
|
||||
screen = ui_new_screen(ui_infos_init, NULL, NULL);
|
||||
ui_add_screen(ui, screen);
|
||||
screen = ui_new_screen(ui_login_init, ui_login_focus, ui_login_event);
|
||||
ui_add_screen(ui, screen);
|
||||
|
||||
if (ui->user)
|
||||
{
|
||||
matrix_initial_sync(ui->user);
|
||||
screen = ui_new_screen(ui_rooms_init, ui_rooms_focus, ui_rooms_event);
|
||||
ui_add_screen(ui, screen);
|
||||
}
|
||||
else
|
||||
{
|
||||
screen = ui_new_screen(ui_login_init, ui_login_focus, ui_login_event);
|
||||
ui_add_screen(ui, screen);
|
||||
}
|
||||
|
||||
/* Start the UI loop */
|
||||
ui_session_loop(ui);
|
||||
|
||||
end:
|
||||
/* End everything... */
|
||||
dbg_end();
|
||||
usb_close();
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#include <gint/kmalloc.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <log.h>
|
||||
|
||||
#define ARENA_COUNT 4
|
||||
static char const *arenas[ARENA_COUNT] = { "_uram", "_ostk", "_os", "extram" };
|
||||
|
||||
uint32_t utils_total_mem(void)
|
||||
{
|
||||
uint32_t mem = 0;
|
||||
size_t i;
|
||||
kmalloc_arena_t *arena;
|
||||
for (i = 0; i < ARENA_COUNT; i++)
|
||||
{
|
||||
arena = kmalloc_get_arena(arenas[i]);
|
||||
if (!strcmp(arenas[i], "_os"))
|
||||
{
|
||||
/* The fx-CG50 has 128KB of OS-provided heap. */
|
||||
mem += 128 * 1024;
|
||||
break;
|
||||
}
|
||||
mem += (uint32_t) (arena->end - arena->start);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
uint32_t utils_used_mem(void)
|
||||
{
|
||||
uint32_t mem = 0;
|
||||
size_t i;
|
||||
kmalloc_arena_t *arena;
|
||||
kmalloc_gint_stats_t *stats;
|
||||
for (i = 0; i < ARENA_COUNT; i++)
|
||||
{
|
||||
arena = kmalloc_get_arena(arenas[i]);
|
||||
stats = kmalloc_get_gint_stats(arena);
|
||||
if (stats)
|
||||
{
|
||||
mem += stats->used_memory;
|
||||
}
|
||||
}
|
||||
return mem;
|
||||
}
|
157
src/mxc.c
|
@ -1,7 +1,11 @@
|
|||
#include "utils.h"
|
||||
#include <matrix.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <http.h>
|
||||
#include <log.h>
|
||||
#include <ui.h>
|
||||
|
||||
char *matrix_send_file(m_user_t *u, char *f, char *ct)
|
||||
{
|
||||
|
@ -33,11 +37,9 @@ char *matrix_send_file(m_user_t *u, char *f, char *ct)
|
|||
if (http_transfer_code(trans) != 200)
|
||||
{
|
||||
/* TODO */
|
||||
log_text("%s: code=%d!", __func__, http_transfer_code(trans));
|
||||
http_transfer_free(trans);
|
||||
return NULL;
|
||||
}
|
||||
log_text("%s: OK!", __func__);
|
||||
|
||||
data = http_get_reply_data(trans, &len);
|
||||
json = utils_json_parse(data, len);
|
||||
|
@ -51,3 +53,152 @@ char *matrix_send_file(m_user_t *u, char *f, char *ct)
|
|||
|
||||
return mxc;
|
||||
}
|
||||
char *matrix_get_file(m_user_t *u, char *mxc, size_t *len)
|
||||
{
|
||||
char *path, *pathcpy;
|
||||
char *cpy, *ret;
|
||||
http_transfer_t *trans;
|
||||
if (!u || !mxc || !len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (strncmp(mxc, "mxc://", 6))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = utils_strcat("/_matrix/media/v3/download/", mxc + 6);
|
||||
pathcpy = path;
|
||||
path = utils_strcat(path, "?timeout_ms=1000");
|
||||
free(pathcpy);
|
||||
|
||||
trans = http_transfer_create(HTTP_GET, u->server, path);
|
||||
free(path);
|
||||
http_transfer_send(trans);
|
||||
|
||||
if (http_transfer_code(trans) != 200)
|
||||
{
|
||||
http_transfer_free(trans);
|
||||
return NULL;
|
||||
}
|
||||
cpy = http_get_reply_data(trans, len);
|
||||
ret = malloc(*len);
|
||||
memcpy(ret, cpy, *len);
|
||||
http_transfer_free(trans);
|
||||
|
||||
return ret;
|
||||
}
|
||||
char *matrix_get_mxc_avatar(m_user_t *u, char *mxc, size_t *len, int w)
|
||||
{
|
||||
char *path, *cpy, *ret;
|
||||
http_transfer_t *trans;
|
||||
if (!u || !mxc || !len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (strncmp(mxc, "mxc://", 6))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = utils_sprintf(
|
||||
"/_matrix/media/v3/thumbnail/%s"
|
||||
"?timeout_ms=1000"
|
||||
"&width=%d&height=%d",
|
||||
mxc + 6, w, w
|
||||
);
|
||||
|
||||
trans = http_transfer_create(HTTP_GET, u->server, path);
|
||||
free(path);
|
||||
http_transfer_send(trans);
|
||||
|
||||
if (http_transfer_code(trans) != 200)
|
||||
{
|
||||
http_transfer_free(trans);
|
||||
return NULL;
|
||||
}
|
||||
cpy = http_get_reply_data(trans, len);
|
||||
ret = malloc(*len);
|
||||
memcpy(ret, cpy, *len);
|
||||
http_transfer_free(trans);
|
||||
|
||||
return ret;
|
||||
}
|
||||
void *matrix_image_from_mxc(void *parent, m_user_t *user, char *mxc, int s)
|
||||
{
|
||||
char *data;
|
||||
size_t size;
|
||||
img_t oimg;
|
||||
img_t simg, *ref;
|
||||
if (!parent || !user || !mxc)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ref = utils_hashmap_get(user->images, mxc)))
|
||||
{
|
||||
simg = *ref;
|
||||
return jmimage_create(parent, simg);
|
||||
}
|
||||
|
||||
data = matrix_get_mxc_avatar(user, mxc, &size, s);
|
||||
if (data)
|
||||
{
|
||||
oimg = load_png(data, size);
|
||||
if (img_null(oimg))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
free(data);
|
||||
|
||||
ref = malloc(sizeof(img_t));
|
||||
memcpy(ref, &oimg, sizeof(img_t));
|
||||
utils_hashmap_set(user->images, mxc, ref);
|
||||
return jmimage_create(parent, oimg);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void *matrix_image_from_user(void *parent, m_user_t *user, char *id)
|
||||
{
|
||||
char *mxc;
|
||||
if (!parent || !user || !id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if ((mxc = utils_hashmap_get(user->mxcs, id)))
|
||||
{
|
||||
return matrix_image_from_mxc(parent, user, mxc, 32);
|
||||
}
|
||||
|
||||
mxc = matrix_get_lavatar(user, id);
|
||||
utils_hashmap_set(user->mxcs, id, mxc);
|
||||
return matrix_image_from_mxc(parent, user, mxc, 32);
|
||||
}
|
||||
void *matrix_image_from_room_user(void *p, m_user_t *u, m_room_t *r, char *id)
|
||||
{
|
||||
hashmap_t *member_state;
|
||||
char *avatar_url;
|
||||
jmimage *img;
|
||||
if (!p || !u || !r || !id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
member_state = matrix_state_fetch(u, r, "m.room.member", id);
|
||||
if (!member_state)
|
||||
{
|
||||
return matrix_image_from_user(p, u, id);
|
||||
}
|
||||
|
||||
avatar_url = utils_json_as_string(
|
||||
utils_hashmap_get(member_state, "avatar_url")
|
||||
);
|
||||
if (!avatar_url)
|
||||
{
|
||||
utils_free_json(member_state);
|
||||
return matrix_image_from_user(p, u, id);
|
||||
}
|
||||
|
||||
img = matrix_image_from_mxc(p, u, avatar_url, 32);
|
||||
utils_free_json(member_state);
|
||||
return img;
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Ha! Gottem! *That* was the __REAL__ prank here!
|
364
src/room.c
|
@ -21,15 +21,14 @@
|
|||
"}"
|
||||
#else
|
||||
#define FILTER_STRING "{" \
|
||||
"\"types\":[\"m.room.message\"]" \
|
||||
"\"types\":[\"m.room.message\",\"m.sticker\",\"m.room.member\",\"m.reaction\"]," \
|
||||
"\"lazy_load_members\":true" \
|
||||
"}"
|
||||
#endif
|
||||
|
||||
hashmap_t *
|
||||
matrix_state_fetch(m_user_t *user, m_room_t *room, char *type, char *key)
|
||||
{
|
||||
m_event_t *e;
|
||||
|
||||
http_transfer_t *trans;
|
||||
|
||||
char *path = NULL, *path_cpy = NULL;
|
||||
|
@ -77,6 +76,27 @@ matrix_state_fetch(m_user_t *user, m_room_t *room, char *type, char *key)
|
|||
return json;
|
||||
}
|
||||
|
||||
char *matrix_resolve_avatar(m_user_t *user, m_room_t *room)
|
||||
{
|
||||
char *name;
|
||||
hashmap_t *name_event;
|
||||
if (!room || !user)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name_event = matrix_state_fetch(user, room, "m.room.avatar", "");
|
||||
if (!name_event)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name = utils_json_as_string(utils_hashmap_get(name_event, "url"));
|
||||
name = utils_strcpy(name);
|
||||
|
||||
utils_free_json(name_event);
|
||||
return name;
|
||||
}
|
||||
char *matrix_resolve_name(m_user_t *user, m_room_t *room)
|
||||
{
|
||||
char *name;
|
||||
|
@ -212,6 +232,8 @@ bool matrix_update_room_history(m_user_t *user, m_room_t *room, m_event_t *e, in
|
|||
|
||||
m_event_t *event = matrix_parse_event(event_object, true);
|
||||
|
||||
char *to_event;
|
||||
|
||||
if (is_in_timeline(room, event->event_id) != -1)
|
||||
{
|
||||
matrix_free_event(event);
|
||||
|
@ -219,7 +241,15 @@ bool matrix_update_room_history(m_user_t *user, m_room_t *room, m_event_t *e, in
|
|||
}
|
||||
|
||||
changed = true;
|
||||
|
||||
utils_array_add(room->timeline, event);
|
||||
|
||||
/* Look for relations. If there is, add to relation map */
|
||||
if (!(to_event = matrix_get_relation_source(event)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
matrix_add_relation(to_event, room, event);
|
||||
}
|
||||
|
||||
events_after = utils_json_as_array(
|
||||
|
@ -252,13 +282,10 @@ matrix_send_event(m_user_t *user, m_room_t *room, char *type, hashmap_t *obj)
|
|||
char *path = NULL, *path_cpy = NULL;
|
||||
|
||||
char *data;
|
||||
size_t len;
|
||||
|
||||
size_t i, size;
|
||||
|
||||
http_transfer_t *trans;
|
||||
|
||||
hashmap_t *reply;
|
||||
if (!user || !room || !type || !obj)
|
||||
{
|
||||
return;
|
||||
|
@ -316,3 +343,328 @@ char *matrix_resolve_nick(m_user_t *user, char *id, m_room_t *room)
|
|||
utils_free_json(name_event);
|
||||
return name;
|
||||
}
|
||||
|
||||
static m_room_chunk_t *parse_chunk(hashmap_t *json)
|
||||
{
|
||||
#define def_val(n, t, v) json_value_t *n##_val = NULL; \
|
||||
t n = v
|
||||
|
||||
#define get(name, r, as, c) name##_val = utils_hashmap_get(json, #name); \
|
||||
if (!name##_val && r) \
|
||||
{ \
|
||||
char *key; \
|
||||
void *value; \
|
||||
while (utils_hashmap_list(json, &key, &value))\
|
||||
{ \
|
||||
} \
|
||||
goto fail; \
|
||||
} \
|
||||
else if (name##_val) \
|
||||
{ \
|
||||
name = c(utils_json_as_##as(name##_val)); \
|
||||
}
|
||||
#define end_val(v, f) if (v) \
|
||||
{ \
|
||||
f(v); \
|
||||
}
|
||||
#define identity(x) (x)
|
||||
m_room_chunk_t *chunk;
|
||||
if (!json)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
def_val(avatar_url, char *, NULL);
|
||||
def_val(canonical_alias, char *, NULL);
|
||||
def_val(join_rule, char *, NULL);
|
||||
def_val(name, char *, NULL);
|
||||
def_val(room_id, char *, NULL);
|
||||
def_val(room_type, char *, NULL);
|
||||
def_val(topic, char *, NULL);
|
||||
def_val(guest_can_join, bool, false);
|
||||
def_val(world_readable, bool, false);
|
||||
def_val(num_joined_members, int, 0);
|
||||
|
||||
get(avatar_url, false, string, utils_strcpy);
|
||||
get(canonical_alias, false, string, utils_strcpy);
|
||||
get(join_rule, false, string, utils_strcpy);
|
||||
get(name, false, string, utils_strcpy);
|
||||
get(room_id, true, string, utils_strcpy);
|
||||
get(room_type, false, string, utils_strcpy);
|
||||
get(topic, false, string, utils_strcpy);
|
||||
|
||||
get(num_joined_members, true, number, identity);
|
||||
get(guest_can_join, true, boolean, identity);
|
||||
get(world_readable, true, boolean, identity);
|
||||
|
||||
chunk = malloc(sizeof(*chunk));
|
||||
chunk->avatar_url = avatar_url;
|
||||
chunk->canonical_alias = canonical_alias;
|
||||
chunk->join_rule = join_rule;
|
||||
chunk->name = name;
|
||||
chunk->room_id = room_id;
|
||||
chunk->room_type = room_type;
|
||||
chunk->topic = topic;
|
||||
chunk->guest_can_join = guest_can_join;
|
||||
chunk->world_readable = world_readable;
|
||||
chunk->num_joined_members = num_joined_members;
|
||||
|
||||
return chunk;
|
||||
#undef define_val
|
||||
#undef get
|
||||
#undef identity
|
||||
fail:
|
||||
end_val(avatar_url, free);
|
||||
end_val(canonical_alias, free);
|
||||
end_val(join_rule, free);
|
||||
end_val(name, free);
|
||||
end_val(room_id, free);
|
||||
end_val(room_type, free);
|
||||
end_val(topic, free);
|
||||
return NULL;
|
||||
#undef end_val
|
||||
}
|
||||
/* TODO: Add filter */
|
||||
array_t *matrix_get_directory(m_user_t *user, char *server, int limit)
|
||||
{
|
||||
array_t *dir;
|
||||
http_transfer_t *trans;
|
||||
hashmap_t *reply;
|
||||
array_t *chunks;
|
||||
|
||||
size_t i;
|
||||
char *path;
|
||||
|
||||
if (!user || limit == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = utils_sprintf(
|
||||
"/_matrix/client/v3/publicRooms"
|
||||
"%s%s" "%s%d" ,
|
||||
server ? "?server=" : "",
|
||||
server ? server : "",
|
||||
server ? "&limit=" : "?limit=", limit
|
||||
);
|
||||
|
||||
trans = http_transfer_create(HTTP_GET, user->server, path);
|
||||
matrix_set_token(trans, user);
|
||||
free(path);
|
||||
http_transfer_send(trans);
|
||||
|
||||
if (http_transfer_code(trans) != 200)
|
||||
{
|
||||
http_transfer_free(trans);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
reply = http_get_reply_json(trans);
|
||||
chunks = utils_json_as_array(utils_hashmap_get(reply, "chunk"));
|
||||
dir = utils_new_array();
|
||||
|
||||
for (i = 0; i < utils_array_size(chunks); i++)
|
||||
{
|
||||
json_value_t *v = utils_array_get(chunks, i);
|
||||
hashmap_t *rawc = utils_json_as_object(v);
|
||||
m_room_chunk_t *chunk = parse_chunk(rawc);
|
||||
|
||||
utils_array_add(dir, chunk);
|
||||
}
|
||||
|
||||
utils_free_json(reply);
|
||||
http_transfer_free(trans);
|
||||
return dir;
|
||||
}
|
||||
void matrix_free_directory(array_t *dir)
|
||||
{
|
||||
/* TODO */
|
||||
(void) dir;
|
||||
}
|
||||
bool matrix_state_set(m_user_t *user, m_room_t *room, char *type, char *key, hashmap_t *h)
|
||||
{
|
||||
http_transfer_t *trans;
|
||||
char *path = NULL, *path_cpy = NULL;
|
||||
if (!user || !room || !type || !key || !h)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
concat("/_matrix/client/v3/rooms/");
|
||||
concat(room->id);
|
||||
concat("/state/");
|
||||
concat(type);
|
||||
concat("/");
|
||||
concat(key);
|
||||
|
||||
trans = http_transfer_create(HTTP_PUT, user->server, path);
|
||||
matrix_set_token(trans, user);
|
||||
free(path);
|
||||
http_transfer_set_json(trans, utils_json_copy(h));
|
||||
http_transfer_send(trans);
|
||||
|
||||
if (http_transfer_code(trans) != 200)
|
||||
{
|
||||
http_transfer_free(trans);
|
||||
return false;
|
||||
}
|
||||
http_transfer_free(trans);
|
||||
return true;
|
||||
}
|
||||
bool matrix_set_nick(m_user_t *user, m_room_t *room, char *nick)
|
||||
{
|
||||
bool ret;
|
||||
hashmap_t *hm;
|
||||
|
||||
if (!user || !room || !nick)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
hm = utils_new_hashmap();
|
||||
utils_hashmap_set(hm, "membership", utils_string_as_json(utils_strcpy("join")));
|
||||
utils_hashmap_set(hm, "displayname", utils_string_as_json(utils_strcpy(nick)));
|
||||
ret = matrix_state_set(
|
||||
user, room,
|
||||
"m.room.member", user->id, hm
|
||||
);
|
||||
utils_free_json(hm);
|
||||
utils_hashmap_set(room->nicks, user->id, utils_strcpy(nick));
|
||||
|
||||
return ret;
|
||||
}
|
||||
void matrix_redact(m_user_t *user, m_event_t *event, char *reason)
|
||||
{
|
||||
http_transfer_t *trans;
|
||||
hashmap_t *req;
|
||||
char *path;
|
||||
uint32_t txn = rtc_ticks();
|
||||
size_t length;
|
||||
if (!user || !event)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
length = snprintf(
|
||||
NULL, 0,
|
||||
"/_matrix/client/v3/rooms"
|
||||
"/%s/redact/%s/%d",
|
||||
event->room_id, event->event_id, txn
|
||||
);
|
||||
path = malloc(length + 1);
|
||||
snprintf(
|
||||
path, length + 1,
|
||||
"/_matrix/client/v3/rooms"
|
||||
"/%s/redact/%s/%d",
|
||||
event->room_id, event->event_id, txn
|
||||
);
|
||||
|
||||
trans = http_transfer_create(HTTP_PUT, user->server, path);
|
||||
req = utils_new_hashmap();
|
||||
if (reason)
|
||||
{
|
||||
utils_hashmap_add(
|
||||
req,
|
||||
"reason", utils_string_as_json(utils_strcpy(reason))
|
||||
);
|
||||
}
|
||||
http_transfer_set_json(trans, req);
|
||||
matrix_set_token(trans, user);
|
||||
free(path);
|
||||
|
||||
http_transfer_send(trans);
|
||||
if (http_transfer_code(trans) == 200)
|
||||
{
|
||||
event->redacted = true;
|
||||
}
|
||||
http_transfer_free(trans);
|
||||
}
|
||||
m_room_t * matrix_join_room(m_user_t *user, char *id)
|
||||
{
|
||||
http_transfer_t *transfer;
|
||||
hashmap_t *request;
|
||||
m_room_t *ret;
|
||||
char *path;
|
||||
if (!user || !id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
request = utils_new_hashmap();
|
||||
path = utils_sprintf("/_matrix/client/v3/rooms/%s/join", id);
|
||||
transfer = http_transfer_create(HTTP_POST, user->server, path);
|
||||
matrix_set_token(transfer, user);
|
||||
http_transfer_set_json(transfer, request);
|
||||
free(path);
|
||||
|
||||
http_transfer_send(transfer);
|
||||
if (http_transfer_code(transfer) != 200)
|
||||
{
|
||||
http_transfer_free(transfer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
http_transfer_free(transfer);
|
||||
ret = malloc(sizeof(*ret));
|
||||
ret->id = utils_strcpy(id);
|
||||
ret->joined = 0;
|
||||
ret->nicks = utils_new_hashmap();
|
||||
ret->relations = utils_new_hashmap();
|
||||
ret->timeline = utils_new_array();
|
||||
utils_hashmap_add(user->rooms, id, ret);
|
||||
|
||||
matrix_populate_messages(user, ret, 10);
|
||||
return ret;
|
||||
}
|
||||
void matrix_populate_messages(m_user_t *user, m_room_t *room, int limit)
|
||||
{
|
||||
http_transfer_t *trans;
|
||||
hashmap_t *reply;
|
||||
json_value_t *value;
|
||||
array_t *chunk;
|
||||
char *path;
|
||||
size_t i;
|
||||
if (!user || !room || !limit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
path = utils_sprintf(
|
||||
"/_matrix/client/v3/rooms/%s/messages"
|
||||
"?limit=%d" "&filter=%s" "&dir=b",
|
||||
room->id,
|
||||
limit, FILTER_STRING
|
||||
);
|
||||
trans = http_transfer_create(HTTP_GET, user->server, path);
|
||||
matrix_set_token(trans, user);
|
||||
http_transfer_send(trans);
|
||||
free(path);
|
||||
|
||||
if (http_transfer_code(trans) != 200)
|
||||
{
|
||||
http_transfer_free(trans);
|
||||
return;
|
||||
}
|
||||
|
||||
reply = http_get_reply_json(trans);
|
||||
http_transfer_free(trans);
|
||||
|
||||
value = utils_hashmap_get(reply, "chunk");
|
||||
chunk = utils_json_as_array(value);
|
||||
|
||||
for (i = 0; i < utils_array_size(chunk); i++)
|
||||
{
|
||||
json_value_t *ev = utils_array_get(chunk, i);
|
||||
hashmap_t *raw_e = utils_json_as_object(ev );
|
||||
m_event_t *event = matrix_parse_event(raw_e, false);
|
||||
char *to_event;
|
||||
|
||||
utils_array_add(room->timeline, event);
|
||||
|
||||
/* Look for relations. If there is, add to relation map */
|
||||
if (!(to_event = matrix_get_relation_source(event)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
matrix_add_relation(to_event, room, event);
|
||||
}
|
||||
utils_free_json(reply);
|
||||
}
|
||||
|
|
131
src/stdref.c
|
@ -1,131 +0,0 @@
|
|||
#include <stdref.h>
|
||||
|
||||
#define isspace(c) ((c)==0x20 || ((c)>=0x09 && (c)<=0x0D))
|
||||
|
||||
/**
|
||||
* refnull()
|
||||
*
|
||||
* Tests if a reference points to a valid memory area.
|
||||
*
|
||||
* @param ref Reference to test.
|
||||
*
|
||||
* @return 1 if the reference is invalid or null, 0 otherwise.
|
||||
*/
|
||||
|
||||
int refnull(reference_t ref)
|
||||
{
|
||||
// Directly returning 1 if the reference is null, 0 otherwise.
|
||||
return (ref.begin >= ref.end);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* refxtrct()
|
||||
*
|
||||
* Extracts the data pointed by a reference and returns it as a
|
||||
* dynamically-allocated text pointer. The text is NUL-ended.
|
||||
*/
|
||||
|
||||
char *refxtrct(reference_t ref)
|
||||
{
|
||||
// Storing the reference length in a variable.
|
||||
const int length = ref.end - ref.begin;
|
||||
// Using a text pointer.
|
||||
char *text;
|
||||
|
||||
// Allocating memory.
|
||||
text = (char *)malloc(length + 1);
|
||||
// Handling alloc failure.
|
||||
if(!text) return NULL;
|
||||
|
||||
// Copying the data.
|
||||
memcpy(text, ref.begin, length);
|
||||
// Setting the NUL ending character.
|
||||
text[length] = 0;
|
||||
|
||||
// Returning the text.
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* reftrim()
|
||||
*
|
||||
* Reduces the given reference by excluding the beginning and ending
|
||||
* spacing.
|
||||
*
|
||||
* @param ref Original reference.
|
||||
*
|
||||
* @return Trimmed reference.
|
||||
*/
|
||||
|
||||
reference_t reftrim(reference_t ref)
|
||||
{
|
||||
// Reducing the end address until a non-space charater is reached.
|
||||
while(ref.end > ref.begin && isspace(*(ref.end-1))) ref.end--;
|
||||
// If the reference has become empty, returning it.
|
||||
if(ref.end == ref.begin) return ref;
|
||||
|
||||
// Now that we ensured the reference contains non-space characters,
|
||||
// just going forward from the beginning.
|
||||
while(isspace(*ref.begin)) ref.begin++;
|
||||
// Returning the obtained reference.
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* refscmp()
|
||||
*
|
||||
* Compares a reference with a string. Returns the result of strncmp()
|
||||
* comparison, and -1 whenever the arguments are not valid or the lengths
|
||||
* don't match.
|
||||
*
|
||||
* @param ref Reference to compare to.
|
||||
* @param str String to compare with.
|
||||
*
|
||||
* @return Result of strncmp() comparison, or -1 on error.
|
||||
*/
|
||||
|
||||
int refscmp(reference_t ref, const char *str)
|
||||
{
|
||||
// Using a variable to store the comparing length.
|
||||
int length;
|
||||
|
||||
// Testing arguments validity.
|
||||
if(refnull(ref) || !str) return -1;
|
||||
|
||||
// Getting the wanted length.
|
||||
length = strlen(str);
|
||||
// Returning 0 if the string length does not match the reference's.
|
||||
if(ref.end - ref.begin != length) return -1;
|
||||
|
||||
// Returning the result of strncmp() comparison.
|
||||
return strncmp(ref.begin, str, length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* refs,cmp()
|
||||
*
|
||||
* Compares a reference with a string in the limit of `length` characters.
|
||||
*
|
||||
* @param ref Reference to compare to.
|
||||
* @param str String to compare with.
|
||||
* @param length Maximum number of characters to compare.
|
||||
*
|
||||
* @return Result of strncmp() comparison, or -1 on error.
|
||||
*/
|
||||
|
||||
int refsncmp(reference_t ref, const char *str, int length)
|
||||
{
|
||||
// Testing arguments validity.
|
||||
if(refnull(ref) || !str || length <= 0) return -1;
|
||||
|
||||
// Returning the result of strncmp() comparison.
|
||||
return strncmp(ref.begin, str, length);
|
||||
}
|
89
src/str.c
|
@ -1,8 +1,10 @@
|
|||
#include <utils.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <log.h>
|
||||
|
||||
char *utils_strcpy(char *in)
|
||||
{
|
||||
|
@ -74,3 +76,90 @@ char * utils_basename(char *str)
|
|||
}
|
||||
return utils_strcpy(last_occurence);
|
||||
}
|
||||
|
||||
int utils_htov(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'a' && c <= 'f')
|
||||
{
|
||||
return (c - 'a') + 0xa;
|
||||
}
|
||||
if (c >= 'A' && c <= 'F')
|
||||
{
|
||||
return (c - 'A') + 0xA;
|
||||
}
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
char *utils_unitoutf(uint16_t uni)
|
||||
{
|
||||
char *ret;
|
||||
if (uni == 0x0000)
|
||||
{
|
||||
/* Don't even *try* putting a NULL byte */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (uni <= 0x007F)
|
||||
{
|
||||
ret = malloc(2 * sizeof(char));
|
||||
ret[0] = uni & 0x00FF;
|
||||
ret[1] = '\0';
|
||||
return ret;
|
||||
}
|
||||
if (uni >= 0x0080 && uni <= 0x07FF)
|
||||
{
|
||||
ret = malloc(3 * sizeof(char));
|
||||
ret[0] =
|
||||
0b11000000 |
|
||||
((uni & 0x0F00) >> 6) |
|
||||
((uni & 0x00F0) >> 6);
|
||||
ret[1] =
|
||||
0b10000000 |
|
||||
((uni & 0x00F0) & 0b110000) |
|
||||
(uni & 0x000F);
|
||||
ret[2] = '\0';
|
||||
return ret;
|
||||
}
|
||||
if (uni >= 0x0800)
|
||||
{
|
||||
ret = malloc(4 * sizeof(char));
|
||||
ret[0] =
|
||||
0b11100000 |
|
||||
((uni & 0xF000) >> 12);
|
||||
ret[1] =
|
||||
0b10000000 |
|
||||
((uni & 0x0F00) >> 6) |
|
||||
((uni & 0x00F0) >> (4 + 2));
|
||||
ret[2] =
|
||||
0b10000000 |
|
||||
((uni & 0x00F0) & 0b110000) |
|
||||
((uni & 0x000F));
|
||||
ret[3] = '\0';
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
char * utils_sprintf(char *fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
char *str;
|
||||
size_t len;
|
||||
|
||||
if (!fmt)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
va_start(list, fmt);
|
||||
|
||||
len = vsnprintf(NULL, 0, fmt, list);
|
||||
str = malloc(len + 1);
|
||||
vsnprintf(str, len + 1, fmt, list);
|
||||
|
||||
va_end(list);
|
||||
return str;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
#include <easters.h>
|
||||
|
||||
#include <gint/defs/timeout.h>
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/display.h>
|
||||
|
||||
extern bopti_image_t cirno;
|
||||
extern font_t curse_casual;
|
||||
|
||||
void easter_strongest(void)
|
||||
{
|
||||
dfont(&curse_casual);
|
||||
timeout_t tm;
|
||||
size_t i = 0;
|
||||
while (true)
|
||||
{
|
||||
dclear(C_BLACK);
|
||||
dimage(0, 0, &cirno);
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
dtext_opt(
|
||||
DWIDTH / 2, DHEIGHT / 2,
|
||||
C_RGB(31, 31, 0), C_NONE,
|
||||
DTEXT_CENTER, DTEXT_MIDDLE,
|
||||
"STRONGEST", 9
|
||||
);
|
||||
}
|
||||
dupdate();
|
||||
tm = timeout_make_ms(1000);
|
||||
while (!timeout_elapsed(&tm));
|
||||
i++;
|
||||
}
|
||||
dfont(NULL);
|
||||
}
|
18
src/sync.c
|
@ -9,10 +9,9 @@
|
|||
|
||||
#include <utils.h>
|
||||
#include <http.h>
|
||||
#include <log.h>
|
||||
|
||||
/* I hate this. */
|
||||
#define FILTER_STRING "{\"event_fields\":[\"content.body\",\"content.msgtype\",\"event_id\",\"sender\",\"origin_server_ts\",\"type\"],\"event_format\":\"client\",\"presence\":{\"limit\":1,\"not_types\":[\"*\"]},\"account_data\":{\"limit\":1},\"room\":{\"ephemeral\":{\"limit\":1,\"not_types\":[\"m.receipt\"]},\"state\":{\"not_types\":[\"m.room.member\",\"m.room.server_acl\"],\"lazy_load_members\":true,\"limit\":1},\"timeline\":{\"limit\":1,\"not_types\":[\"m.room.server_acl\"],\"types\":[\"m.room.message\"],\"lazy_load_members\":true,\"unread_thread_notifications\":true},\"account_data\":{\"limit\":1}}}"
|
||||
#define FILTER_STRING "{\"event_fields\":[\"content.body\",\"content.msgtype\",\"room_id\",\"event_id\",\"sender\",\"origin_server_ts\",\"type\"],\"event_format\":\"client\",\"presence\":{\"limit\":1,\"not_types\":[\"*\"]},\"account_data\":{\"limit\":1},\"room\":{\"ephemeral\":{\"limit\":1,\"not_types\":[\"m.receipt\"]},\"state\":{\"not_types\":[\"m.room.member\",\"m.room.server_acl\"],\"lazy_load_members\":true,\"limit\":1},\"timeline\":{\"limit\":1,\"not_types\":[\"m.room.server_acl\"],\"types\":[\"m.room.message\"],\"lazy_load_members\":true,\"unread_thread_notifications\":true},\"account_data\":{\"limit\":1}}}"
|
||||
|
||||
/* TODO: This will not be fun on Conduit/Dendrite.
|
||||
* It seems like both of them have a tendency to *ignore* some properties I
|
||||
|
@ -57,7 +56,7 @@ void matrix_initial_sync(m_user_t *user)
|
|||
|
||||
if (http_transfer_code(trans) != 200)
|
||||
{
|
||||
const char *msg = "Reply isn't 200.\n";
|
||||
/* TODO: Error managment */
|
||||
}
|
||||
|
||||
json = utils_json_parse(reply, length);
|
||||
|
@ -100,6 +99,7 @@ void matrix_initial_sync(m_user_t *user)
|
|||
|
||||
room->id = utils_strcpy(key);
|
||||
room->timeline = utils_new_array();
|
||||
room->relations = utils_new_hashmap();
|
||||
room->nicks = utils_new_hashmap();
|
||||
|
||||
/* TODO: Create "add event to timeline" function */
|
||||
|
@ -135,10 +135,16 @@ void matrix_initial_sync(m_user_t *user)
|
|||
|
||||
if (event)
|
||||
{
|
||||
json_value_t *msg;
|
||||
msg = utils_hashmap_get(event->content, "body");
|
||||
char *to_event;
|
||||
|
||||
utils_array_add(room->timeline, event);
|
||||
continue;
|
||||
|
||||
/* Look for relations. If there is, add to relation map */
|
||||
if (!(to_event = matrix_get_relation_source(event)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
matrix_add_relation(to_event, room, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
45
src/ui.c
|
@ -111,6 +111,8 @@ ui_screen_t * ui_set_screen(ui_session_t *ui, size_t idx)
|
|||
|
||||
return indexed;
|
||||
}
|
||||
|
||||
#include <log.h>
|
||||
bool ui_manage_event(ui_session_t *ui, jevent e)
|
||||
{
|
||||
ui_screen_t *screen;
|
||||
|
@ -133,8 +135,10 @@ 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. */
|
||||
/* TODO: Actually investigate on this arsehole */
|
||||
log_text("focusing (%p, %p)", ui->justui_screen, widget);
|
||||
jscene_set_focused_widget(ui->justui_screen, widget);
|
||||
log_text("focused");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -142,7 +146,7 @@ bool ui_manage_event(ui_session_t *ui, jevent e)
|
|||
void ui_session_loop(ui_session_t *ui)
|
||||
{
|
||||
int key = 0;
|
||||
while (key != KEY_EXIT)
|
||||
while (true)
|
||||
{
|
||||
jevent e = jscene_run(ui->justui_screen);
|
||||
|
||||
|
@ -239,40 +243,3 @@ 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
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
#include <ui.h>
|
||||
#include <utils.h>
|
||||
#include <ui_generators.h>
|
||||
|
||||
#include <justui/jwidget.h>
|
||||
#include <justui/jlabel.h>
|
||||
#include <justui/jframe.h>
|
||||
#include <justui/jfkeys.h>
|
||||
#include <justui/jinput.h>
|
||||
|
||||
#include <libimg.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <easters.h>
|
||||
#include <matrix.h>
|
||||
#include <log.h>
|
||||
|
||||
|
||||
extern font_t terminus_strong;
|
||||
|
||||
typedef struct accinfo_extra {
|
||||
jwidget *main;
|
||||
jlabel *acct_name;
|
||||
void *content;
|
||||
void *input;
|
||||
void *input_widget;
|
||||
} accinfo_extra_t;
|
||||
void render(int x, int y, img_t *img)
|
||||
{
|
||||
img_render_vram(*img, x, y);
|
||||
}
|
||||
void * ui_accinfo_init(ui_screen_t *that)
|
||||
{
|
||||
#define display(un, property)do {\
|
||||
jwidget *wid = jwidget_create(cwidget);\
|
||||
jlabel *left, *right; \
|
||||
jlayout_set_hbox(wid)->spacing = 1; \
|
||||
jwidget_set_stretch(wid, 1, 0, false); \
|
||||
left = jlabel_create(un, wid); \
|
||||
right = jlabel_create("[unknown]", wid); \
|
||||
jwidget_set_stretch(left, 1, 0, false); \
|
||||
jlabel_asprintf(right, \
|
||||
"%s", \
|
||||
that->owner->user->property \
|
||||
); \
|
||||
} while(0)
|
||||
jlabel *title;
|
||||
jwidget *basic_acct;
|
||||
jlabel *acct_name;
|
||||
|
||||
jframe *content;
|
||||
jwidget *cwidget;
|
||||
|
||||
jwidget *widget;
|
||||
|
||||
jfkeys *jfk;
|
||||
|
||||
accinfo_extra_t *extra = malloc(sizeof(accinfo_extra_t));
|
||||
|
||||
widget = jwidget_create(that->owner->stack);
|
||||
jlayout_set_vbox(widget)->spacing = 1;
|
||||
jwidget_set_padding(widget, 0, 0, 0, 0);
|
||||
jwidget_set_stretch(widget, 1, 1, false);
|
||||
|
||||
title = jlabel_create("Account information", widget);
|
||||
jwidget_set_padding(title, 1, 1, 3, 1);
|
||||
jwidget_set_stretch(title, 1, 0, false);
|
||||
jwidget_set_background(title, C_BLACK);
|
||||
jlabel_set_text_color(title, C_WHITE);
|
||||
|
||||
basic_acct = jwidget_create(widget);
|
||||
jwidget_set_padding(basic_acct, 1, 1, 1, 1);
|
||||
jwidget_set_stretch(basic_acct, 1, 0, false);
|
||||
jlayout_set_hbox(basic_acct)->spacing = 1;
|
||||
jwidget_set_border(basic_acct, J_BORDER_SOLID, 1, C_BLACK);
|
||||
|
||||
{
|
||||
char *avatar_url = matrix_get_avatar(that->owner->user);
|
||||
matrix_image_from_mxc(basic_acct, that->owner->user, avatar_url, 32);
|
||||
}
|
||||
{
|
||||
char *acc_name = matrix_get_displayname(that->owner->user);
|
||||
if (!acc_name)
|
||||
{
|
||||
acc_name = utils_strcpy(that->owner->user->id);
|
||||
}
|
||||
acct_name = jlabel_create("", basic_acct);
|
||||
extra->acct_name = acct_name;
|
||||
jlabel_asprintf(acct_name, "%s", acc_name);
|
||||
jlabel_set_font(acct_name, &terminus_strong);
|
||||
free(acc_name);
|
||||
}
|
||||
|
||||
|
||||
content = jframe_create(widget);
|
||||
jwidget_set_padding(content, 2, 2, 2, 2);
|
||||
jwidget_set_stretch(content, 1, 1, false);
|
||||
jframe_set_keyboard_control(content, true);
|
||||
|
||||
cwidget = jwidget_create(content);
|
||||
jlayout_set_vbox(cwidget)->spacing = 1;
|
||||
jwidget_set_padding(cwidget, 2, 2, 2, 2);
|
||||
jwidget_set_stretch(cwidget, 1, 1, false);
|
||||
jwidget_set_maximum_width(cwidget, DWIDTH - 5);
|
||||
|
||||
jfk = jfkeys_create("#USERNAME;;;;;;#LOGOUT", widget);
|
||||
jwidget_set_stretch(jfk, 1, 0, false);
|
||||
|
||||
jlabel_create("General account information", cwidget);
|
||||
display("User ID ", id);
|
||||
display("Device ID ", device_id);
|
||||
display("Server ", server);
|
||||
display("Access token ", access_token);
|
||||
|
||||
/* TODO: Device list */
|
||||
|
||||
extra->content = content;
|
||||
extra->main = widget;
|
||||
extra->input_widget = NULL;
|
||||
extra->input = NULL;
|
||||
that->data = extra;
|
||||
|
||||
return content;
|
||||
|
||||
}
|
||||
void * ui_accinfo_focus(ui_screen_t *that)
|
||||
{
|
||||
(void) that;
|
||||
return NULL;
|
||||
}
|
||||
void * ui_accinfo_event(ui_screen_t *that, jevent e)
|
||||
{
|
||||
key_event_t ke = e.key;
|
||||
accinfo_extra_t *extra = that->data;
|
||||
if (e.type == JINPUT_VALIDATED)
|
||||
{
|
||||
jinput *input = extra->input;
|
||||
char *text = (char *) jinput_value(input);
|
||||
|
||||
matrix_set_displayname(that->owner->user, text);
|
||||
|
||||
jlabel_asprintf(extra->acct_name, "%s", text);
|
||||
|
||||
jwidget_destroy(extra->input_widget);
|
||||
extra->input_widget = NULL;
|
||||
extra->input = NULL;
|
||||
|
||||
if (!strcmp(text, "Cirno"))
|
||||
{
|
||||
easter_strongest();
|
||||
}
|
||||
|
||||
return extra->content;
|
||||
}
|
||||
if (ke.key == KEY_F1 && ke.type == KEYEV_UP && !extra->input)
|
||||
{
|
||||
jwidget *floating = jwidget_create(extra->main);
|
||||
jinput *input;
|
||||
jwidget_set_floating(floating, true);
|
||||
jlayout_set_vbox(floating)->spacing = 3;
|
||||
jwidget_set_border(floating, J_BORDER_SOLID, 1, C_BLACK);
|
||||
jwidget_set_background(floating, C_WHITE);
|
||||
jwidget_set_fixed_width(floating, DWIDTH - 70);
|
||||
jwidget_set_fixed_height(floating, DHEIGHT - 150);
|
||||
floating->x = ((DWIDTH - floating->max_w) / 2);
|
||||
floating->y = ((DHEIGHT - floating->max_h) / 2);
|
||||
|
||||
jlabel_create("Enter a username", floating);
|
||||
input = jinput_create("", 32, floating);
|
||||
jwidget_set_stretch(input, 1, 0, false);
|
||||
jwidget_set_padding(input, 1, 2, 1, 2);
|
||||
extra->input = input;
|
||||
extra->input_widget = floating;
|
||||
|
||||
return input;
|
||||
}
|
||||
if (ke.key == KEY_EXIT)
|
||||
{
|
||||
jwidget_destroy(extra->main);
|
||||
free(that->data);
|
||||
ui_destroy_screen(that->owner);
|
||||
return NULL;
|
||||
}
|
||||
if (ke.key == KEY_F6 && ke.type == KEYEV_UP && !extra->input)
|
||||
{
|
||||
matrix_logout(that->owner->user);
|
||||
that->owner->user = NULL;
|
||||
exit(0); /* TODO: gracefully exit */
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#include <ui.h>
|
||||
|
||||
#include <gint/defs/timeout.h>
|
||||
#include <gint/clock.h>
|
||||
#include <gint/usb-ff-bulk.h>
|
||||
#include <gint/usb.h>
|
||||
#include <gint/defs/timeout.h>
|
||||
|
@ -11,6 +13,7 @@
|
|||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <easters.h>
|
||||
#include <matrix.h>
|
||||
#include <utils.h>
|
||||
#include <info.h>
|
||||
|
@ -19,14 +22,15 @@ const char *infos =
|
|||
"= Ma's Trix\n"
|
||||
"A half decent [matrix] client.\n\n\n"
|
||||
"LICENSE: \n"
|
||||
"- CeCILL\n\n"
|
||||
"- MIT (see COPYING and LAWYER STUFF)\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, WebCalc and other tools\n"
|
||||
"- Lephe for writing gint, fxlink, libimg, uf5x7/uf8x9 and other tools\n"
|
||||
"- Yoran Heling for making yxml\n"
|
||||
"- ari.lt for offering the mastrix.org domain for free!\n"
|
||||
"- The [matrix] Foundation for providing its specification to "
|
||||
"the public\n"
|
||||
|
@ -34,31 +38,107 @@ const char *infos =
|
|||
"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"
|
||||
"- @moonzero:4d2.org and @sarah:4d2.org for finding a small bug " "\n"
|
||||
"in my JSON implementation without even trying to (gg)" "\n"
|
||||
"- plate, just come back please :(\n\n"
|
||||
"FUN STUFF (press F1 to exit): \n"
|
||||
"FUN STUFF (press EXIT to exit): \n"
|
||||
"- Program name: " MASTRIX_NAME "\n"
|
||||
"- Program version: " MASTRIX_VERS "\n"
|
||||
"- Intended platform: " MASTRIX_PLAT "\n"
|
||||
"- User-Agent string: " MASTRIX_UA "\n";
|
||||
"- User-Agent string: " MASTRIX_UA "\n\n"
|
||||
"LAWYER STUFF (not fun): \n"
|
||||
"- YXML (MIT)\n"
|
||||
"Copyright (c) 2013-2014 Yoran Heling\n\n"
|
||||
"Permission is hereby granted, free of charge, to any person obtaining\n"
|
||||
"a copy of this software and associated documentation files (the\n"
|
||||
"\"Software\"), to deal in the Software without restriction, including\n"
|
||||
"without limitation the rights to use, copy, modify, merge, publish,\n"
|
||||
"distribute, sublicense, and/or sell copies of the Software, and to\n"
|
||||
"permit persons to whom the Software is furnished to do so, subject to\n"
|
||||
"the following conditions:\n"
|
||||
"\n"
|
||||
"The above copyright notice and this permission notice shall be included\n"
|
||||
"in all copies or substantial portions of the Software.\n"
|
||||
"\n"
|
||||
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"
|
||||
"EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n"
|
||||
"MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n"
|
||||
"IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n"
|
||||
"CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n"
|
||||
"TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n"
|
||||
"SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n"
|
||||
"- Ma's Trix (MIT)\n"
|
||||
"Copyright (c) 2024 LDA\n\n"
|
||||
"Permission is hereby granted, free of charge, to any person obtaining\n"
|
||||
"a copy of this software and associated documentation files (the\n"
|
||||
"\"Software\"), to deal in the Software without restriction, including\n"
|
||||
"without limitation the rights to use, copy, modify, merge, publish,\n"
|
||||
"distribute, sublicense, and/or sell copies of the Software, and to\n"
|
||||
"permit persons to whom the Software is furnished to do so, subject to\n"
|
||||
"the following conditions:\n"
|
||||
"\n"
|
||||
"The above copyright notice and this permission notice shall be included\n"
|
||||
"in all copies or substantial portions of the Software.\n"
|
||||
"\n"
|
||||
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"
|
||||
"EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n"
|
||||
"MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n"
|
||||
"IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n"
|
||||
"CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n"
|
||||
"TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n"
|
||||
"SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" ;
|
||||
void * ui_infos_init(ui_screen_t *that)
|
||||
{
|
||||
jframe *info_frame;
|
||||
jlabel *info_label;
|
||||
|
||||
info_frame = jframe_create(that->owner->stack);
|
||||
jframe_set_keyboard_control(info_frame, true);
|
||||
jwidget_set_padding(info_frame, 1, 1, 1, 1);
|
||||
jwidget_set_stretch(info_frame, 1, 1, false);
|
||||
|
||||
info_label = jlabel_create(infos, info_frame);
|
||||
jlabel_create(infos, info_frame);
|
||||
|
||||
return info_frame;
|
||||
}
|
||||
void * ui_infos_event(ui_screen_t *that, jevent e)
|
||||
{
|
||||
if (e.key.type == KEYEV_UP && e.key.key == KEY_F1)
|
||||
if (e.key.type == KEYEV_UP && e.key.key == KEY_EXIT)
|
||||
{
|
||||
ui_destroy_screen(that->owner);
|
||||
}
|
||||
if (e.key.type == KEYEV_UP && e.key.key == KEY_F1)
|
||||
{
|
||||
easter_credit();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define TEXT_CNTR 7
|
||||
static const char *texts[TEXT_CNTR] = {
|
||||
"It's over.",
|
||||
"You've reached the credit screen.",
|
||||
"I hope you're proud.",
|
||||
"If you wonder what I'm up to",
|
||||
"I'm on a FOOLS ERRAND",
|
||||
"SMASHing out those bugs",
|
||||
"All on a PC"
|
||||
};
|
||||
extern bopti_image_t credits_image;
|
||||
void easter_credit(void)
|
||||
{
|
||||
int y = 0;
|
||||
dimage(0, 0, &credits_image);
|
||||
for (y = 0; y < TEXT_CNTR; y++)
|
||||
{
|
||||
dprint_opt(0, y * 11 + 20, C_WHITE, C_NONE, DTEXT_RIGHT, DTEXT_MIDDLE, texts[y]);
|
||||
}
|
||||
dupdate();
|
||||
sleep_ms(1000);
|
||||
while (true)
|
||||
{
|
||||
if (getkey().key == KEY_F1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ void * ui_login_init(ui_screen_t *that)
|
|||
);
|
||||
login_data_t *data;
|
||||
jlabel *error;
|
||||
jpainted *logo;
|
||||
login_content = jwidget_create(login_widget);
|
||||
that->data = malloc(sizeof(login_data_t));
|
||||
data = that->data;
|
||||
|
@ -56,7 +55,7 @@ void * ui_login_init(ui_screen_t *that)
|
|||
jwidget_set_padding(login_content, 0, 0, 0, 0);
|
||||
jwidget_set_stretch(login_content, 1, 1,false);
|
||||
|
||||
logo = ui_image(
|
||||
ui_image(
|
||||
login_content,
|
||||
&mastrix
|
||||
);
|
||||
|
@ -103,12 +102,10 @@ void * ui_login_event(ui_screen_t *that, jevent e)
|
|||
|
||||
if (e.type == JINPUT_VALIDATED)
|
||||
{
|
||||
jinput *server, *login, *password;
|
||||
jinput *server;
|
||||
jlabel *error = data->error;
|
||||
|
||||
server = data->server;
|
||||
login = data->login;
|
||||
password = data->password;
|
||||
if (data->focusing == data->server)
|
||||
{
|
||||
char *delegated = NULL;
|
||||
|
@ -145,6 +142,7 @@ void * ui_login_event(ui_screen_t *that, jevent e)
|
|||
break;
|
||||
case DELEG_FAIL_PROMPT:
|
||||
jlabel_set_text_color(error, C_RED);
|
||||
/* Fallthrough */
|
||||
case DELEG_PROMPT:
|
||||
jlabel_asprintf(
|
||||
error,
|
||||
|
@ -199,6 +197,7 @@ void * ui_login_event(ui_screen_t *that, jevent e)
|
|||
/* TODO: Create a function to logout later */
|
||||
ui_screen_t *rooms;
|
||||
that->owner->user = user;
|
||||
matrix_save(user);
|
||||
|
||||
jlabel_set_text_color(error, C_GREEN);
|
||||
jlabel_asprintf(
|
||||
|
|
598
src/ui_room.c
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <gint/drivers/keydev.h>
|
||||
#include <gint/timer.h>
|
||||
#include <gint/rtc.h>
|
||||
|
||||
#include <justui/jfileselect.h>
|
||||
#include <justui/jwidget.h>
|
||||
|
@ -14,9 +15,14 @@
|
|||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <command.h>
|
||||
#include <easters.h>
|
||||
#include <matrix.h>
|
||||
#include <utils.h>
|
||||
#include <usb.h>
|
||||
#include <log.h>
|
||||
|
||||
extern font_t uf5x7, uf8x9;
|
||||
|
||||
typedef struct ui_room_extra {
|
||||
jwidget *main;
|
||||
|
@ -25,12 +31,15 @@ typedef struct ui_room_extra {
|
|||
jwidget *tl_widget;
|
||||
jfkeys *jfk;
|
||||
jmlist *timeline;
|
||||
jmlist *charpick;
|
||||
jfileselect *file;
|
||||
|
||||
jwidget *time_head;
|
||||
|
||||
m_room_t *room;
|
||||
m_user_t *user;
|
||||
|
||||
m_event_t *replying;
|
||||
|
||||
int timer_id;
|
||||
|
||||
volatile bool flag;
|
||||
|
@ -41,8 +50,9 @@ typedef struct ui_room_extra {
|
|||
|
||||
static int timer_cb(ui_screen_t *);
|
||||
|
||||
#include "keymap_translate.h"
|
||||
|
||||
typedef struct item_extra {
|
||||
const char *code;
|
||||
ui_screen_t *screen;
|
||||
m_event_t *event;
|
||||
|
||||
|
@ -51,28 +61,40 @@ typedef struct item_extra {
|
|||
|
||||
static void ui_room_act(item_extra_t *ie)
|
||||
{
|
||||
ui_room_extra_t *extra = ie->extra;
|
||||
m_event_t *event = ie->event;
|
||||
|
||||
char *msgtype;
|
||||
char *body;
|
||||
char *url;
|
||||
|
||||
if (strcmp(event->type, "m.room.message"))
|
||||
{
|
||||
/* Do not interact over non-messages for now */
|
||||
return;
|
||||
}
|
||||
/* TODO: Act upon the event(downloading/...) */
|
||||
}
|
||||
msgtype = utils_json_as_string(
|
||||
utils_hashmap_get(event->content, "msgtype")
|
||||
);
|
||||
if (!strcmp(msgtype, "m.file") || !strcmp(msgtype, "m.image"))
|
||||
{
|
||||
char *data;
|
||||
size_t len = 0;
|
||||
body = utils_json_as_string(
|
||||
utils_hashmap_get(event->content, "body")
|
||||
);
|
||||
body = utils_strcat("/", body);
|
||||
url = utils_json_as_string(
|
||||
utils_hashmap_get(event->content, "url")
|
||||
);
|
||||
|
||||
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);
|
||||
data = matrix_get_file(ie->extra->user, url, &len);
|
||||
utils_write_file(body, data, len);
|
||||
|
||||
label = jlabel_create("", item->widget);
|
||||
jlabel_asprintf(label, "%c", c);
|
||||
jwidget_set_background(label, C_WHITE);
|
||||
free(data);
|
||||
free(body);
|
||||
return;
|
||||
}
|
||||
ie->extra->replying = event;
|
||||
}
|
||||
static void set(jmlist_item *item, int idx)
|
||||
{
|
||||
|
@ -80,14 +102,9 @@ static void set(jmlist_item *item, int idx)
|
|||
ui_room_extra_t *extra = ie->extra;
|
||||
m_event_t *e = ie->event;
|
||||
|
||||
jlabel *sender;
|
||||
jlabel *content;
|
||||
|
||||
json_value_t *body;
|
||||
char *msg;
|
||||
char *nick;
|
||||
|
||||
matrix_show_event(extra->room, extra->user, e, item->widget);
|
||||
|
||||
(void) idx;
|
||||
}
|
||||
static void screen_free(ui_screen_t *that)
|
||||
{
|
||||
|
@ -161,11 +178,13 @@ void * ui_room_init(ui_screen_t *that)
|
|||
|
||||
|
||||
|
||||
type_message = jinput_create("Send a message: ", 100, main);
|
||||
type_message = jinput_create("Type: ", 100, main);
|
||||
jwidget_set_stretch(type_message, 1, 0, false);
|
||||
jwidget_set_border(type_message, J_BORDER_SOLID, 1, C_BLACK);
|
||||
jinput_set_font(type_message, &uf5x7);
|
||||
jinput_set_keymap_function(type_message, uni_keymap_translate);
|
||||
|
||||
jfk = jfkeys_create("@MESG;@ROOM;/FILE;;#CHR;@EXIT", main);
|
||||
jfk = jfkeys_create(utils_strcpy("@MESG;@ROOM;/FILE;;;@EXIT"), main);
|
||||
jwidget_set_stretch(jfk, 1, 0, false);
|
||||
|
||||
{
|
||||
|
@ -178,7 +197,8 @@ void * ui_room_init(ui_screen_t *that)
|
|||
extra->jfk = jfk;
|
||||
extra->on_timeline = true;
|
||||
extra->file = NULL;
|
||||
extra->charpick = NULL;
|
||||
extra->replying = NULL;
|
||||
extra->time_head = NULL;
|
||||
|
||||
extra->timer_id = timer_configure(
|
||||
TIMER_ANY,
|
||||
|
@ -193,13 +213,15 @@ void * ui_room_init(ui_screen_t *that)
|
|||
m_event_t *e = utils_array_get(room->timeline, size - i - 1);
|
||||
item_extra_t *ie = malloc(sizeof(item_extra_t));
|
||||
|
||||
ie->code = "hiiiiiii >:3";
|
||||
ie->event = e;
|
||||
ie->screen = that;
|
||||
ie->extra = extra;
|
||||
jmlist_add_item(timeline, ie);
|
||||
}
|
||||
jmlist_select(timeline, 1);
|
||||
jmlist_select(
|
||||
extra->timeline,
|
||||
utils_array_size(extra->timeline->arr) - 1
|
||||
);
|
||||
|
||||
extra->flag = false;
|
||||
extra->flag1 = false;
|
||||
|
@ -207,9 +229,26 @@ void * ui_room_init(ui_screen_t *that)
|
|||
|
||||
return timeline;
|
||||
}
|
||||
static ssize_t find_event_in_timeline(jmlist *timeline, char *id)
|
||||
{
|
||||
ssize_t i;
|
||||
ssize_t len = utils_array_size(timeline->arr);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
jmlist_item *item = utils_array_get(timeline->arr, i);
|
||||
item_extra_t *extra = item->data;
|
||||
m_event_t *e = extra->event;
|
||||
|
||||
if (!strcmp(e->event_id, id))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
static void ui_update_history(ui_screen_t *that)
|
||||
{
|
||||
/* help */
|
||||
ui_room_extra_t *extra = that->data;
|
||||
size_t lidx, i, size;
|
||||
|
||||
|
@ -232,18 +271,36 @@ static void ui_update_history(ui_screen_t *that)
|
|||
m_event_t *e = utils_array_get(extra->room->timeline, size - i - 1);
|
||||
item_extra_t *ie = malloc(sizeof(item_extra_t));
|
||||
|
||||
ie->code = "hii :3";
|
||||
ie->event = e;
|
||||
ie->screen = that;
|
||||
ie->extra = extra;
|
||||
/*jmlist_prepend_item(extra->timeline, ie);*/
|
||||
jmlist_add_item(extra->timeline, ie);
|
||||
|
||||
if (matrix_get_relation_type(e))
|
||||
{
|
||||
jmlist_item *item;
|
||||
item_extra_t *itemextra;
|
||||
int event = find_event_in_timeline(
|
||||
extra->timeline,
|
||||
matrix_get_relation_source(e)
|
||||
);
|
||||
if (event == -1)
|
||||
{
|
||||
log_text("Couldn't find!");
|
||||
continue;
|
||||
}
|
||||
item = utils_array_get(extra->timeline->arr, event);
|
||||
itemextra = item->data;
|
||||
|
||||
jmlist_redo(extra->timeline, event);
|
||||
log_text("Have to redo(%d->%s)!", event, itemextra->event->event_id);
|
||||
}
|
||||
}
|
||||
jmlist_select(extra->timeline, 1);
|
||||
|
||||
return;
|
||||
}
|
||||
#include <string.h>
|
||||
void emit(void *w0, jevent e)
|
||||
{
|
||||
J_CAST(w)
|
||||
|
@ -316,122 +373,88 @@ static void * ui_file_event(ui_screen_t *that, jevent e)
|
|||
}
|
||||
return extra->file;
|
||||
}
|
||||
static void * ui_char_event(ui_screen_t *that, jevent e)
|
||||
static m_event_t * send_msg(ui_room_extra_t *extra)
|
||||
{
|
||||
ui_room_extra_t *extra = that->data;
|
||||
if (e.type == JMLIST_ITEM_CHOSEN)
|
||||
hashmap_t *msg = utils_new_hashmap();
|
||||
m_event_t *e;
|
||||
if (!extra)
|
||||
{
|
||||
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)
|
||||
|
||||
utils_hashmap_set(
|
||||
msg,
|
||||
"msgtype",
|
||||
utils_string_as_json(
|
||||
utils_strcpy("m.text")
|
||||
)
|
||||
);
|
||||
if (extra->replying)
|
||||
{
|
||||
int selected = jmlist_selected(extra->timeline);
|
||||
if (selected == 0)
|
||||
{
|
||||
ui_update_history(that);
|
||||
return extra->timeline;
|
||||
}
|
||||
extra->timeline->widget.update = 1;
|
||||
return NULL;
|
||||
}
|
||||
if (e.type == JMLIST_ITEM_NOP && !extra->file)
|
||||
{
|
||||
ui_room_extra_t *extra = that->data;
|
||||
m_event_t *e;
|
||||
ssize_t size, i;
|
||||
size_t from;
|
||||
|
||||
int prev;
|
||||
uint8_t code = extra->input->mode;
|
||||
jrect rect;
|
||||
|
||||
|
||||
e = utils_array_get(extra->room->timeline, 0);
|
||||
|
||||
rect = extra->timeline->rect;
|
||||
prev = jmlist_selected(extra->timeline);
|
||||
|
||||
that->owner->waiting = true;
|
||||
matrix_update_room_history(extra->user, extra->room, e, 10);
|
||||
|
||||
from = is_in_timeline(extra->room, e->event_id);
|
||||
if (from != 0)
|
||||
{
|
||||
size = utils_array_size(extra->room->timeline);
|
||||
for (i = from - 1; i >= 0; i--)
|
||||
{
|
||||
m_event_t *e = utils_array_get(
|
||||
extra->room->timeline,
|
||||
i
|
||||
);
|
||||
item_extra_t *ie = malloc(sizeof(item_extra_t));
|
||||
|
||||
ie->code = "hi";
|
||||
ie->event = e;
|
||||
ie->screen = that;
|
||||
ie->extra = that->data;
|
||||
jmlist_add_item(extra->timeline, ie);
|
||||
}
|
||||
|
||||
}
|
||||
that->owner->waiting = false;
|
||||
extra->input->mode = code; /* It seems like the input doesn't keep
|
||||
its mode, somehow??????? */
|
||||
((ui_room_extra_t *) that->data)->flag1 = false;
|
||||
return NULL;
|
||||
|
||||
}
|
||||
if (e.type == JINPUT_VALIDATED && !extra->file)
|
||||
{
|
||||
hashmap_t *msg = utils_new_hashmap();
|
||||
m_event_t *e;
|
||||
|
||||
|
||||
hashmap_t *relations = utils_new_hashmap();
|
||||
hashmap_t *reply = utils_new_hashmap();
|
||||
utils_hashmap_set(
|
||||
reply,
|
||||
"event_id",
|
||||
utils_string_as_json(
|
||||
utils_strcpy(extra->replying->event_id)
|
||||
)
|
||||
);
|
||||
utils_hashmap_set(
|
||||
relations,
|
||||
"m.in_reply_to", utils_object_as_json(reply)
|
||||
);
|
||||
utils_hashmap_set(
|
||||
msg,
|
||||
"body",
|
||||
utils_string_as_json(
|
||||
utils_strcpy((char *) jinput_value(extra->input))
|
||||
)
|
||||
"m.relates_to", utils_object_as_json(relations)
|
||||
);
|
||||
|
||||
}
|
||||
utils_hashmap_set(
|
||||
msg,
|
||||
"body",
|
||||
utils_string_as_json(
|
||||
utils_strcpy((char *) jinput_value(extra->input))
|
||||
)
|
||||
);
|
||||
jinput_clear(extra->input);
|
||||
matrix_send_event(
|
||||
extra->user, extra->room,
|
||||
"m.room.message", msg
|
||||
);
|
||||
e = utils_array_get(
|
||||
extra->room->timeline,
|
||||
utils_array_size(extra->room->timeline) - 1
|
||||
);
|
||||
|
||||
extra->replying = NULL;
|
||||
|
||||
return e;
|
||||
}
|
||||
static void manage_command(ui_screen_t *that, command_t *cmd)
|
||||
{
|
||||
ui_room_extra_t *extra = that->data;
|
||||
|
||||
if (!strcmp(cmd->command, "punch"))
|
||||
{
|
||||
/* TODO: Actual punch MSC */
|
||||
char *punched = utils_array_get(cmd->arguments, 0);
|
||||
hashmap_t *msg;
|
||||
m_event_t *e;
|
||||
if (!punched)
|
||||
{
|
||||
return;
|
||||
}
|
||||
msg = utils_new_hashmap();
|
||||
|
||||
utils_hashmap_set(
|
||||
msg, "body",
|
||||
utils_string_as_json(utils_strcat("punches ", punched))
|
||||
);
|
||||
utils_hashmap_set(
|
||||
msg,
|
||||
"msgtype",
|
||||
utils_string_as_json(
|
||||
utils_strcpy("m.text")
|
||||
)
|
||||
utils_string_as_json(utils_strcpy("m.emote"))
|
||||
);
|
||||
jinput_clear(extra->input);
|
||||
matrix_send_event(
|
||||
|
@ -445,6 +468,268 @@ void * ui_room_event(ui_screen_t *that, jevent e)
|
|||
that->owner->waiting = true;
|
||||
matrix_update_room_history(extra->user, extra->room, e, 5);
|
||||
that->owner->waiting = false;
|
||||
}
|
||||
if (!strcmp(cmd->command, "fx"))
|
||||
{
|
||||
hashmap_t *msg;
|
||||
m_event_t *e;
|
||||
|
||||
msg = utils_new_hashmap();
|
||||
|
||||
utils_hashmap_set(
|
||||
msg, "body",
|
||||
utils_string_as_json(utils_strcat("Sent from my ", "fx-CG50"))
|
||||
);
|
||||
utils_hashmap_set(
|
||||
msg,
|
||||
"msgtype",
|
||||
utils_string_as_json(utils_strcpy("m.text"))
|
||||
);
|
||||
jinput_clear(extra->input);
|
||||
matrix_send_event(
|
||||
extra->user, extra->room,
|
||||
"m.room.message", msg
|
||||
);
|
||||
e = utils_array_get(
|
||||
extra->room->timeline,
|
||||
utils_array_size(extra->room->timeline) - 1
|
||||
);
|
||||
that->owner->waiting = true;
|
||||
matrix_update_room_history(extra->user, extra->room, e, 5);
|
||||
that->owner->waiting = false;
|
||||
}
|
||||
if (!strcmp(cmd->command, "myroomnick") || !strcmp(cmd->command, "rn"))
|
||||
{
|
||||
char *nick = utils_array_get(cmd->arguments, 0);
|
||||
if (!nick)
|
||||
{
|
||||
return;
|
||||
}
|
||||
matrix_set_nick(extra->user, extra->room, nick);
|
||||
}
|
||||
if (!strcmp(cmd->command, "reply") || !strcmp(cmd->command, "r"))
|
||||
{
|
||||
int selected = jmlist_selected(extra->timeline);
|
||||
jmlist_item *i = utils_array_get(extra->timeline->arr, selected);
|
||||
item_extra_t *ie = i->data;
|
||||
m_event_t *e = ie->event;
|
||||
|
||||
/* TODO: A 'lil bit of formatting when this is set to anything */
|
||||
extra->replying = e;
|
||||
}
|
||||
if (!strcmp(cmd->command, "delete") || !strcmp(cmd->command, "del"))
|
||||
{
|
||||
char *reason = "Requested by user";
|
||||
|
||||
int selected = jmlist_selected(extra->timeline);
|
||||
jmlist_item *i = utils_array_get(extra->timeline->arr, selected);
|
||||
item_extra_t *ie = i->data;
|
||||
m_event_t *e = ie->event;
|
||||
|
||||
if (utils_array_size(cmd->arguments) > 0)
|
||||
{
|
||||
reason = utils_array_get(cmd->arguments, 0);
|
||||
}
|
||||
|
||||
if (strcmp(e->sender, extra->user->id))
|
||||
{
|
||||
/* Yes, I know about power levels, but I am NOT
|
||||
* going to try and manage that */
|
||||
return;
|
||||
}
|
||||
matrix_redact(extra->user, e, reason);
|
||||
/* Rerender the event, to make sure the user knows it's redacted. */
|
||||
jmlist_redo(extra->timeline, selected);
|
||||
}
|
||||
if (!strcmp(cmd->command, "download") || !strcmp(cmd->command, "dl"))
|
||||
{
|
||||
int selected = jmlist_selected(extra->timeline);
|
||||
jmlist_item *i = utils_array_get(extra->timeline->arr, selected);
|
||||
item_extra_t *ie = i->data;
|
||||
m_event_t *e = ie->event;
|
||||
char *data, *body, *url, *msgtype;
|
||||
size_t len = 0;
|
||||
|
||||
if (strcmp(e->type, "m.room.message"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
msgtype = utils_json_as_string(
|
||||
utils_hashmap_get(e->content, "msgtype")
|
||||
);
|
||||
if (strcmp(msgtype, "m.file") &&
|
||||
strcmp(msgtype, "m.image") &&
|
||||
strcmp(msgtype, "m.audio"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
body = utils_json_as_string(
|
||||
utils_hashmap_get(e->content, "body")
|
||||
);
|
||||
body = utils_strcat("/", body);
|
||||
url = utils_json_as_string(
|
||||
utils_hashmap_get(e->content, "url")
|
||||
);
|
||||
|
||||
data = matrix_get_file(ie->extra->user, url, &len);
|
||||
utils_write_file(body, data, len);
|
||||
|
||||
free(data);
|
||||
free(body);
|
||||
}
|
||||
if (!strcmp(cmd->command, "9") || !strcmp(cmd->command, "cirno"))
|
||||
{
|
||||
rtc_time_t time;
|
||||
rtc_get_time(&time);
|
||||
|
||||
if (time.month_day != 9 || time.month != 9)
|
||||
{
|
||||
/* This command only works on 9/9/AAAA */
|
||||
return;
|
||||
}
|
||||
easter_strongest();
|
||||
}
|
||||
if (!strcmp(cmd->command, "exit"))
|
||||
{
|
||||
ui_destroy_screen(that->owner);
|
||||
}
|
||||
}
|
||||
void * ui_room_event(ui_screen_t *that, jevent e)
|
||||
{
|
||||
ui_room_extra_t *extra = that->data;
|
||||
if (extra->time_head)
|
||||
{
|
||||
if (e.key.key == KEY_EXIT && e.key.type == KEYEV_UP)
|
||||
{
|
||||
jwidget_destroy(extra->time_head);
|
||||
extra->time_head = NULL;
|
||||
return extra->on_timeline ?
|
||||
(void *) extra->timeline :
|
||||
(void *) extra->input ;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (e.type == JMLIST_ITEM_CHOSEN && !extra->file)
|
||||
{
|
||||
/* TODO */
|
||||
int selected = jmlist_selected(extra->timeline);
|
||||
jmlist_item *i = utils_array_get(extra->timeline->arr, selected);
|
||||
item_extra_t *ie = i->data;
|
||||
|
||||
if (!ie)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
ui_room_act(ie);
|
||||
return NULL;
|
||||
}
|
||||
if (e.type == JMLIST_ITEM_OVERFLEW && !extra->file)
|
||||
{
|
||||
if (jmlist_selected(extra->timeline) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
ui_update_history(that);
|
||||
extra->timeline->widget.update = 1;
|
||||
return extra->timeline;
|
||||
}
|
||||
if (e.type == JMLIST_ITEM_NOP && !extra->file)
|
||||
{
|
||||
ui_room_extra_t *extra = that->data;
|
||||
m_event_t *e;
|
||||
ssize_t i;
|
||||
size_t from;
|
||||
|
||||
uint8_t code = extra->input->mode;
|
||||
|
||||
e = utils_array_get(extra->room->timeline, 0);
|
||||
|
||||
that->owner->waiting = true;
|
||||
matrix_update_room_history(extra->user, extra->room, e, 10);
|
||||
|
||||
from = is_in_timeline(extra->room, e->event_id);
|
||||
if (from != 0)
|
||||
{
|
||||
for (i = from - 1; i >= 0; i--)
|
||||
{
|
||||
m_event_t *e = utils_array_get(
|
||||
extra->room->timeline,
|
||||
i
|
||||
);
|
||||
item_extra_t *ie = malloc(sizeof(item_extra_t));
|
||||
|
||||
ie->event = e;
|
||||
ie->screen = that;
|
||||
ie->extra = that->data;
|
||||
jmlist_add_item(extra->timeline, ie);
|
||||
|
||||
if (matrix_get_relation_type(e))
|
||||
{
|
||||
jmlist_item *item;
|
||||
item_extra_t *itemextra;
|
||||
int event = find_event_in_timeline(
|
||||
extra->timeline,
|
||||
matrix_get_relation_source(e)
|
||||
);
|
||||
if (event == -1)
|
||||
{
|
||||
log_text("Couldn't find!");
|
||||
continue;
|
||||
}
|
||||
item = utils_array_get(extra->timeline->arr, event);
|
||||
itemextra = item->data;
|
||||
|
||||
matrix_add_relation(
|
||||
itemextra->event->event_id,
|
||||
extra->room,
|
||||
e
|
||||
);
|
||||
|
||||
jmlist_redo(extra->timeline, event);
|
||||
log_text("Have to redo(%d->%s)!", event, itemextra->event->event_id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
that->owner->waiting = false;
|
||||
extra->input->mode = code; /* It seems like the input doesn't keep
|
||||
its mode, somehow??????? */
|
||||
((ui_room_extra_t *) that->data)->flag1 = false;
|
||||
|
||||
if (extra->jfk->labels)
|
||||
{
|
||||
rtc_time_t t;
|
||||
rtc_get_time(&t);
|
||||
char *new;
|
||||
free((void *) extra->jfk->labels);
|
||||
new = utils_sprintf(
|
||||
"@MESG;@ROOM;/FILE;#%02d:%02d;;@EXIT",
|
||||
t.hours, t.minutes
|
||||
);
|
||||
jfkeys_set(extra->jfk, new);
|
||||
}
|
||||
return NULL;
|
||||
|
||||
}
|
||||
if (e.type == JINPUT_VALIDATED && !extra->file)
|
||||
{
|
||||
m_event_t *event;
|
||||
const char *input = jinput_value(extra->input);
|
||||
if (strlen(input) > 0 && *input == '/')
|
||||
{
|
||||
command_t *cmd = command_parse((char *)input);
|
||||
if (cmd)
|
||||
{
|
||||
manage_command(that, cmd);
|
||||
command_free(cmd);
|
||||
return extra->timeline;
|
||||
}
|
||||
return extra->timeline;
|
||||
}
|
||||
event = send_msg(extra);
|
||||
that->owner->waiting = true;
|
||||
matrix_update_room_history(extra->user, extra->room, event, 5);
|
||||
that->owner->waiting = false;
|
||||
return extra->timeline;
|
||||
}
|
||||
|
||||
|
@ -458,12 +743,14 @@ void * ui_room_event(ui_screen_t *that, jevent e)
|
|||
if (e.key.key == KEY_F1 && e.key.type == KEYEV_UP && !extra->file)
|
||||
{
|
||||
extra->on_timeline = !extra->on_timeline;
|
||||
return (!extra->on_timeline) ? extra->input : extra->timeline;
|
||||
return (!extra->on_timeline) ?
|
||||
(void *) extra->input :
|
||||
(void *) extra->timeline ;
|
||||
}
|
||||
if (e.key.key == KEY_F3 && e.key.type == KEYEV_UP && !extra->file)
|
||||
{
|
||||
int null;
|
||||
extra->file = jfileselect_create(that->widget);
|
||||
extra->file = jfileselect_create(extra->main);
|
||||
|
||||
jwidget_set_floating(extra->file, true);
|
||||
jwidget_set_background(extra->file, C_WHITE);
|
||||
|
@ -482,26 +769,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)
|
||||
if (e.key.key == KEY_F4 && 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));
|
||||
}
|
||||
jlabel *text;
|
||||
|
||||
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
|
||||
extra->time_head = jwidget_create(that->widget);
|
||||
jwidget_set_floating(extra->time_head, true);
|
||||
jwidget_set_fixed_size(extra->time_head, DWIDTH - 20, DHEIGHT - 90);
|
||||
jwidget_set_border(extra->time_head, J_BORDER_SOLID, 1, C_BLACK);
|
||||
jwidget_set_background(extra->time_head, C_WHITE);
|
||||
extra->time_head->x = (DWIDTH - extra->time_head->max_w) / 2;
|
||||
extra->time_head->y = (DHEIGHT - extra->time_head->max_h) / 2;
|
||||
|
||||
text = jlabel_create(
|
||||
"Hey, sillyhead!" "\n"
|
||||
"This button doesn't serve any purpose, " "\n"
|
||||
"its just here to show the date!" "\n\n"
|
||||
"So yeah, press EXIT to get out of there "
|
||||
"kthxbye" "\n\n",
|
||||
extra->time_head
|
||||
);
|
||||
jwidget_set_minimum_size(extra->charpick, DWIDTH, DHEIGHT - 35);
|
||||
jmlist_select(extra->charpick, 1);
|
||||
return extra->charpick;
|
||||
jwidget_set_stretch(text, 1, 1, false);
|
||||
jwidget_set_padding(text, 1, 1, 1, 1);
|
||||
|
||||
return extra->time_head;
|
||||
}
|
||||
if (e.key.key == KEY_F6 && e.key.type == KEYEV_UP && !extra->file)
|
||||
if ((e.key.key == KEY_F6 || e.key.key == KEY_EXIT) &&
|
||||
e.key.type == KEYEV_UP && !extra->file)
|
||||
{
|
||||
ui_destroy_screen(that->owner);
|
||||
return NULL;
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
#include "matrix.h"
|
||||
#include <ui_generators.h>
|
||||
|
||||
#include <justui/jinput.h>
|
||||
#include <justui/jlabel.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <utils.h>
|
||||
#include <log.h>
|
||||
#include <ui.h>
|
||||
typedef struct chunk_extra {
|
||||
m_room_chunk_t *chunk;
|
||||
ui_session_t *session;
|
||||
} chunk_extra_t;
|
||||
|
||||
static void set(jmlist_item *item, int idx)
|
||||
{
|
||||
jlabel *room_name, *room_topic;
|
||||
jwidget *vbox;
|
||||
chunk_extra_t *extra = item->data;
|
||||
m_room_chunk_t *chunk = extra->chunk;
|
||||
|
||||
jwidget_set_stretch(item->widget, 1, 0, false);
|
||||
jlayout_set_hbox(item->widget)->spacing = 1;
|
||||
|
||||
if (chunk->avatar_url)
|
||||
{
|
||||
matrix_image_from_mxc(
|
||||
item->widget,
|
||||
extra->session->user,
|
||||
chunk->avatar_url,
|
||||
32
|
||||
);
|
||||
}
|
||||
|
||||
vbox = jwidget_create(item->widget);
|
||||
jwidget_set_stretch(vbox, 1, 0, false);
|
||||
jlayout_set_vbox(vbox)->spacing = 1;
|
||||
|
||||
room_name = jlabel_create("", vbox);
|
||||
jwidget_set_stretch(room_name, 1, 0, false);
|
||||
jlabel_asprintf(room_name, "%s", chunk->room_id);
|
||||
if (chunk->canonical_alias)
|
||||
{
|
||||
jlabel_asprintf(room_name, "%s", chunk->canonical_alias);
|
||||
}
|
||||
if (chunk->name)
|
||||
{
|
||||
jlabel_asprintf(room_name, "%s", chunk->name);
|
||||
}
|
||||
room_topic = jlabel_create("", vbox);
|
||||
if (chunk->topic)
|
||||
{
|
||||
jlabel_asprintf(room_topic, "%s", chunk->topic);
|
||||
}
|
||||
|
||||
(void) idx;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
jmlist *serv_list;
|
||||
jinput *server_name;
|
||||
} roomdir_extra_t;
|
||||
void * ui_roomdir_init(ui_screen_t *that)
|
||||
{
|
||||
jwidget *main = jwidget_create(that->owner->stack);
|
||||
jinput *server_name;
|
||||
jmlist *serv_list;
|
||||
roomdir_extra_t *extra = malloc(sizeof(roomdir_extra_t));
|
||||
|
||||
jlayout_set_vbox(main)->spacing = 1;
|
||||
jwidget_set_padding(main, 0, 0, 0, 0);
|
||||
jwidget_set_stretch(main, 15, 15, false);
|
||||
|
||||
server_name = jinput_create("Server: ", 20, main);
|
||||
jwidget_set_stretch(server_name, 1, 0, false);
|
||||
jwidget_set_border(server_name, J_BORDER_SOLID, 1, C_BLACK);
|
||||
|
||||
serv_list = jmlist_create(main, set, NULL); /* TODO */
|
||||
|
||||
/* TODO */
|
||||
extra->server_name = server_name;
|
||||
extra->serv_list = serv_list;
|
||||
that->data = extra;
|
||||
|
||||
return server_name;
|
||||
}
|
||||
void * ui_roomdir_event(ui_screen_t *that, jevent e)
|
||||
{
|
||||
/* TODO */
|
||||
roomdir_extra_t *extra = that->data;
|
||||
if (e.type == JINPUT_VALIDATED)
|
||||
{
|
||||
char *v = (char *) jinput_value(extra->server_name);
|
||||
array_t *dir = matrix_get_directory(that->owner->user, v, 20);
|
||||
size_t i;
|
||||
for (i = 0; i < utils_array_size(dir); i++)
|
||||
{
|
||||
m_room_chunk_t *chunk = utils_array_get(dir, i);
|
||||
chunk_extra_t *c_extra = malloc(sizeof(*c_extra));
|
||||
|
||||
c_extra->chunk = chunk;
|
||||
c_extra->session = that->owner;
|
||||
jmlist_add_item(extra->serv_list, c_extra);
|
||||
log_text("id=%s", chunk->room_id);
|
||||
}
|
||||
jmlist_select(extra->serv_list, 0);
|
||||
utils_free_array(dir);
|
||||
return extra->serv_list;
|
||||
}
|
||||
if (e.type == JMLIST_ITEM_CHOSEN)
|
||||
{
|
||||
int selected = jmlist_selected(extra->serv_list);
|
||||
jmlist_item *item = utils_array_get(extra->serv_list->arr, selected);
|
||||
chunk_extra_t *c_extra = item->data;
|
||||
m_room_chunk_t *chunk = c_extra->chunk;
|
||||
char *room_id = chunk->room_id;
|
||||
m_room_t *room;
|
||||
|
||||
log_text("Joining id='%s'", room_id);
|
||||
room = matrix_join_room(c_extra->session->user, room_id);
|
||||
if (!room)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c_extra->session->rooms_dirty = true;
|
||||
c_extra->session->new_id = room->id;
|
||||
ui_destroy_screen(that->owner);
|
||||
return NULL;
|
||||
}
|
||||
if (e.key.key == KEY_EXIT)
|
||||
{
|
||||
ui_destroy_screen(that->owner);
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#include <ui.h>
|
||||
|
||||
#include <gint/defs/timeout.h>
|
||||
#include <gint/usb-ff-bulk.h>
|
||||
#include <gint/usb.h>
|
||||
#include <gint/defs/timeout.h>
|
||||
|
||||
#include <justui/jwidget.h>
|
||||
#include <justui/jlabel.h>
|
||||
|
@ -16,6 +16,7 @@
|
|||
#include <ui_generators.h>
|
||||
#include <matrix.h>
|
||||
#include <utils.h>
|
||||
#include <log.h>
|
||||
|
||||
typedef struct ui_userroom {
|
||||
m_user_t *user;
|
||||
|
@ -27,31 +28,39 @@ extern bopti_image_t user;
|
|||
static void set(jmlist_item *item, int idx)
|
||||
{
|
||||
char *id;
|
||||
char *name;
|
||||
char *name, *avatar;
|
||||
size_t joined;
|
||||
jwidget *content_box;
|
||||
jlabel *room_label;
|
||||
|
||||
ui_userroom_t *data = item->data;
|
||||
id = data->room->id;
|
||||
joined = data->room->joined;
|
||||
name = matrix_resolve_name(data->user, data->room);
|
||||
avatar = matrix_resolve_avatar(data->user, data->room);
|
||||
m_event_t *e = utils_array_get(data->room->timeline, 0);
|
||||
|
||||
|
||||
jwidget_set_stretch(item->widget, 1, 0, false);
|
||||
jlayout_set_vbox(item->widget)->spacing = 1;
|
||||
jlayout_set_hbox(item->widget)->spacing = 1;
|
||||
|
||||
room_label = jlabel_create("", item->widget);
|
||||
matrix_image_from_mxc(item->widget, data->user, avatar, 32);
|
||||
|
||||
content_box = jwidget_create(item->widget);
|
||||
jwidget_set_stretch(content_box, 1, 0, false);
|
||||
jlayout_set_vbox(content_box)->spacing = 1;
|
||||
|
||||
room_label = jlabel_create("", content_box);
|
||||
jlabel_asprintf(room_label, "%s", name ? name : id);
|
||||
free(name);
|
||||
jwidget_set_stretch(room_label, 1, 0, false);
|
||||
|
||||
if (e && !strcmp(e->type, "m.room.message"))
|
||||
{
|
||||
jlabel *message = jlabel_create("", item->widget);
|
||||
jwidget *hbox = jwidget_create(item->widget);
|
||||
jlabel *message = jlabel_create("", content_box);
|
||||
jwidget *hbox = jwidget_create(content_box);
|
||||
jwidget *hpad = jwidget_create(hbox);
|
||||
jlabel *user_count;
|
||||
jpainted *user_painted;
|
||||
jwidget *ulist = jwidget_create(hbox);
|
||||
char *body = utils_json_as_string(
|
||||
utils_hashmap_get(e->content, "body")
|
||||
|
@ -67,7 +76,7 @@ static void set(jmlist_item *item, int idx)
|
|||
jlayout_set_hbox(hbox)->spacing = 2;
|
||||
|
||||
user_count = jlabel_create("", ulist);
|
||||
user_painted = ui_image(ulist, &user);
|
||||
ui_image(ulist, &user);
|
||||
jlayout_set_hbox(ulist)->spacing = 5;
|
||||
jlabel_asprintf(user_count, "%lu", joined);
|
||||
|
||||
|
@ -80,7 +89,7 @@ static void set(jmlist_item *item, int idx)
|
|||
jwidget_set_stretch(message, 1, 0, false);
|
||||
jwidget_set_maximum_width(message, DWIDTH - 10);
|
||||
}
|
||||
|
||||
(void) idx;
|
||||
}
|
||||
|
||||
void * ui_rooms_init(ui_screen_t *that)
|
||||
|
@ -95,7 +104,7 @@ void * ui_rooms_init(ui_screen_t *that)
|
|||
char *key;
|
||||
void *data;
|
||||
|
||||
size_t i;
|
||||
that->owner->rooms_dirty = false;
|
||||
|
||||
wid = jwidget_create(that->owner->stack);
|
||||
jlayout_set_vbox(wid)->spacing = 1;
|
||||
|
@ -123,7 +132,7 @@ 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);
|
||||
jfk = jfkeys_create("/INFOS;@DIRECTORY;;;;#ACCOUNT", wid);
|
||||
jwidget_set_stretch(jfk, 1, 0, false);
|
||||
|
||||
that->data = rooms_list;
|
||||
|
@ -155,26 +164,36 @@ void * ui_rooms_event(ui_screen_t *that, jevent e)
|
|||
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)
|
||||
{
|
||||
ui_screen_t *dir;
|
||||
dir = ui_new_screen(ui_roomdir_init, NULL, ui_roomdir_event);
|
||||
ui_add_screen(that->owner, dir);
|
||||
return NULL;
|
||||
}
|
||||
if (e.key.key == KEY_F6 && e.key.type == KEYEV_UP)
|
||||
{
|
||||
ui_screen_t *accinfo;
|
||||
|
||||
}
|
||||
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 */
|
||||
accinfo = ui_new_screen(ui_accinfo_init, ui_accinfo_focus, ui_accinfo_event);
|
||||
ui_add_screen(that->owner, accinfo);
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void * ui_rooms_focus(ui_screen_t *that)
|
||||
{
|
||||
hashmap_t *rooms = that->owner->user->rooms;
|
||||
if (that->owner->rooms_dirty)
|
||||
{
|
||||
m_room_t *room = utils_hashmap_get(rooms, that->owner->new_id);
|
||||
ui_userroom_t *pack = malloc(sizeof(ui_userroom_t));
|
||||
pack->room = room;
|
||||
pack->user = that->owner->user;
|
||||
jmlist_add_item(that->data, pack);
|
||||
|
||||
that->owner->rooms_dirty = false;
|
||||
}
|
||||
return that->data;
|
||||
}
|
||||
|
|
17
src/usb.c
|
@ -17,6 +17,7 @@
|
|||
void usb_init(int *out, int *in)
|
||||
{
|
||||
timeout_t tm;
|
||||
static bool first_time = true;
|
||||
|
||||
usb_interface_t const *intf[] = { &usb_ff_bulk, NULL };
|
||||
usb_open(intf, GINT_CALL_NULL);
|
||||
|
@ -25,11 +26,15 @@ void usb_init(int *out, int *in)
|
|||
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 (first_time)
|
||||
{
|
||||
easter_dvd_frame(
|
||||
"Uplinking with USB (run mastrix on your PC now)..."
|
||||
);
|
||||
while (!timeout_elapsed(&tm1));
|
||||
}
|
||||
}
|
||||
first_time = false;
|
||||
|
||||
if (!usb_is_open())
|
||||
{
|
||||
|
@ -59,7 +64,7 @@ int usb_except_message(const char *app, const char *type, usb_except_cb cb)
|
|||
{
|
||||
usb_fxlink_header_t header;
|
||||
timeout_t tm;
|
||||
static volatile uint64_t idles = 0;
|
||||
static volatile int64_t idles = 0;
|
||||
static volatile int64_t idlemax = -1;
|
||||
|
||||
int rc;
|
||||
|
@ -89,7 +94,7 @@ int usb_except_message(const char *app, const char *type, usb_except_cb cb)
|
|||
idles++;
|
||||
return idlemax == -1 ? 0 : (idles > idlemax ? -2 : 0);
|
||||
}
|
||||
if (rc < sizeof(usb_fxlink_header_t))
|
||||
if ((unsigned int) rc < sizeof(usb_fxlink_header_t))
|
||||
{
|
||||
idles++;
|
||||
return idlemax == -1 ? 0 : (idles > idlemax ? -2 : 0);
|
||||
|
|