400 lines
9.7 KiB
C
400 lines
9.7 KiB
C
#include <hikari/view_config.h>
|
|
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <ucl.h>
|
|
|
|
#include <hikari/geometry.h>
|
|
#include <hikari/memory.h>
|
|
#include <hikari/output.h>
|
|
#include <hikari/server.h>
|
|
#include <hikari/view.h>
|
|
|
|
static void
|
|
init_properties(struct hikari_view_properties *properties)
|
|
{
|
|
properties->group_name = NULL;
|
|
properties->sheet_nr = -1;
|
|
properties->mark = NULL;
|
|
properties->focus = false;
|
|
properties->invisible = false;
|
|
properties->floating = false;
|
|
properties->publicview = false;
|
|
|
|
hikari_position_config_init(&properties->position);
|
|
}
|
|
|
|
void
|
|
hikari_view_config_init(struct hikari_view_config *view_config)
|
|
{
|
|
view_config->app_id = NULL;
|
|
|
|
init_properties(&view_config->properties);
|
|
|
|
view_config->child_properties = &view_config->properties;
|
|
}
|
|
|
|
static void
|
|
fini_properties(struct hikari_view_properties *properties)
|
|
{
|
|
hikari_free(properties->group_name);
|
|
}
|
|
|
|
void
|
|
hikari_view_config_fini(struct hikari_view_config *view_config)
|
|
{
|
|
assert(view_config != NULL);
|
|
|
|
struct hikari_view_properties *properties = &view_config->properties;
|
|
struct hikari_view_properties *child_properties =
|
|
view_config->child_properties;
|
|
|
|
if (child_properties != properties) {
|
|
fini_properties(child_properties);
|
|
hikari_free(child_properties);
|
|
}
|
|
|
|
fini_properties(properties);
|
|
hikari_free(view_config->app_id);
|
|
}
|
|
|
|
struct hikari_sheet *
|
|
hikari_view_properties_resolve_sheet(struct hikari_view_properties *properties)
|
|
{
|
|
assert(properties != NULL);
|
|
|
|
struct hikari_sheet *sheet;
|
|
if (properties->sheet_nr != -1) {
|
|
sheet = hikari_server.workspace->sheets + properties->sheet_nr;
|
|
} else {
|
|
sheet = hikari_server.workspace->sheet;
|
|
}
|
|
|
|
return sheet;
|
|
}
|
|
|
|
struct hikari_group *
|
|
hikari_view_properties_resolve_group(
|
|
struct hikari_view_properties *properties, const char *app_id)
|
|
{
|
|
struct hikari_group *group;
|
|
|
|
if (properties->group_name != NULL && strlen(properties->group_name) > 0) {
|
|
group = hikari_server_find_or_create_group(properties->group_name);
|
|
} else {
|
|
group = hikari_server_find_or_create_group(app_id);
|
|
}
|
|
|
|
return group;
|
|
}
|
|
|
|
void
|
|
hikari_view_properties_resolve_position(
|
|
struct hikari_view_properties *properties,
|
|
struct hikari_view *view,
|
|
int *x,
|
|
int *y)
|
|
{
|
|
assert(properties != NULL);
|
|
|
|
struct hikari_output *output = hikari_server.workspace->output;
|
|
struct wlr_box *geometry = hikari_view_border_geometry(view);
|
|
|
|
switch (properties->position.type) {
|
|
case HIKARI_POSITION_CONFIG_TYPE_ABSOLUTE:
|
|
*x = properties->position.config.absolute.x;
|
|
*y = properties->position.config.absolute.y;
|
|
break;
|
|
|
|
case HIKARI_POSITION_CONFIG_TYPE_AUTO:
|
|
*x = hikari_server.cursor.wlr_cursor->x - output->geometry.x;
|
|
*y = hikari_server.cursor.wlr_cursor->y - output->geometry.y;
|
|
break;
|
|
|
|
case HIKARI_POSITION_CONFIG_TYPE_RELATIVE:
|
|
switch (properties->position.config.relative) {
|
|
case HIKARI_POSITION_CONFIG_RELATIVE_BOTTOM_LEFT:
|
|
hikari_geometry_position_bottom_left(
|
|
geometry, &output->usable_area, x, y);
|
|
break;
|
|
|
|
case HIKARI_POSITION_CONFIG_RELATIVE_BOTTOM_MIDDLE:
|
|
hikari_geometry_position_bottom_middle(
|
|
geometry, &output->usable_area, x, y);
|
|
break;
|
|
|
|
case HIKARI_POSITION_CONFIG_RELATIVE_BOTTOM_RIGHT:
|
|
hikari_geometry_position_bottom_right(
|
|
geometry, &output->usable_area, x, y);
|
|
break;
|
|
|
|
case HIKARI_POSITION_CONFIG_RELATIVE_CENTER:
|
|
hikari_geometry_position_center(geometry, &output->usable_area, x, y);
|
|
break;
|
|
|
|
case HIKARI_POSITION_CONFIG_RELATIVE_CENTER_LEFT:
|
|
hikari_geometry_position_center_left(
|
|
geometry, &output->usable_area, x, y);
|
|
break;
|
|
|
|
case HIKARI_POSITION_CONFIG_RELATIVE_CENTER_RIGHT:
|
|
hikari_geometry_position_center_right(
|
|
geometry, &output->usable_area, x, y);
|
|
break;
|
|
|
|
case HIKARI_POSITION_CONFIG_RELATIVE_TOP_LEFT:
|
|
hikari_geometry_position_top_left(
|
|
geometry, &output->usable_area, x, y);
|
|
break;
|
|
|
|
case HIKARI_POSITION_CONFIG_RELATIVE_TOP_MIDDLE:
|
|
hikari_geometry_position_top_middle(
|
|
geometry, &output->usable_area, x, y);
|
|
break;
|
|
|
|
case HIKARI_POSITION_CONFIG_RELATIVE_TOP_RIGHT:
|
|
hikari_geometry_position_top_right(
|
|
geometry, &output->usable_area, x, y);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool
|
|
parse_property(struct hikari_view_properties *properties,
|
|
const char *key,
|
|
const ucl_object_t *property_obj)
|
|
{
|
|
bool success = false;
|
|
|
|
if (!strcmp(key, "group")) {
|
|
const char *group_name;
|
|
|
|
if (!ucl_object_tostring_safe(property_obj, &group_name)) {
|
|
fprintf(stderr,
|
|
"configuration error: expected string for \"views\" "
|
|
"\"group\"\n");
|
|
goto done;
|
|
}
|
|
|
|
if (strlen(group_name) == 0) {
|
|
fprintf(stderr,
|
|
"configuration error: expected non-empty string for \"views\" "
|
|
"\"group\"\n");
|
|
goto done;
|
|
}
|
|
|
|
hikari_free(properties->group_name);
|
|
properties->group_name = strdup(group_name);
|
|
} else if (!strcmp(key, "sheet")) {
|
|
int64_t sheet_nr;
|
|
if (!ucl_object_toint_safe(property_obj, &sheet_nr)) {
|
|
fprintf(stderr,
|
|
"configuration error: expected integer for \"views\" "
|
|
"\"sheet\"\n");
|
|
goto done;
|
|
}
|
|
|
|
properties->sheet_nr = sheet_nr;
|
|
} else if (!strcmp(key, "mark")) {
|
|
const char *mark_name;
|
|
|
|
if (!ucl_object_tostring_safe(property_obj, &mark_name)) {
|
|
fprintf(stderr,
|
|
"configuration error: expected string for \"views\" \"mark\"");
|
|
goto done;
|
|
}
|
|
|
|
if (strlen(mark_name) != 1) {
|
|
fprintf(stderr,
|
|
"configuration error: invalid \"mark\" register \"%s\" for "
|
|
"\"views\"\n",
|
|
mark_name);
|
|
goto done;
|
|
}
|
|
|
|
properties->mark = &hikari_marks[mark_name[0] - 'a'];
|
|
} else if (!strcmp(key, "position")) {
|
|
if (!hikari_position_config_parse(&properties->position, property_obj)) {
|
|
goto done;
|
|
}
|
|
} else if (!strcmp(key, "focus")) {
|
|
bool focus;
|
|
|
|
if (!ucl_object_toboolean_safe(property_obj, &focus)) {
|
|
fprintf(stderr,
|
|
"configuration error: expected boolean for \"views\" "
|
|
"\"focus\"\n");
|
|
goto done;
|
|
}
|
|
|
|
properties->focus = focus;
|
|
} else if (!strcmp(key, "invisible")) {
|
|
bool invisible;
|
|
|
|
if (!ucl_object_toboolean_safe(property_obj, &invisible)) {
|
|
fprintf(stderr,
|
|
"configuration error: expected boolean for \"views\" "
|
|
"\"invisible\"\n");
|
|
goto done;
|
|
}
|
|
|
|
properties->invisible = invisible;
|
|
} else if (!strcmp(key, "floating")) {
|
|
bool floating;
|
|
|
|
if (!ucl_object_toboolean_safe(property_obj, &floating)) {
|
|
fprintf(stderr,
|
|
"configuration error: expected boolean for \"views\" "
|
|
"\"floating\"\n");
|
|
goto done;
|
|
}
|
|
|
|
properties->floating = floating;
|
|
} else if (!strcmp(key, "public")) {
|
|
bool publicview;
|
|
|
|
if (!ucl_object_toboolean_safe(property_obj, &publicview)) {
|
|
fprintf(stderr,
|
|
"configuration error: expected boolean for \"views\" "
|
|
"\"public\"\n");
|
|
goto done;
|
|
}
|
|
|
|
properties->publicview = publicview;
|
|
} else {
|
|
fprintf(stderr, "configuration error: unkown \"views\" key \"%s\"\n", key);
|
|
goto done;
|
|
}
|
|
|
|
success = true;
|
|
|
|
done:
|
|
|
|
return success;
|
|
}
|
|
|
|
static bool
|
|
parse_properties(struct hikari_view_properties *properties,
|
|
const ucl_object_t *view_config_obj)
|
|
{
|
|
bool success = false;
|
|
ucl_object_iter_t it = ucl_object_iterate_new(view_config_obj);
|
|
|
|
const ucl_object_t *cur;
|
|
while ((cur = ucl_object_iterate_safe(it, false)) != NULL) {
|
|
const char *key = ucl_object_key(cur);
|
|
|
|
if (!strcmp(key, "inherit")) {
|
|
continue;
|
|
}
|
|
|
|
if (!parse_property(properties, key, cur)) {
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
success = true;
|
|
|
|
done:
|
|
ucl_object_iterate_free(it);
|
|
|
|
return success;
|
|
}
|
|
|
|
static bool
|
|
parse_inherited_properties(struct hikari_view_properties *properties,
|
|
struct hikari_view_properties *child_properties,
|
|
const ucl_object_t *inherit_obj)
|
|
{
|
|
bool success = false;
|
|
ucl_object_iter_t it = ucl_object_iterate_new(inherit_obj);
|
|
|
|
const ucl_object_t *cur;
|
|
while ((cur = ucl_object_iterate_safe(it, false)) != NULL) {
|
|
ucl_type_t type = ucl_object_type(cur);
|
|
const char *attr;
|
|
|
|
switch (type) {
|
|
case UCL_STRING:
|
|
if (!ucl_object_tostring_safe(cur, &attr)) {
|
|
goto done;
|
|
}
|
|
|
|
if (!strcmp(attr, "group")) {
|
|
if (properties->group_name != NULL) {
|
|
child_properties->group_name = strdup(properties->group_name);
|
|
} else {
|
|
child_properties->group_name = NULL;
|
|
}
|
|
} else if (!strcmp(attr, "sheet")) {
|
|
child_properties->sheet_nr = properties->sheet_nr;
|
|
} else if (!strcmp(attr, "mark")) {
|
|
child_properties->mark = properties->mark;
|
|
} else if (!strcmp(attr, "position")) {
|
|
memcpy(&child_properties->position,
|
|
&properties->position,
|
|
sizeof(struct hikari_position_config));
|
|
} else if (!strcmp(attr, "focus")) {
|
|
child_properties->focus = properties->focus;
|
|
} else if (!strcmp(attr, "invisible")) {
|
|
child_properties->invisible = properties->invisible;
|
|
} else if (!strcmp(attr, "floating")) {
|
|
child_properties->floating = properties->floating;
|
|
} else if (!strcmp(attr, "publicview")) {
|
|
child_properties->publicview = properties->publicview;
|
|
}
|
|
break;
|
|
|
|
case UCL_OBJECT:
|
|
parse_properties(child_properties, cur);
|
|
break;
|
|
|
|
default:
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
success = true;
|
|
|
|
done:
|
|
ucl_object_iterate_free(it);
|
|
|
|
return success;
|
|
}
|
|
|
|
bool
|
|
hikari_view_config_parse(
|
|
struct hikari_view_config *view_config, const ucl_object_t *view_config_obj)
|
|
{
|
|
struct hikari_view_properties *properties = &view_config->properties;
|
|
bool success = false;
|
|
|
|
if (!parse_properties(properties, view_config_obj)) {
|
|
goto done;
|
|
}
|
|
|
|
const ucl_object_t *inherit_obj =
|
|
ucl_object_lookup(view_config_obj, "inherit");
|
|
|
|
if (inherit_obj != NULL) {
|
|
view_config->child_properties =
|
|
hikari_malloc(sizeof(struct hikari_view_properties));
|
|
|
|
struct hikari_view_properties *child_properties =
|
|
view_config->child_properties;
|
|
init_properties(child_properties);
|
|
|
|
if (!parse_inherited_properties(
|
|
properties, child_properties, inherit_obj)) {
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
success = true;
|
|
|
|
done:
|
|
|
|
return success;
|
|
}
|