Compare commits
6 Commits
46d0bc1670
...
836241c014
Author | SHA1 | Date | |
---|---|---|---|
836241c014 | |||
42779798fa | |||
fac46f74f6 | |||
11636b2754 | |||
0fefb31535 | |||
a2384822d8 |
22
src/config.c
22
src/config.c
@ -1,6 +1,6 @@
|
|||||||
#include "config.h"
|
|
||||||
#include "wm.h"
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@ -10,6 +10,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "wm.h"
|
||||||
|
|
||||||
void wm_cfg_init_def(Config *config)
|
void wm_cfg_init_def(Config *config)
|
||||||
{
|
{
|
||||||
@ -20,6 +24,20 @@ void wm_cfg_init_def(Config *config)
|
|||||||
config->focus_on_motion = true;
|
config->focus_on_motion = true;
|
||||||
|
|
||||||
wm_keybinds_init_def(config);
|
wm_keybinds_init_def(config);
|
||||||
|
|
||||||
|
char log_file_dir[PATH_MAX] = {0};
|
||||||
|
const char* log_file_name = "wm.json";
|
||||||
|
char *xdg_data_home = getenv("XDG_DATA_HOME");
|
||||||
|
|
||||||
|
if (!xdg_data_home) {
|
||||||
|
char *home = getenv("HOME");
|
||||||
|
assert(home);
|
||||||
|
snprintf(log_file_dir, sizeof(log_file_dir), "%s/.local/share", home);
|
||||||
|
} else {
|
||||||
|
strncpy(log_file_dir, xdg_data_home, PATH_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(config->log_path, PATH_MAX, "%s/%s", log_file_dir, log_file_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_keybinds_init_def(Config *config)
|
void wm_keybinds_init_def(Config *config)
|
||||||
|
@ -78,6 +78,7 @@ typedef struct {
|
|||||||
Keybind *keybinds;
|
Keybind *keybinds;
|
||||||
int kb_count;
|
int kb_count;
|
||||||
bool focus_on_motion;
|
bool focus_on_motion;
|
||||||
|
char log_path[PATH_MAX];
|
||||||
} Config;
|
} Config;
|
||||||
|
|
||||||
void wm_cfg_init_def(Config *config);
|
void wm_cfg_init_def(Config *config);
|
||||||
|
@ -105,7 +105,7 @@ void wm_maprequest_handler(Wm *wm, XMapRequestEvent e)
|
|||||||
wm_client_focus(wm, c);
|
wm_client_focus(wm, c);
|
||||||
|
|
||||||
if (wm->log_after_maprequest) {
|
if (wm->log_after_maprequest) {
|
||||||
wm_log_state(wm, "after wm_kb_spawn", WM_LOGFILENAME);
|
wm_log_state(wm, "after wm_kb_spawn", wm->config.log_path);
|
||||||
wm->log_after_maprequest = false;
|
wm->log_after_maprequest = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
510
src/tests.c
510
src/tests.c
@ -1,11 +1,24 @@
|
|||||||
#include "util.h"
|
#include <stdint.h>
|
||||||
#include "client.h"
|
|
||||||
#include "wm.h"
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <cmocka.h>
|
#include <cmocka.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <json-c/json_tokener.h>
|
||||||
|
#include "util.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "wm.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char logfilepath[PATH_MAX];
|
||||||
|
char *jsonstr;
|
||||||
|
char *logjsonstr;
|
||||||
|
} TestGroup1State;
|
||||||
|
|
||||||
// store a copy of the nodes created in test2_setup, to check if any
|
// store a copy of the nodes created in test2_setup, to check if any
|
||||||
// of the tests modified them
|
// of the tests modified them
|
||||||
@ -323,6 +336,187 @@ static void test_wm_treenode_remove_client2(void **state)
|
|||||||
wm_treenode_free(client_node3);
|
wm_treenode_free(client_node3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_wm_ptrarray_2d_index(void **state)
|
||||||
|
{
|
||||||
|
size_t x = 5;
|
||||||
|
size_t y = 10;
|
||||||
|
|
||||||
|
UIntArray *uintarr = wm_uintarray_new();
|
||||||
|
|
||||||
|
_Static_assert(sizeof(uint64_t) == sizeof(uint64_t*), "static assert failed");
|
||||||
|
for (size_t i = 0; i < x; i++) {
|
||||||
|
wm_uintarray_push(uintarr, (uint64_t)calloc(y, sizeof(uintptr_t)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < uintarr->size; i++) {
|
||||||
|
for (size_t j = 0; j < y; j++) {
|
||||||
|
((uint64_t**)uintarr->elements)[i][j] = i * j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < uintarr->size; i++) {
|
||||||
|
for (size_t j = 0; j < y; j++) {
|
||||||
|
assert_int_equal(wm_uintarray_2d_index(uintarr, i, j), i * j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < uintarr->size; i++) {
|
||||||
|
free((void*)uintarr->elements[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_uintarray_free(uintarr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_wm_treenode_to_str(void **state)
|
||||||
|
{
|
||||||
|
TreeNode *node = wm_treenode_new(NODE_CLIENT, (void*)54321);
|
||||||
|
node->pos.x = 1;
|
||||||
|
node->pos.y = 2;
|
||||||
|
node->pos.w = 3;
|
||||||
|
node->pos.h = 4;
|
||||||
|
node->id = 5;
|
||||||
|
node->client = &(Client) {.name = "client_name", .is_pid_set = true, .pid = 12341234};
|
||||||
|
char *str = wm_treenode_to_str(node);
|
||||||
|
|
||||||
|
assert_non_null(strstr(str, "\"type\":\"NODE_CLIENT\","));
|
||||||
|
assert_non_null(strstr(str, "\"parent\":54321,"));
|
||||||
|
assert_non_null(strstr(str, "\"children\":[],"));
|
||||||
|
assert_non_null(strstr(str, "\"pos\":{"));
|
||||||
|
assert_non_null(strstr(str, "\"x\":1,"));
|
||||||
|
assert_non_null(strstr(str, "\"y\":2,"));
|
||||||
|
assert_non_null(strstr(str, "\"w\":3,"));
|
||||||
|
assert_non_null(strstr(str, "\"h\":4"));
|
||||||
|
assert_non_null(strstr(str, "\"client\":{"));
|
||||||
|
assert_non_null(strstr(str, "\"name\":\"client_name\""));
|
||||||
|
assert_non_null(strstr(str, "\"is_pid_set\":true"));
|
||||||
|
assert_non_null(strstr(str, "\"pid\":12341234"));
|
||||||
|
assert_non_null(strstr(str, "\"id\":5"));
|
||||||
|
|
||||||
|
wm_treenode_free(node);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_wm_json_obj_to_treenode(void **state)
|
||||||
|
{
|
||||||
|
TestGroup1State *_state = (TestGroup1State*)(*state);
|
||||||
|
struct json_object *parsed_json = json_tokener_parse(_state->jsonstr);
|
||||||
|
assert_non_null(parsed_json);
|
||||||
|
|
||||||
|
TreeNode *node = wm_json_obj_to_treenode(parsed_json);
|
||||||
|
assert_int_equal(node->type, NODE_VERTICAL);
|
||||||
|
assert_int_equal(node->parent, 0);
|
||||||
|
assert_int_equal(node->children->size, 2);
|
||||||
|
assert_int_equal(node->pos.x, 1);
|
||||||
|
assert_int_equal(node->pos.y, 2);
|
||||||
|
assert_int_equal(node->pos.w, 3);
|
||||||
|
assert_int_equal(node->pos.h, 4);
|
||||||
|
assert_null(node->client);
|
||||||
|
|
||||||
|
TreeNode *child1 = node->children->nodes[0];
|
||||||
|
|
||||||
|
assert_int_equal(child1->type, NODE_CLIENT);
|
||||||
|
// assert_int_equal(child1->parent, 0);
|
||||||
|
assert_int_equal(child1->children->size, 0);
|
||||||
|
assert_int_equal(child1->pos.x, 2);
|
||||||
|
assert_int_equal(child1->pos.y, 2);
|
||||||
|
assert_int_equal(child1->pos.w, 798);
|
||||||
|
assert_int_equal(child1->pos.h, 896);
|
||||||
|
assert_non_null(child1->client);
|
||||||
|
assert_string_equal(child1->client->name, "child1_client_name");
|
||||||
|
assert_true(child1->client->is_pid_set);
|
||||||
|
assert_int_equal(child1->client->pid, 19058);
|
||||||
|
assert_int_equal(child1->id, 10);
|
||||||
|
|
||||||
|
TreeNode *child2 = node->children->nodes[1];
|
||||||
|
|
||||||
|
assert_int_equal(child2->type, NODE_CLIENT);
|
||||||
|
// assert_int_equal(child2->parent, 0);
|
||||||
|
assert_int_equal(child2->children->size, 0);
|
||||||
|
assert_int_equal(child2->pos.x, 800);
|
||||||
|
assert_int_equal(child2->pos.y, 2);
|
||||||
|
assert_int_equal(child2->pos.w, 798);
|
||||||
|
assert_int_equal(child2->pos.h, 896);
|
||||||
|
assert_non_null(child2->client);
|
||||||
|
assert_string_equal(child2->client->name, "child2_client_name");
|
||||||
|
assert_true(child2->client->is_pid_set);
|
||||||
|
assert_int_equal(child2->client->pid, 19063);
|
||||||
|
assert_int_equal(child2->id, 11);
|
||||||
|
|
||||||
|
json_object_put(parsed_json);
|
||||||
|
|
||||||
|
free(node->children->nodes[0]->client->name);
|
||||||
|
free(node->children->nodes[0]->client);
|
||||||
|
wm_treenode_free(node->children->nodes[0]);
|
||||||
|
|
||||||
|
free(node->children->nodes[1]->client->name);
|
||||||
|
free(node->children->nodes[1]->client);
|
||||||
|
wm_treenode_free(node->children->nodes[1]);
|
||||||
|
|
||||||
|
wm_treenode_free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_wm_read_log(void **state)
|
||||||
|
{
|
||||||
|
TestGroup1State *_state = (TestGroup1State*)(*state);
|
||||||
|
|
||||||
|
UIntArray *entries = wm_read_log(_state->logfilepath);
|
||||||
|
assert_int_equal(entries->size, 1);
|
||||||
|
|
||||||
|
LogEntry *entry = (void*)wm_uintarray_at(entries, 0);
|
||||||
|
assert_int_equal(entry->timestamp, 1705601049);
|
||||||
|
assert_string_equal(entry->function_name, "wm_kb_spawn");
|
||||||
|
assert_true(entry->after);
|
||||||
|
|
||||||
|
// TODO check nodes
|
||||||
|
|
||||||
|
free(entry->workspaces->nodes[2]->children->nodes[0]->client->name);
|
||||||
|
free(entry->workspaces->nodes[2]->children->nodes[0]->client);
|
||||||
|
wm_treenode_free(entry->workspaces->nodes[2]->children->nodes[0]);
|
||||||
|
|
||||||
|
free(entry->workspaces->nodes[2]->children->nodes[1]->client->name);
|
||||||
|
free(entry->workspaces->nodes[2]->children->nodes[1]->client);
|
||||||
|
wm_treenode_free(entry->workspaces->nodes[2]->children->nodes[1]);
|
||||||
|
|
||||||
|
wm_treenode_free(entry->workspaces->nodes[2]);
|
||||||
|
wm_nodearray_free(entry->workspaces);
|
||||||
|
free(entry);
|
||||||
|
wm_uintarray_free(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t simple_update_cost_function(TreeNode* node1, TreeNode* node2)
|
||||||
|
{
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_wm_logentries_calculate_distances(void **state)
|
||||||
|
{
|
||||||
|
TestGroup1State *_state = (TestGroup1State*)(*state);
|
||||||
|
|
||||||
|
UIntArray *entries = wm_read_log(_state->logfilepath);
|
||||||
|
|
||||||
|
TreeNode *node = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
TreeNode *child = wm_treenode_new(NODE_CLIENT, NULL);
|
||||||
|
wm_treenode_add_child(node, child);
|
||||||
|
|
||||||
|
wm_logentries_calculate_distances(entries, node, &simple_update_cost_function);
|
||||||
|
|
||||||
|
LogEntry *entry = (void*)wm_uintarray_at(entries, 0);
|
||||||
|
|
||||||
|
// TODO check node distances
|
||||||
|
|
||||||
|
free(entry->workspaces->nodes[2]->children->nodes[0]->client->name);
|
||||||
|
free(entry->workspaces->nodes[2]->children->nodes[0]->client);
|
||||||
|
|
||||||
|
free(entry->workspaces->nodes[2]->children->nodes[1]->client->name);
|
||||||
|
free(entry->workspaces->nodes[2]->children->nodes[1]->client);
|
||||||
|
|
||||||
|
wm_treenode_free(entry->workspaces->nodes[2]->children->nodes[0]);
|
||||||
|
wm_treenode_free(entry->workspaces->nodes[2]->children->nodes[1]);
|
||||||
|
wm_logentries_free(entries);
|
||||||
|
wm_treenode_free(node);
|
||||||
|
wm_treenode_free(child);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_wm_postorder_traversal(void **state)
|
static void test_wm_postorder_traversal(void **state)
|
||||||
{
|
{
|
||||||
TreeNode *node1 = (TreeNode*)*state;
|
TreeNode *node1 = (TreeNode*)*state;
|
||||||
@ -392,14 +586,14 @@ static void test_wm_is_treenode_keyroot(void **state)
|
|||||||
assert_non_null(postorder);
|
assert_non_null(postorder);
|
||||||
assert_int_equal(postorder->size, 8);
|
assert_int_equal(postorder->size, 8);
|
||||||
|
|
||||||
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[0]), false);
|
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[0], postorder), false);
|
||||||
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[1]), true);
|
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[1], postorder), true);
|
||||||
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[2]), true);
|
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[2], postorder), true);
|
||||||
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[3]), false);
|
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[3], postorder), false);
|
||||||
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[4]), false);
|
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[4], postorder), false);
|
||||||
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[5]), true);
|
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[5], postorder), true);
|
||||||
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[6]), true);
|
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[6], postorder), true);
|
||||||
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[7]), true);
|
assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[7], postorder), true);
|
||||||
|
|
||||||
wm_nodearray_free(postorder);
|
wm_nodearray_free(postorder);
|
||||||
}
|
}
|
||||||
@ -425,10 +619,59 @@ static void test_wm_treenode_all_lmds(void **state)
|
|||||||
wm_nodearray_free(lmds);
|
wm_nodearray_free(lmds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_wm_treenode_all_lmds_index(void **state)
|
||||||
|
{
|
||||||
|
TreeNode *node1 = (TreeNode*)*state;
|
||||||
|
|
||||||
|
NodeArray *postorder = wm_postorder_traversal(node1);
|
||||||
|
UIntArray *lmds = wm_treenode_all_lmds_index(node1);
|
||||||
|
|
||||||
|
assert_non_null(lmds);
|
||||||
|
|
||||||
|
assert_int_equal(lmds->size, 8);
|
||||||
|
|
||||||
|
assert_int_equal(wm_uintarray_at(lmds, 0), 0);
|
||||||
|
assert_int_equal(wm_uintarray_at(lmds, 1), 1);
|
||||||
|
assert_int_equal(wm_uintarray_at(lmds, 2), 2);
|
||||||
|
assert_int_equal(wm_uintarray_at(lmds, 3), 0);
|
||||||
|
assert_int_equal(wm_uintarray_at(lmds, 4), 4);
|
||||||
|
assert_int_equal(wm_uintarray_at(lmds, 5), 5);
|
||||||
|
assert_int_equal(wm_uintarray_at(lmds, 6), 4);
|
||||||
|
assert_int_equal(wm_uintarray_at(lmds, 7), 0);
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 0)],
|
||||||
|
wm_treenode_lmd(postorder->nodes[0]));
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 1)],
|
||||||
|
wm_treenode_lmd(postorder->nodes[1]));
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 2)],
|
||||||
|
wm_treenode_lmd(postorder->nodes[2]));
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 3)],
|
||||||
|
wm_treenode_lmd(postorder->nodes[3]));
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 4)],
|
||||||
|
wm_treenode_lmd(postorder->nodes[4]));
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 5)],
|
||||||
|
wm_treenode_lmd(postorder->nodes[5]));
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 6)],
|
||||||
|
wm_treenode_lmd(postorder->nodes[6]));
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 7)],
|
||||||
|
wm_treenode_lmd(postorder->nodes[7]));
|
||||||
|
|
||||||
|
wm_nodearray_free(postorder);
|
||||||
|
wm_uintarray_free(lmds);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_wm_treenode_all_keyroots(void **state)
|
static void test_wm_treenode_all_keyroots(void **state)
|
||||||
{
|
{
|
||||||
TreeNode *node1 = (TreeNode*)*state;
|
TreeNode *node1 = (TreeNode*)*state;
|
||||||
|
|
||||||
|
NodeArray *postorder = wm_postorder_traversal(node1);
|
||||||
NodeArray *keyroots = wm_treenode_all_keyroots(node1);
|
NodeArray *keyroots = wm_treenode_all_keyroots(node1);
|
||||||
|
|
||||||
assert_non_null(keyroots);
|
assert_non_null(keyroots);
|
||||||
@ -440,9 +683,119 @@ static void test_wm_treenode_all_keyroots(void **state)
|
|||||||
assert_int_equal(keyroots->nodes[3]->id, 3);
|
assert_int_equal(keyroots->nodes[3]->id, 3);
|
||||||
assert_int_equal(keyroots->nodes[4]->id, 1);
|
assert_int_equal(keyroots->nodes[4]->id, 1);
|
||||||
|
|
||||||
|
assert_true(wm_is_treenode_keyroot(keyroots->nodes[0], postorder));
|
||||||
|
assert_true(wm_is_treenode_keyroot(keyroots->nodes[1], postorder));
|
||||||
|
assert_true(wm_is_treenode_keyroot(keyroots->nodes[2], postorder));
|
||||||
|
assert_true(wm_is_treenode_keyroot(keyroots->nodes[3], postorder));
|
||||||
|
assert_true(wm_is_treenode_keyroot(keyroots->nodes[4], postorder));
|
||||||
|
|
||||||
|
wm_nodearray_free(postorder);
|
||||||
wm_nodearray_free(keyroots);
|
wm_nodearray_free(keyroots);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_wm_treenode_all_keyroots_index(void **state)
|
||||||
|
{
|
||||||
|
TreeNode *node1 = (TreeNode*)*state;
|
||||||
|
|
||||||
|
NodeArray *postorder = wm_postorder_traversal(node1);
|
||||||
|
UIntArray *keyroot_indexes = wm_treenode_all_keyroots_index(node1);
|
||||||
|
|
||||||
|
assert_non_null(keyroot_indexes);
|
||||||
|
assert_int_equal(keyroot_indexes->size, 5);
|
||||||
|
|
||||||
|
assert_int_equal(keyroot_indexes->elements[0], 1);
|
||||||
|
assert_int_equal(keyroot_indexes->elements[1], 2);
|
||||||
|
assert_int_equal(keyroot_indexes->elements[2], 5);
|
||||||
|
assert_int_equal(keyroot_indexes->elements[3], 6);
|
||||||
|
assert_int_equal(keyroot_indexes->elements[4], 7);
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(keyroot_indexes, 0)],
|
||||||
|
postorder->nodes[1]);
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(keyroot_indexes, 1)],
|
||||||
|
postorder->nodes[2]);
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(keyroot_indexes, 2)],
|
||||||
|
postorder->nodes[5]);
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(keyroot_indexes, 3)],
|
||||||
|
postorder->nodes[6]);
|
||||||
|
|
||||||
|
assert_ptr_equal(postorder->nodes[wm_uintarray_at(keyroot_indexes, 4)],
|
||||||
|
postorder->nodes[7]);
|
||||||
|
|
||||||
|
assert_true(wm_is_treenode_keyroot(postorder->nodes[wm_uintarray_at(
|
||||||
|
keyroot_indexes, 0)], postorder));
|
||||||
|
|
||||||
|
assert_true(wm_is_treenode_keyroot(postorder->nodes[wm_uintarray_at(
|
||||||
|
keyroot_indexes, 1)], postorder));
|
||||||
|
|
||||||
|
assert_true(wm_is_treenode_keyroot(postorder->nodes[wm_uintarray_at(
|
||||||
|
keyroot_indexes, 2)], postorder));
|
||||||
|
|
||||||
|
assert_true(wm_is_treenode_keyroot(postorder->nodes[wm_uintarray_at(
|
||||||
|
keyroot_indexes, 3)], postorder));
|
||||||
|
|
||||||
|
assert_true(wm_is_treenode_keyroot(postorder->nodes[wm_uintarray_at(
|
||||||
|
keyroot_indexes, 4)], postorder));
|
||||||
|
|
||||||
|
wm_nodearray_free(postorder);
|
||||||
|
wm_uintarray_free(keyroot_indexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_wm_tree_edit_distance(void **state)
|
||||||
|
{
|
||||||
|
TreeNode *a_root = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
TreeNode *a_child1 = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
TreeNode *a_child2 = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
TreeNode *a_child3 = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
TreeNode *a_child4 = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
TreeNode *a_child5 = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
|
||||||
|
TreeNode *b_root = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
TreeNode *b_child1 = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
TreeNode *b_child2 = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
TreeNode *b_child3 = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
TreeNode *b_child4 = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
TreeNode *b_child5 = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
|
||||||
|
wm_treenode_add_child(a_root, a_child1);
|
||||||
|
wm_treenode_add_child(a_root, a_child2);
|
||||||
|
|
||||||
|
wm_treenode_add_child(a_child1, a_child3);
|
||||||
|
wm_treenode_add_child(a_child1, a_child4);
|
||||||
|
|
||||||
|
wm_treenode_add_child(a_child4, a_child5);
|
||||||
|
|
||||||
|
wm_treenode_add_child(b_root, b_child1);
|
||||||
|
wm_treenode_add_child(b_root, b_child2);
|
||||||
|
|
||||||
|
wm_treenode_add_child(b_child1, b_child3);
|
||||||
|
wm_treenode_add_child(b_child3, b_child4);
|
||||||
|
wm_treenode_add_child(b_child3, b_child5);
|
||||||
|
|
||||||
|
size_t dist = wm_tree_edit_distance(a_root, b_root, (TreeEditDistanceCosts) {
|
||||||
|
.insert_cost = 10,
|
||||||
|
.remove_cost = 10,
|
||||||
|
.update_cost_function = &simple_update_cost_function,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_int_equal(dist, 70);
|
||||||
|
|
||||||
|
wm_treenode_free(a_root);
|
||||||
|
wm_treenode_free(a_child1);
|
||||||
|
wm_treenode_free(a_child2);
|
||||||
|
wm_treenode_free(a_child3);
|
||||||
|
wm_treenode_free(a_child4);
|
||||||
|
wm_treenode_free(a_child5);
|
||||||
|
wm_treenode_free(b_root);
|
||||||
|
wm_treenode_free(b_child1);
|
||||||
|
wm_treenode_free(b_child2);
|
||||||
|
wm_treenode_free(b_child3);
|
||||||
|
wm_treenode_free(b_child4);
|
||||||
|
wm_treenode_free(b_child5);
|
||||||
|
}
|
||||||
|
|
||||||
static int test2_setup(void **state)
|
static int test2_setup(void **state)
|
||||||
{
|
{
|
||||||
TreeNode *node1 = wm_treenode_new(NODE_VERTICAL, NULL);
|
TreeNode *node1 = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
@ -463,13 +816,13 @@ static int test2_setup(void **state)
|
|||||||
assert_non_null(node7);
|
assert_non_null(node7);
|
||||||
assert_non_null(node8);
|
assert_non_null(node8);
|
||||||
|
|
||||||
wm_nodearray_push(node1->children, node2);
|
wm_treenode_add_child(node1, node2);
|
||||||
wm_nodearray_push(node1->children, node3);
|
wm_treenode_add_child(node1, node3);
|
||||||
wm_nodearray_push(node2->children, node4);
|
wm_treenode_add_child(node2, node4);
|
||||||
wm_nodearray_push(node2->children, node5);
|
wm_treenode_add_child(node2, node5);
|
||||||
wm_nodearray_push(node2->children, node6);
|
wm_treenode_add_child(node2, node6);
|
||||||
wm_nodearray_push(node3->children, node7);
|
wm_treenode_add_child(node3, node7);
|
||||||
wm_nodearray_push(node3->children, node8);
|
wm_treenode_add_child(node3, node8);
|
||||||
|
|
||||||
node1->id = 1;
|
node1->id = 1;
|
||||||
node2->id = 2;
|
node2->id = 2;
|
||||||
@ -543,6 +896,117 @@ static int test2_teardown(void **state)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test1_setup(void **state)
|
||||||
|
{
|
||||||
|
*state = calloc(1, sizeof(TestGroup1State));
|
||||||
|
TestGroup1State *_state = (TestGroup1State*)(*state);
|
||||||
|
_state->jsonstr = "{"
|
||||||
|
"\"type\":\"NODE_VERTICAL\","
|
||||||
|
"\"parent\":0,"
|
||||||
|
"\"children\":["
|
||||||
|
"{"
|
||||||
|
"\"type\":\"NODE_CLIENT\","
|
||||||
|
"\"parent\":105965433127232,"
|
||||||
|
"\"children\":[],"
|
||||||
|
"\"pos\":{"
|
||||||
|
"\"x\":2,"
|
||||||
|
"\"y\":2,"
|
||||||
|
"\"w\":798,"
|
||||||
|
"\"h\":896"
|
||||||
|
"},"
|
||||||
|
"\"client\":{"
|
||||||
|
"\"address\":106102872080672,"
|
||||||
|
"\"name\":\"child1_client_name\","
|
||||||
|
"\"is_pid_set\":true,"
|
||||||
|
"\"pid\":19058"
|
||||||
|
"},"
|
||||||
|
"\"id\":10"
|
||||||
|
"},"
|
||||||
|
"{"
|
||||||
|
"\"type\":\"NODE_CLIENT\","
|
||||||
|
"\"parent\":105965433127232,"
|
||||||
|
"\"children\":[],"
|
||||||
|
"\"pos\":{"
|
||||||
|
"\"x\":800,"
|
||||||
|
"\"y\":2,"
|
||||||
|
"\"w\":798,"
|
||||||
|
"\"h\":896"
|
||||||
|
"},"
|
||||||
|
"\"client\":{"
|
||||||
|
"\"address\":106102872080800,"
|
||||||
|
"\"name\":\"child2_client_name\","
|
||||||
|
"\"is_pid_set\":true,"
|
||||||
|
"\"pid\":19063"
|
||||||
|
"},"
|
||||||
|
"\"id\":11"
|
||||||
|
"}"
|
||||||
|
"],"
|
||||||
|
"\"pos\":{"
|
||||||
|
"\"x\":1,"
|
||||||
|
"\"y\":2,"
|
||||||
|
"\"w\":3,"
|
||||||
|
"\"h\":4"
|
||||||
|
"},"
|
||||||
|
"\"client\":{"
|
||||||
|
"\"address\":1234,"
|
||||||
|
"\"name\":\"client_name\","
|
||||||
|
"\"is_pid_set\":true,"
|
||||||
|
"\"pid\":1234"
|
||||||
|
"},"
|
||||||
|
"\"id\":5"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
size_t logjsonstr_size = strlen(_state->jsonstr) + 1024;
|
||||||
|
_state->logjsonstr = calloc(logjsonstr_size, 1);
|
||||||
|
snprintf(_state->logjsonstr, logjsonstr_size, "{\"1705601049:wm_kb_spawn:after\": {"
|
||||||
|
"\"2\":"
|
||||||
|
"%s"
|
||||||
|
"}}", _state->jsonstr);
|
||||||
|
|
||||||
|
const char *basedir = "./";
|
||||||
|
assert_true(access(basedir, W_OK) >= 0);
|
||||||
|
|
||||||
|
srand(time(NULL));
|
||||||
|
bool ok = false;
|
||||||
|
int tries = 0;
|
||||||
|
|
||||||
|
while (!ok && tries < 1000) {
|
||||||
|
snprintf(_state->logfilepath, PATH_MAX, "%s%ld.json", basedir, random());
|
||||||
|
|
||||||
|
if (access(_state->logfilepath, F_OK) < 0)
|
||||||
|
ok = true;
|
||||||
|
tries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int fd = creat(_state->logfilepath, 0664);
|
||||||
|
if (fd < 0) perror("creat");
|
||||||
|
assert_true(fd >= 0);
|
||||||
|
|
||||||
|
assert_true(write(fd, _state->logjsonstr, strlen(_state->logjsonstr)) > 0);
|
||||||
|
assert_true(close(fd) >= 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test1_teardown(void **state)
|
||||||
|
{
|
||||||
|
TestGroup1State *_state = (TestGroup1State*)(*state);
|
||||||
|
int ret = unlink(_state->logfilepath);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("unlink");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(_state->logjsonstr);
|
||||||
|
free(*state);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
const struct CMUnitTest test_group1[] = {
|
const struct CMUnitTest test_group1[] = {
|
||||||
@ -553,6 +1017,11 @@ int main(void)
|
|||||||
cmocka_unit_test(test_wm_find_client_nodes),
|
cmocka_unit_test(test_wm_find_client_nodes),
|
||||||
cmocka_unit_test(test_wm_treenode_remove_client1),
|
cmocka_unit_test(test_wm_treenode_remove_client1),
|
||||||
cmocka_unit_test(test_wm_treenode_remove_client2),
|
cmocka_unit_test(test_wm_treenode_remove_client2),
|
||||||
|
cmocka_unit_test(test_wm_ptrarray_2d_index),
|
||||||
|
cmocka_unit_test(test_wm_treenode_to_str),
|
||||||
|
cmocka_unit_test(test_wm_json_obj_to_treenode),
|
||||||
|
cmocka_unit_test(test_wm_read_log),
|
||||||
|
cmocka_unit_test(test_wm_logentries_calculate_distances),
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct CMUnitTest test_group2[] = {
|
const struct CMUnitTest test_group2[] = {
|
||||||
@ -560,9 +1029,12 @@ int main(void)
|
|||||||
cmocka_unit_test(test_wm_treenode_lmd),
|
cmocka_unit_test(test_wm_treenode_lmd),
|
||||||
cmocka_unit_test(test_wm_is_treenode_keyroot),
|
cmocka_unit_test(test_wm_is_treenode_keyroot),
|
||||||
cmocka_unit_test(test_wm_treenode_all_lmds),
|
cmocka_unit_test(test_wm_treenode_all_lmds),
|
||||||
|
cmocka_unit_test(test_wm_treenode_all_lmds_index),
|
||||||
cmocka_unit_test(test_wm_treenode_all_keyroots),
|
cmocka_unit_test(test_wm_treenode_all_keyroots),
|
||||||
|
cmocka_unit_test(test_wm_treenode_all_keyroots_index),
|
||||||
|
cmocka_unit_test(test_wm_tree_edit_distance),
|
||||||
};
|
};
|
||||||
|
|
||||||
cmocka_run_group_tests(test_group1, NULL, NULL);
|
cmocka_run_group_tests(test_group1, test1_setup, test1_teardown);
|
||||||
cmocka_run_group_tests(test_group2, test2_setup, test2_teardown);
|
cmocka_run_group_tests(test_group2, test2_setup, test2_teardown);
|
||||||
}
|
}
|
||||||
|
722
src/util.c
722
src/util.c
@ -1,13 +1,23 @@
|
|||||||
#include "util.h"
|
#include <fcntl.h>
|
||||||
#include "wm.h"
|
#include <stdint.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <json-c/json_object.h>
|
|
||||||
#include <json-c/json_tokener.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <json-c/arraylist.h>
|
||||||
|
#include <json-c/json_object_iterator.h>
|
||||||
|
#include <json-c/json_util.h>
|
||||||
|
#include <json-c/json_object.h>
|
||||||
|
#include <json-c/json_tokener.h>
|
||||||
|
#include "util.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "wm.h"
|
||||||
|
|
||||||
static unsigned int node_id = 0;
|
static unsigned int node_id = 0;
|
||||||
|
|
||||||
@ -104,6 +114,15 @@ void wm_treenode_swap(TreeNode *root, TreeNode *node1, TreeNode* node2)
|
|||||||
node2->client = tmp;
|
node2->client = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wm_treenode_add_child(TreeNode *node, TreeNode *child)
|
||||||
|
{
|
||||||
|
assert(node);
|
||||||
|
assert(child);
|
||||||
|
|
||||||
|
wm_nodearray_push(node->children, child);
|
||||||
|
child->parent = node;
|
||||||
|
}
|
||||||
|
|
||||||
void wm_node_type_to_str(NodeType type, char *buf, size_t bufsize)
|
void wm_node_type_to_str(NodeType type, char *buf, size_t bufsize)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -124,6 +143,23 @@ void wm_node_type_to_str(NodeType type, char *buf, size_t bufsize)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeType wm_node_type_from_str(char *buf, size_t bufsize)
|
||||||
|
{
|
||||||
|
char *types[4] = {0};
|
||||||
|
types[NODE_CLIENT] = "NODE_CLIENT";
|
||||||
|
types[NODE_VERTICAL] = "NODE_VERTICAL";
|
||||||
|
types[NODE_HORIZONTAL] = "NODE_HORIZONTAL";
|
||||||
|
types[NODE_TAB] = "NODE_TAB";
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 4; i++) {
|
||||||
|
if (strncmp(buf, types[i], bufsize) == 0)
|
||||||
|
return (NodeType)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "wm: invalid node type string: %s. exiting\n", buf);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
char* wm_treenode_to_str(TreeNode *node)
|
char* wm_treenode_to_str(TreeNode *node)
|
||||||
{
|
{
|
||||||
assert(node);
|
assert(node);
|
||||||
@ -166,9 +202,10 @@ char* wm_treenode_to_str(TreeNode *node)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
PtrArray wm_nonempty_workspaces_to_strptrarray(Wm *wm)
|
UIntArray* wm_nonempty_workspaces_to_strptrarray(Wm *wm)
|
||||||
{
|
{
|
||||||
PtrArray ret = wm_ptrarray_new();
|
_Static_assert(sizeof(uint64_t) == sizeof(uint64_t*), "static assert failed");
|
||||||
|
UIntArray *ret = wm_uintarray_new();
|
||||||
|
|
||||||
for (size_t i = 0; i < wm->smon->wscount; i++) {
|
for (size_t i = 0; i < wm->smon->wscount; i++) {
|
||||||
TreeNode *node = wm->smon->workspaces[i].tree;
|
TreeNode *node = wm->smon->workspaces[i].tree;
|
||||||
@ -179,11 +216,11 @@ PtrArray wm_nonempty_workspaces_to_strptrarray(Wm *wm)
|
|||||||
.ws_index = i,
|
.ws_index = i,
|
||||||
.str = wm_treenode_to_str(wm->smon->workspaces[i].tree)
|
.str = wm_treenode_to_str(wm->smon->workspaces[i].tree)
|
||||||
};
|
};
|
||||||
wm_ptrarray_push(&ret, ws_str_with_index);
|
wm_uintarray_push(ret, (uint64_t)ws_str_with_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINT("%s returning %ld\n", __func__, ret.size);
|
DEBUG_PRINT("%s returning %ld\n", __func__, ret->size);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -193,34 +230,83 @@ void wm_log_state(Wm *wm, const char *prefixstr, const char* logfile)
|
|||||||
RETURN_IF_NULL(prefixstr);
|
RETURN_IF_NULL(prefixstr);
|
||||||
RETURN_IF_NULL(logfile);
|
RETURN_IF_NULL(logfile);
|
||||||
|
|
||||||
FILE *fptr = fopen(logfile, "a");
|
UIntArray *ws_str = wm_nonempty_workspaces_to_strptrarray(wm);
|
||||||
if (!fptr) {
|
|
||||||
fprintf(stderr, "wm: could not open log file %s\n", logfile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PtrArray ws_str = wm_nonempty_workspaces_to_strptrarray(wm);
|
|
||||||
|
|
||||||
char str[128] = {0};
|
char str[128] = {0};
|
||||||
char prefix[WM_PREFIX_LEN + 32] = {0};
|
char prefix[WM_PREFIX_LEN + 32] = {0};
|
||||||
snprintf(prefix, sizeof(prefix), "%lu_%s", time(NULL), prefixstr);
|
snprintf(prefix, sizeof(prefix), "%lu:%s", time(NULL), prefixstr);
|
||||||
|
|
||||||
json_object *log_entry_obj = json_object_new_object();
|
json_object *log_entry_obj = json_object_new_object();
|
||||||
json_object_object_add(log_entry_obj, prefix, json_object_new_object());
|
|
||||||
|
|
||||||
for (size_t i = 0; i < ws_str.size; i++) {
|
for (size_t i = 0; i < ws_str->size; i++) {
|
||||||
WmWorkspaceToStrRet *ws_with_index = (WmWorkspaceToStrRet*)ws_str.ptrs[i];
|
WmWorkspaceToStrRet *ws_with_index = (WmWorkspaceToStrRet*)
|
||||||
|
wm_uintarray_at(ws_str, i);
|
||||||
|
|
||||||
snprintf(str, sizeof(str), "%ld", ws_with_index->ws_index);
|
snprintf(str, sizeof(str), "%ld", ws_with_index->ws_index);
|
||||||
json_object_object_add(json_object_object_get(log_entry_obj, prefix), str, json_tokener_parse(ws_with_index->str));
|
json_object_object_add(log_entry_obj, str, json_tokener_parse(ws_with_index->str));
|
||||||
fprintf(fptr, "%s,\n", json_object_to_json_string_ext(log_entry_obj, JSON_C_TO_STRING_PRETTY));
|
|
||||||
free(ws_with_index->str);
|
free(ws_with_index->str);
|
||||||
free(ws_with_index);
|
free(ws_with_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object_put(log_entry_obj);
|
int fd = -1;
|
||||||
fflush(fptr);
|
struct json_object *jobj = NULL;
|
||||||
fclose(fptr);
|
if (access(logfile, F_OK) != 0) {
|
||||||
wm_ptrarray_free(&ws_str);
|
fd = creat(logfile, 0644);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("creat");
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobj = json_object_new_object();
|
||||||
|
} else {
|
||||||
|
fd = open(logfile, O_RDWR);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("open");
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobj = json_object_from_fd(fd);
|
||||||
|
if (!jobj) {
|
||||||
|
const char *err = json_util_get_last_err();
|
||||||
|
fprintf(stderr, "wm: could not read json: %s\n", err);
|
||||||
|
// TODO maybe free
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object_object_add(jobj, prefix, log_entry_obj);
|
||||||
|
|
||||||
|
int ret = close(fd);
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("close");
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = open(logfile, O_TRUNC | O_WRONLY);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("open");
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object_to_fd(fd, jobj, JSON_C_TO_STRING_PRETTY);
|
||||||
|
|
||||||
|
ret = close(fd);
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("close");
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
wm_logentries_free(wm->log_entries);
|
||||||
|
wm->log_entries = wm_read_log(logfile);
|
||||||
|
|
||||||
|
ret:
|
||||||
|
json_object_put(jobj);
|
||||||
|
wm_uintarray_free(ws_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeNode* wm_treenode_lmd(TreeNode *node)
|
TreeNode* wm_treenode_lmd(TreeNode *node)
|
||||||
@ -249,6 +335,30 @@ NodeArray* wm_treenode_all_lmds(TreeNode *node)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UIntArray* wm_treenode_all_lmds_index(TreeNode *node)
|
||||||
|
{
|
||||||
|
assert(node);
|
||||||
|
|
||||||
|
NodeArray *postorder = wm_postorder_traversal(node);
|
||||||
|
UIntArray *ret = wm_uintarray_new();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < postorder->size; i++) {
|
||||||
|
TreeNode *lmd = wm_treenode_lmd(postorder->nodes[i]);
|
||||||
|
|
||||||
|
uintptr_t index = UINT_MAX;
|
||||||
|
for (index = 0; index < postorder->size; index++) {
|
||||||
|
if (postorder->nodes[index]->id == lmd->id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(index != UINT_MAX);
|
||||||
|
wm_uintarray_push(ret, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_nodearray_free(postorder);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
NodeArray* wm_postorder_traversal(TreeNode *tree)
|
NodeArray* wm_postorder_traversal(TreeNode *tree)
|
||||||
{
|
{
|
||||||
assert(tree);
|
assert(tree);
|
||||||
@ -308,12 +418,30 @@ NodeArray* wm_postorder_traversal(TreeNode *tree)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_is_treenode_keyroot(TreeNode *node)
|
bool wm_is_treenode_keyroot(TreeNode *node, NodeArray *postorder)
|
||||||
{
|
{
|
||||||
assert(node);
|
assert(node);
|
||||||
|
assert(postorder);
|
||||||
if (!node->parent) return true;
|
if (!node->parent) return true;
|
||||||
|
|
||||||
return wm_treenode_lmd(node) != wm_treenode_lmd(node->parent);
|
TreeNode *node_lmd = wm_treenode_lmd(node);
|
||||||
|
size_t node_index = SIZE_MAX;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < postorder->size; i++) {
|
||||||
|
if (node->id == postorder->nodes[i]->id) {
|
||||||
|
node_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(node_index != SIZE_MAX);
|
||||||
|
|
||||||
|
for (size_t i = node_index + 1; i < postorder->size; i++) {
|
||||||
|
if (node_lmd->id == wm_treenode_lmd(postorder->nodes[i])->id)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeArray* wm_treenode_all_keyroots(TreeNode *node)
|
NodeArray* wm_treenode_all_keyroots(TreeNode *node)
|
||||||
@ -325,7 +453,7 @@ NodeArray* wm_treenode_all_keyroots(TreeNode *node)
|
|||||||
|
|
||||||
for (size_t i = 0; i < postorder->size; i++) {
|
for (size_t i = 0; i < postorder->size; i++) {
|
||||||
TreeNode *node = postorder->nodes[i];
|
TreeNode *node = postorder->nodes[i];
|
||||||
if (wm_is_treenode_keyroot(node))
|
if (wm_is_treenode_keyroot(node, postorder))
|
||||||
wm_nodearray_push(ret, node);
|
wm_nodearray_push(ret, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,6 +461,192 @@ NodeArray* wm_treenode_all_keyroots(TreeNode *node)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UIntArray* wm_treenode_all_keyroots_index(TreeNode *node)
|
||||||
|
{
|
||||||
|
assert(node);
|
||||||
|
|
||||||
|
NodeArray *postorder = wm_postorder_traversal(node);
|
||||||
|
UIntArray *ret = wm_uintarray_new();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < postorder->size; i++) {
|
||||||
|
if (wm_is_treenode_keyroot(postorder->nodes[i], postorder))
|
||||||
|
wm_uintarray_push(ret, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_nodearray_free(postorder);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wm_nodes_are_equal(TreeNode *node1, TreeNode *node2)
|
||||||
|
{
|
||||||
|
if (node1->type != node2->type)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/timtadh/zhang-shasha
|
||||||
|
void wm_treedist(TreeNode *tree1, TreeNode *tree2, size_t i, size_t j,
|
||||||
|
UIntArray *dists, TreeEditDistanceCosts costs)
|
||||||
|
{
|
||||||
|
assert(tree1);
|
||||||
|
assert(tree2);
|
||||||
|
|
||||||
|
NodeArray *tree1_postorder = wm_postorder_traversal(tree1);
|
||||||
|
NodeArray *tree2_postorder = wm_postorder_traversal(tree2);
|
||||||
|
|
||||||
|
UIntArray *tree1_lmds = wm_treenode_all_lmds_index(tree1);
|
||||||
|
UIntArray *tree2_lmds = wm_treenode_all_lmds_index(tree2);
|
||||||
|
|
||||||
|
size_t m = i - wm_uintarray_at(tree1_lmds, i) + 2;
|
||||||
|
size_t n = j - wm_uintarray_at(tree2_lmds, j) + 2;
|
||||||
|
|
||||||
|
UIntArray *fd = wm_uintarray_new();
|
||||||
|
|
||||||
|
_Static_assert(sizeof(uint64_t) == sizeof(uint64_t*), "static assert failed");
|
||||||
|
|
||||||
|
for (size_t k = 0; k < m; k++) {
|
||||||
|
wm_uintarray_push(fd, (uint64_t)calloc(n, sizeof(uint64_t)));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ioff = wm_uintarray_at(tree1_lmds, i) - 1;
|
||||||
|
size_t joff = wm_uintarray_at(tree2_lmds, j) - 1;
|
||||||
|
|
||||||
|
for (size_t x = 1; x < m; x++) {
|
||||||
|
TreeNode *node = tree1_postorder->nodes[x + ioff];
|
||||||
|
((uint64_t**)fd->elements)[x][0] = ((size_t)wm_uintarray_2d_index(fd,
|
||||||
|
x - 1, 0) + (size_t)costs.remove_cost);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t y = 1; y < n; y++) {
|
||||||
|
TreeNode *node = tree2_postorder->nodes[y + joff];
|
||||||
|
((uint64_t**)fd->elements)[0][y] = ((size_t)wm_uintarray_2d_index(fd,
|
||||||
|
0, y - 1) + (size_t)costs.insert_cost);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t x = 1; x < m; x++) {
|
||||||
|
for (size_t y = 1; y < n; y++) {
|
||||||
|
TreeNode *node1 = tree1_postorder->nodes[x + ioff];
|
||||||
|
TreeNode *node2 = tree2_postorder->nodes[y + joff];
|
||||||
|
if (wm_uintarray_at(tree1_lmds, i) == tree1_lmds->elements[x + ioff] &&
|
||||||
|
wm_uintarray_at(tree2_lmds, j) == tree2_lmds->elements[y + joff]) {
|
||||||
|
|
||||||
|
size_t _costs[3] = {
|
||||||
|
wm_uintarray_2d_index(fd, x - 1, y) + costs.remove_cost, //(node1)
|
||||||
|
wm_uintarray_2d_index(fd, x, y - 1) + costs.insert_cost, //(node2)
|
||||||
|
wm_uintarray_2d_index(fd, x - 1, y - 1) + (*costs.update_cost_function)(node1, node2),
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t min = SIZE_MAX;
|
||||||
|
for (size_t k = 0; k < 3; k++) {
|
||||||
|
if (_costs[k] < min) {
|
||||||
|
min = _costs[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(min != SIZE_MAX);
|
||||||
|
|
||||||
|
((uint64_t**)fd->elements)[x][y] = min;
|
||||||
|
((uint64_t**)dists->elements)[x + ioff][y + joff] = min;
|
||||||
|
} else {
|
||||||
|
size_t p = tree1_lmds->elements[x + ioff] - 1 - ioff;
|
||||||
|
size_t q = tree2_lmds->elements[y + joff] - 1 - joff;
|
||||||
|
|
||||||
|
size_t _costs[3] = {
|
||||||
|
(size_t)wm_uintarray_2d_index(fd, x - 1, y) + costs.remove_cost, // (node1)
|
||||||
|
(size_t)wm_uintarray_2d_index(fd, x, y - 1) + costs.insert_cost, // (node2)
|
||||||
|
(size_t)wm_uintarray_2d_index(fd, p, q) +
|
||||||
|
(size_t)wm_uintarray_2d_index(dists, x + ioff, y + joff),
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t min = SIZE_MAX;
|
||||||
|
for (size_t k = 0; k < 3; k++) {
|
||||||
|
if (_costs[k] < min) {
|
||||||
|
min = _costs[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(min != SIZE_MAX);
|
||||||
|
((uint64_t**)fd->elements)[x][y] = min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t k = 0; k < m; k++) {
|
||||||
|
free((void*)wm_uintarray_at(fd, k));
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_nodearray_free(tree1_postorder);
|
||||||
|
wm_nodearray_free(tree2_postorder);
|
||||||
|
wm_uintarray_free(tree1_lmds);
|
||||||
|
wm_uintarray_free(tree2_lmds);
|
||||||
|
wm_uintarray_free(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/timtadh/zhang-shasha
|
||||||
|
size_t wm_tree_edit_distance(TreeNode *tree1, TreeNode *tree2, TreeEditDistanceCosts costs)
|
||||||
|
{
|
||||||
|
assert(tree1);
|
||||||
|
assert(tree2);
|
||||||
|
|
||||||
|
NodeArray *tree1_postorder = wm_postorder_traversal(tree1);
|
||||||
|
NodeArray *tree2_postorder = wm_postorder_traversal(tree2);
|
||||||
|
|
||||||
|
UIntArray *tree1_keyroot_indexes = wm_treenode_all_keyroots_index(tree1);
|
||||||
|
UIntArray *tree2_keyroot_indexes = wm_treenode_all_keyroots_index(tree2);
|
||||||
|
|
||||||
|
UIntArray *dists = wm_uintarray_new();
|
||||||
|
|
||||||
|
_Static_assert(sizeof(uint64_t) == sizeof(uint64_t*), "static assert failed");
|
||||||
|
|
||||||
|
for (size_t k = 0; k < tree1_postorder->size; k++) {
|
||||||
|
wm_uintarray_push(dists, (uint64_t)calloc(tree2_postorder->size, sizeof(uint64_t)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t p = 0; p < tree1_keyroot_indexes->size; p++) {
|
||||||
|
for (size_t q = 0; q < tree2_keyroot_indexes->size; q++) {
|
||||||
|
size_t i = wm_uintarray_at(tree1_keyroot_indexes, p);
|
||||||
|
size_t j = wm_uintarray_at(tree2_keyroot_indexes, q);
|
||||||
|
wm_treedist(tree1, tree2, i, j, dists, costs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ret = wm_uintarray_2d_index(dists, tree1_postorder->size - 1, tree2_postorder->size - 1);
|
||||||
|
|
||||||
|
for (size_t k = 0; k < tree1_postorder->size; k++) {
|
||||||
|
free((void*)wm_uintarray_at(dists, k));
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_nodearray_free(tree1_postorder);
|
||||||
|
wm_nodearray_free(tree2_postorder);
|
||||||
|
wm_uintarray_free(tree1_keyroot_indexes);
|
||||||
|
wm_uintarray_free(tree2_keyroot_indexes);
|
||||||
|
wm_uintarray_free(dists);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_logentries_calculate_distances(UIntArray *log_entries, TreeNode *curr_tree,
|
||||||
|
UpdateCostFunction update_cost_function)
|
||||||
|
{
|
||||||
|
TreeEditDistanceCosts costs = (TreeEditDistanceCosts) {
|
||||||
|
.insert_cost = 3,
|
||||||
|
.remove_cost = 100,
|
||||||
|
.update_cost_function = update_cost_function,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < log_entries->size; i++) {
|
||||||
|
LogEntry *entry = (LogEntry*)wm_uintarray_at(log_entries, i);
|
||||||
|
|
||||||
|
for (size_t j = 0; j < entry->workspaces->size; j++) {
|
||||||
|
TreeNode *node = entry->workspaces->nodes[j];
|
||||||
|
if (node == NULL) continue;
|
||||||
|
|
||||||
|
node->distance = wm_tree_edit_distance(curr_tree, node, costs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void wm_treenode_print(TreeNode *node)
|
void wm_treenode_print(TreeNode *node)
|
||||||
{
|
{
|
||||||
char *str = wm_treenode_to_str(node);
|
char *str = wm_treenode_to_str(node);
|
||||||
@ -340,6 +654,259 @@ void wm_treenode_print(TreeNode *node)
|
|||||||
free(str);
|
free(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TreeNode* wm_json_obj_to_treenode(struct json_object *jobj)
|
||||||
|
{
|
||||||
|
assert(jobj);
|
||||||
|
|
||||||
|
TreeNode *tree_ret = wm_treenode_new(NODE_VERTICAL, NULL);
|
||||||
|
|
||||||
|
bool found_key = false;
|
||||||
|
|
||||||
|
struct json_object *ret;
|
||||||
|
struct json_object *tmp;
|
||||||
|
|
||||||
|
char *key = "type";
|
||||||
|
// TODO
|
||||||
|
found_key = json_object_object_get_ex(jobj, key, &ret);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
const char *type = json_object_get_string(ret);
|
||||||
|
tree_ret->type = wm_node_type_from_str((char*)type, strlen(type));
|
||||||
|
|
||||||
|
key = "parent";
|
||||||
|
found_key = json_object_object_get_ex(jobj, key, &ret);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
tree_ret->parent = (void*)json_object_get_int64(ret);
|
||||||
|
|
||||||
|
key = "id";
|
||||||
|
found_key = json_object_object_get_ex(jobj, key, &ret);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
tree_ret->id = json_object_get_int64(ret);
|
||||||
|
|
||||||
|
if (tree_ret->type == NODE_CLIENT) {
|
||||||
|
tree_ret->client = calloc(1, sizeof(Client));
|
||||||
|
key = "client";
|
||||||
|
found_key = json_object_object_get_ex(jobj, key, &tmp);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
|
||||||
|
key = "name";
|
||||||
|
found_key = json_object_object_get_ex(tmp, key, &ret);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
tree_ret->client->name = strdup(json_object_get_string(ret));
|
||||||
|
|
||||||
|
key = "is_pid_set";
|
||||||
|
found_key = json_object_object_get_ex(tmp, key, &ret);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
tree_ret->client->is_pid_set = json_object_get_boolean(ret);
|
||||||
|
|
||||||
|
key = "pid";
|
||||||
|
found_key = json_object_object_get_ex(tmp, key, &ret);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
tree_ret->client->pid = json_object_get_int(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pos
|
||||||
|
key = "pos";
|
||||||
|
found_key = json_object_object_get_ex(jobj, key, &tmp);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
|
||||||
|
key = "x";
|
||||||
|
found_key = json_object_object_get_ex(tmp, key, &ret);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
tree_ret->pos.x = json_object_get_int(ret);
|
||||||
|
|
||||||
|
key = "y";
|
||||||
|
found_key = json_object_object_get_ex(tmp, key, &ret);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
tree_ret->pos.y = json_object_get_int(ret);
|
||||||
|
|
||||||
|
key = "w";
|
||||||
|
found_key = json_object_object_get_ex(tmp, key, &ret);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
tree_ret->pos.w = json_object_get_int(ret);
|
||||||
|
|
||||||
|
key = "h";
|
||||||
|
found_key = json_object_object_get_ex(tmp, key, &ret);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
tree_ret->pos.h = json_object_get_int(ret);
|
||||||
|
|
||||||
|
// children
|
||||||
|
key = "children";
|
||||||
|
found_key = json_object_object_get_ex(jobj, key, &ret);
|
||||||
|
if (!found_key) goto not_found_key;
|
||||||
|
struct array_list *list = json_object_get_array(ret);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < array_list_length(list); i++) {
|
||||||
|
struct json_object *child = array_list_get_idx(list, i);
|
||||||
|
wm_nodearray_push(tree_ret->children, wm_json_obj_to_treenode(child));
|
||||||
|
}
|
||||||
|
|
||||||
|
return tree_ret;
|
||||||
|
|
||||||
|
not_found_key:
|
||||||
|
fprintf(stderr, "wm: %s: could not find key %s\n", __func__, key);
|
||||||
|
return tree_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CREATE_LOGFILE_ERROR(str) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, "wm: could not create log file. error: %s. exiting.\n", str); \
|
||||||
|
exit(1); \
|
||||||
|
} while (0); \
|
||||||
|
|
||||||
|
static void recursive_mkdir(char *path, mode_t mode)
|
||||||
|
{
|
||||||
|
char *sep = strrchr(path, '/');
|
||||||
|
|
||||||
|
if(sep != NULL) {
|
||||||
|
*sep = '\0';
|
||||||
|
recursive_mkdir(path, mode);
|
||||||
|
*sep = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mkdir(path, mode) < 0 && errno != EEXIST) {
|
||||||
|
fprintf(stderr, "wm: could not create directory. error %s. exiting.\n",
|
||||||
|
strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_logfile_init(const char *path)
|
||||||
|
{
|
||||||
|
char *log_file_dir = dirname((char*)path);
|
||||||
|
|
||||||
|
if (access(path, F_OK) == 0) return;
|
||||||
|
|
||||||
|
int ret = access(log_file_dir, W_OK | R_OK);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = creat(path, 0664);
|
||||||
|
if (ret < 0) CREATE_LOGFILE_ERROR(strerror(errno));
|
||||||
|
|
||||||
|
ret = close(ret);
|
||||||
|
if (ret < 0) CREATE_LOGFILE_ERROR(strerror(errno));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0 && errno == ENOENT) {
|
||||||
|
recursive_mkdir(log_file_dir, 0751);
|
||||||
|
|
||||||
|
ret = creat(path, 0664);
|
||||||
|
if (ret < 0) CREATE_LOGFILE_ERROR(strerror(errno));
|
||||||
|
|
||||||
|
ret = close(ret);
|
||||||
|
if (ret < 0) CREATE_LOGFILE_ERROR(strerror(errno));
|
||||||
|
} else {
|
||||||
|
CREATE_LOGFILE_ERROR(strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UIntArray<LogEntry*> */
|
||||||
|
UIntArray* wm_read_log(const char* filename)
|
||||||
|
{
|
||||||
|
_Static_assert(sizeof(LogEntry*) == sizeof(uint64_t), "");
|
||||||
|
// TODO maybe prealloc
|
||||||
|
UIntArray* ret = wm_uintarray_new();
|
||||||
|
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
struct json_object *jobj = NULL;
|
||||||
|
|
||||||
|
fd = open(filename, O_RDONLY);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("open");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobj = json_object_from_fd(fd);
|
||||||
|
if (!jobj) {
|
||||||
|
const char *err = json_util_get_last_err();
|
||||||
|
fprintf(stderr, "wm: could not read json: %s\n", err);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *token;
|
||||||
|
const char *name = NULL;
|
||||||
|
struct json_object *value = NULL;
|
||||||
|
struct json_object_iterator iter = json_object_iter_begin(jobj);
|
||||||
|
struct json_object_iterator iter_end = json_object_iter_end(jobj);
|
||||||
|
|
||||||
|
const char *ws_name = NULL;
|
||||||
|
struct json_object *ws_value = NULL;
|
||||||
|
struct json_object_iterator ws_iter = json_object_iter_init_default();
|
||||||
|
struct json_object_iterator ws_iter_end = json_object_iter_init_default();
|
||||||
|
|
||||||
|
while (!json_object_iter_equal(&iter, &iter_end)) {
|
||||||
|
// TODO maybe prealloc
|
||||||
|
LogEntry *entry = calloc(1, sizeof(LogEntry));
|
||||||
|
entry->workspaces = wm_nodearray_new();
|
||||||
|
name = json_object_iter_peek_name(&iter);
|
||||||
|
value = json_object_iter_peek_value(&iter);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
char *token = strtok((char*)name, ":");
|
||||||
|
|
||||||
|
while(token != NULL) {
|
||||||
|
i++;
|
||||||
|
|
||||||
|
switch (i) {
|
||||||
|
case 1:
|
||||||
|
// TODO
|
||||||
|
entry->timestamp = atol(token);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
strncpy(entry->function_name, token, 128);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (strncmp(token, "after", strlen("after")) == 0)
|
||||||
|
entry->after = true;
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "wm: encountered invalid token %s\n. exiting.",
|
||||||
|
token);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "wm: encountered invalid token %s\n. exiting.",
|
||||||
|
token);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, ":");
|
||||||
|
}
|
||||||
|
|
||||||
|
ws_iter = json_object_iter_begin(value);
|
||||||
|
ws_iter_end = json_object_iter_end(value);
|
||||||
|
|
||||||
|
while (!json_object_iter_equal(&ws_iter, &ws_iter_end)) {
|
||||||
|
ws_name = json_object_iter_peek_name(&ws_iter);
|
||||||
|
ws_value = json_object_iter_peek_value(&ws_iter);
|
||||||
|
|
||||||
|
int ws_index = atoi(ws_name);
|
||||||
|
|
||||||
|
while (entry->workspaces->size < ws_index) {
|
||||||
|
wm_nodearray_push(entry->workspaces, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_nodearray_push(entry->workspaces, wm_json_obj_to_treenode(ws_value));
|
||||||
|
|
||||||
|
json_object_iter_next(&ws_iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_uintarray_push(ret, (uint64_t)entry);
|
||||||
|
json_object_iter_next(&iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object_put(jobj);
|
||||||
|
|
||||||
|
int result = close(fd);
|
||||||
|
if (result < 0)
|
||||||
|
perror("close");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void wm_tree_to_DOT(TreeNode *root, const char *filename)
|
void wm_tree_to_DOT(TreeNode *root, const char *filename)
|
||||||
{
|
{
|
||||||
DEBUG_PRINT("%s\n", __func__);
|
DEBUG_PRINT("%s\n", __func__);
|
||||||
@ -671,45 +1238,54 @@ void wm_nodearray_free(NodeArray *arr)
|
|||||||
free(arr);
|
free(arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
PtrArray wm_ptrarray_new()
|
UIntArray* wm_uintarray_new()
|
||||||
{
|
{
|
||||||
PtrArray arr;
|
UIntArray *arr = calloc(1, sizeof(UIntArray));
|
||||||
|
assert(arr);
|
||||||
|
|
||||||
arr.capacity = 10;
|
arr->capacity = 10;
|
||||||
arr.ptrs = calloc(arr.capacity, sizeof(void*));
|
arr->elements = calloc(arr->capacity, sizeof(void*));
|
||||||
assert(arr.ptrs);
|
assert(arr->elements);
|
||||||
arr.size = 0;
|
arr->size = 0;
|
||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_ptrarray_push(PtrArray *arr, void* ptr)
|
uint64_t wm_uintarray_at(UIntArray *arr, size_t index)
|
||||||
|
{
|
||||||
|
assert(arr);
|
||||||
|
assert(index < arr->size);
|
||||||
|
|
||||||
|
return arr->elements[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_uintarray_push(UIntArray *arr, uint64_t element)
|
||||||
{
|
{
|
||||||
assert(arr);
|
assert(arr);
|
||||||
|
|
||||||
arr->size++;
|
arr->size++;
|
||||||
|
|
||||||
if (arr->size >= arr->capacity) {
|
if (arr->size >= arr->capacity) {
|
||||||
void* temp = calloc(arr->capacity, sizeof(void*));
|
void* temp = calloc(arr->capacity, sizeof(uint64_t));
|
||||||
assert(temp);
|
assert(temp);
|
||||||
memcpy(temp, arr->ptrs, arr->capacity * sizeof(void*));
|
memcpy(temp, arr->elements, arr->capacity * sizeof(uint64_t));
|
||||||
free(arr->ptrs);
|
free(arr->elements);
|
||||||
size_t old_capacity = arr->capacity;
|
size_t old_capacity = arr->capacity;
|
||||||
arr->capacity = old_capacity * 2;
|
arr->capacity = old_capacity * 2;
|
||||||
|
|
||||||
arr->ptrs = calloc(arr->capacity, sizeof(void*));
|
arr->elements = calloc(arr->capacity, sizeof(uint64_t));
|
||||||
assert(arr->ptrs);
|
assert(arr->elements);
|
||||||
memcpy(arr->ptrs, temp, old_capacity * sizeof(void*));
|
memcpy(arr->elements, temp, old_capacity * sizeof(uint64_t));
|
||||||
|
|
||||||
free(temp);
|
free(temp);
|
||||||
arr->ptrs[arr->size - 1] = ptr;
|
arr->elements[arr->size - 1] = element;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
arr->ptrs[arr->size - 1] = ptr;
|
arr->elements[arr->size - 1] = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_ptrarray_pop(PtrArray *arr, void **ret)
|
bool wm_uintarray_pop(UIntArray *arr, uint64_t *ret)
|
||||||
{
|
{
|
||||||
DEBUG_PRINT("%s\n", __func__);
|
DEBUG_PRINT("%s\n", __func__);
|
||||||
assert(arr);
|
assert(arr);
|
||||||
@ -718,12 +1294,12 @@ bool wm_ptrarray_pop(PtrArray *arr, void **ret)
|
|||||||
if (arr->size == 0)
|
if (arr->size == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*ret = arr->ptrs[arr->size - 1];
|
*ret = arr->elements[arr->size - 1];
|
||||||
arr->size--;
|
arr->size--;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_ptrarray_pop_front(PtrArray *arr, void **ret)
|
bool wm_uintarray_pop_front(UIntArray *arr, uint64_t *ret)
|
||||||
{
|
{
|
||||||
assert(arr);
|
assert(arr);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
@ -731,14 +1307,14 @@ bool wm_ptrarray_pop_front(PtrArray *arr, void **ret)
|
|||||||
if (arr->size == 0)
|
if (arr->size == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*ret = arr->ptrs[0];
|
*ret = arr->elements[0];
|
||||||
arr->size--;
|
arr->size--;
|
||||||
memmove(arr->ptrs, arr->ptrs+1, arr->size * sizeof(void*));
|
memmove(arr->elements, arr->elements+1, arr->size * sizeof(uint64_t));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wm_ptrarray_remove(PtrArray *arr, size_t index)
|
bool wm_uintarray_remove(UIntArray *arr, size_t index)
|
||||||
{
|
{
|
||||||
DEBUG_PRINT("%s\n", __func__);
|
DEBUG_PRINT("%s\n", __func__);
|
||||||
assert(arr);
|
assert(arr);
|
||||||
@ -754,21 +1330,47 @@ bool wm_ptrarray_remove(PtrArray *arr, size_t index)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
memmove(arr->ptrs + index, arr->ptrs + index+1, arr->size-1 * sizeof(void*));
|
memmove(arr->elements + index, arr->elements + index+1, arr->size-1 * sizeof(uint64_t));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_ptrarray_free(PtrArray *arr)
|
void wm_uintarray_free(UIntArray *arr)
|
||||||
{
|
{
|
||||||
// DEBUG_PRINT("%s\n", __func__);
|
// DEBUG_PRINT("%s\n", __func__);
|
||||||
assert(arr);
|
assert(arr);
|
||||||
RETURN_IF_NULL(arr->ptrs);
|
RETURN_IF_NULL(arr->elements);
|
||||||
|
|
||||||
arr->capacity = 0;
|
arr->capacity = 0;
|
||||||
arr->size = 0;
|
arr->size = 0;
|
||||||
free(arr->ptrs);
|
free(arr->elements);
|
||||||
arr->ptrs = NULL;
|
arr->elements = NULL;
|
||||||
|
|
||||||
|
free(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t wm_uintarray_2d_index(UIntArray *arr, size_t i, size_t j)
|
||||||
|
{
|
||||||
|
assert(arr);
|
||||||
|
|
||||||
|
return ((uint64_t**)arr->elements)[i][j];
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_logentries_free(UIntArray *entries)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < entries->size; i++) {
|
||||||
|
LogEntry *entry = (LogEntry*)wm_uintarray_at(entries, i);
|
||||||
|
|
||||||
|
for (size_t j = 0; j < entry->workspaces->size; j++) {
|
||||||
|
TreeNode *node = entry->workspaces->nodes[j];
|
||||||
|
if (node != NULL) wm_treenode_free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_nodearray_free(entry->workspaces);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
wm_uintarray_free(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeNode* wm_treenode_ptr_find_focused_client_node(TreeNode *root)
|
TreeNode* wm_treenode_ptr_find_focused_client_node(TreeNode *root)
|
||||||
@ -781,14 +1383,14 @@ TreeNode* wm_treenode_ptr_find_focused_client_node(TreeNode *root)
|
|||||||
NodeArray *visited = wm_nodearray_new();
|
NodeArray *visited = wm_nodearray_new();
|
||||||
wm_nodearray_push(visited, root);
|
wm_nodearray_push(visited, root);
|
||||||
|
|
||||||
PtrArray queue = wm_ptrarray_new();
|
NodeArray *queue = wm_nodearray_new();
|
||||||
|
|
||||||
wm_ptrarray_push(&queue, root);
|
wm_nodearray_push(queue, root);
|
||||||
|
|
||||||
while (queue.size > 0) {
|
while (queue->size > 0) {
|
||||||
TreeNode *node;
|
TreeNode *node;
|
||||||
|
|
||||||
if (!wm_ptrarray_pop_front(&queue, (void**)&node))
|
if (!wm_nodearray_pop_front(queue, &node))
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
if (node->type == NODE_CLIENT && node->client && node->client->focused) {
|
if (node->type == NODE_CLIENT && node->client && node->client->focused) {
|
||||||
@ -809,14 +1411,14 @@ TreeNode* wm_treenode_ptr_find_focused_client_node(TreeNode *root)
|
|||||||
|
|
||||||
if (!_visited) {
|
if (!_visited) {
|
||||||
wm_nodearray_push(visited, child_node);
|
wm_nodearray_push(visited, child_node);
|
||||||
wm_ptrarray_push(&queue, child_node);
|
wm_nodearray_push(queue, child_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret:
|
ret:
|
||||||
wm_nodearray_free(visited);
|
wm_nodearray_free(visited);
|
||||||
wm_ptrarray_free(&queue);
|
wm_nodearray_free(queue);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
66
src/util.h
66
src/util.h
@ -2,6 +2,7 @@
|
|||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <json-c/json.h>
|
#include <json-c/json.h>
|
||||||
@ -30,10 +31,10 @@ typedef struct {
|
|||||||
} NodeArray;
|
} NodeArray;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void **ptrs;
|
uint64_t *elements;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
} PtrArray;
|
} UIntArray;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int x;
|
int x;
|
||||||
@ -53,6 +54,7 @@ struct TreeNode {
|
|||||||
|
|
||||||
Client *client;
|
Client *client;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
|
uint64_t distance;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -60,13 +62,30 @@ typedef struct {
|
|||||||
char *str;
|
char *str;
|
||||||
} WmWorkspaceToStrRet;
|
} WmWorkspaceToStrRet;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
time_t timestamp;
|
||||||
|
bool after;
|
||||||
|
char function_name[128];
|
||||||
|
NodeArray *workspaces;
|
||||||
|
} LogEntry;
|
||||||
|
|
||||||
|
typedef uint64_t (*UpdateCostFunction)(TreeNode*, TreeNode*);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t insert_cost;
|
||||||
|
uint64_t remove_cost;
|
||||||
|
UpdateCostFunction update_cost_function;
|
||||||
|
} TreeEditDistanceCosts;
|
||||||
|
|
||||||
NodeArray* wm_nodearray_new();
|
NodeArray* wm_nodearray_new();
|
||||||
|
void wm_nodearray_set(NodeArray *arr, size_t index, uint64_t value);
|
||||||
void wm_nodearray_push(NodeArray *arr, TreeNode *node);
|
void wm_nodearray_push(NodeArray *arr, TreeNode *node);
|
||||||
bool wm_nodearray_pop(NodeArray *arr, TreeNode **ret);
|
bool wm_nodearray_pop(NodeArray *arr, TreeNode **ret);
|
||||||
bool wm_nodearray_pop_front(NodeArray *arr, TreeNode **ret);
|
bool wm_nodearray_pop_front(NodeArray *arr, TreeNode **ret);
|
||||||
void wm_nodearray_clear(NodeArray *arr);
|
void wm_nodearray_clear(NodeArray *arr);
|
||||||
bool wm_nodearray_remove(NodeArray *arr, size_t index);
|
bool wm_nodearray_remove(NodeArray *arr, size_t index);
|
||||||
void wm_nodearray_free(NodeArray *arr);
|
void wm_nodearray_free(NodeArray *arr);
|
||||||
|
TreeNode* wm_nodearray_at(NodeArray *arr, size_t index);
|
||||||
|
|
||||||
TreeNode* wm_treenode_new(NodeType type, TreeNode *parent);
|
TreeNode* wm_treenode_new(NodeType type, TreeNode *parent);
|
||||||
void wm_treenode_free(TreeNode *node);
|
void wm_treenode_free(TreeNode *node);
|
||||||
@ -74,20 +93,29 @@ bool wm_treenode_is_empty(TreeNode *node);
|
|||||||
void wm_treenode_split_space(TreeNode *node, Rect *ret1, Rect *ret2);
|
void wm_treenode_split_space(TreeNode *node, Rect *ret1, Rect *ret2);
|
||||||
void wm_treenode_recalculate_space(TreeNode *node);
|
void wm_treenode_recalculate_space(TreeNode *node);
|
||||||
void wm_treenode_swap(TreeNode *root, TreeNode *node1, TreeNode* node2);
|
void wm_treenode_swap(TreeNode *root, TreeNode *node1, TreeNode* node2);
|
||||||
|
void wm_treenode_add_child(TreeNode *node, TreeNode *child);
|
||||||
TreeNode* wm_treenode_remove_client(Wm *wm, TreeNode *root, Client *client);
|
TreeNode* wm_treenode_remove_client(Wm *wm, TreeNode *root, Client *client);
|
||||||
void wm_treenode_remove_node(Wm *wm, TreeNode *root, TreeNode *node);
|
void wm_treenode_remove_node(Wm *wm, TreeNode *root, TreeNode *node);
|
||||||
int wm_get_node_index(TreeNode *parent, unsigned int node_id);
|
int wm_get_node_index(TreeNode *parent, unsigned int node_id);
|
||||||
|
|
||||||
void wm_tree_to_DOT(TreeNode *root, const char *filename);
|
void wm_tree_to_DOT(TreeNode *root, const char *filename);
|
||||||
void wm_node_type_to_str(NodeType type, char *buf, size_t bufsize);
|
void wm_node_type_to_str(NodeType type, char *buf, size_t bufsize);
|
||||||
|
UIntArray* wm_nonempty_workspaces_to_strptrarray(Wm *wm);
|
||||||
|
NodeType wm_node_type_from_str(char *buf, size_t bufsize);
|
||||||
char* wm_treenode_to_str(TreeNode *node);
|
char* wm_treenode_to_str(TreeNode *node);
|
||||||
void wm_treenode_print(TreeNode *node);
|
void wm_treenode_print(TreeNode *node);
|
||||||
|
TreeNode* wm_json_obj_to_treenode(struct json_object *jobj);
|
||||||
|
|
||||||
|
UIntArray* wm_uintarray_new();
|
||||||
|
uint64_t wm_uintarray_at(UIntArray *arr, size_t index);
|
||||||
|
void wm_uintarray_set(UIntArray *arr, size_t index, uint64_t value);
|
||||||
|
void wm_uintarray_push(UIntArray *arr, uint64_t element);
|
||||||
|
bool wm_uintarray_pop(UIntArray *arr, uint64_t *ret);
|
||||||
|
bool wm_uintarray_pop_front(UIntArray *arr, uint64_t *ret);
|
||||||
|
bool wm_uintarray_remove(UIntArray *arr, size_t index);
|
||||||
|
void wm_uintarray_free(UIntArray *arr);
|
||||||
|
uint64_t wm_uintarray_2d_index(UIntArray *arr, size_t i, size_t j);
|
||||||
|
|
||||||
PtrArray wm_ptrarray_new();
|
|
||||||
void wm_ptrarray_push(PtrArray *arr, void* ptr);
|
|
||||||
bool wm_ptrarray_pop(PtrArray *arr, void **ret);
|
|
||||||
bool wm_ptrarray_pop_front(PtrArray *arr, void **ret);
|
|
||||||
bool wm_ptrarray_remove(PtrArray *arr, size_t index);
|
|
||||||
void wm_ptrarray_free(PtrArray *arr);
|
|
||||||
TreeNode* wm_treenode_ptr_find_focused_client_node(TreeNode *root);
|
TreeNode* wm_treenode_ptr_find_focused_client_node(TreeNode *root);
|
||||||
TreeNode* wm_treenode_ptr_find_client_node(TreeNode *root, Client *client);
|
TreeNode* wm_treenode_ptr_find_client_node(TreeNode *root, Client *client);
|
||||||
NodeArray* wm_treenode_find_client_nodes(TreeNode *root);
|
NodeArray* wm_treenode_find_client_nodes(TreeNode *root);
|
||||||
@ -97,8 +125,28 @@ void wm_log_state(Wm *wm, const char *prefixstr, const char* logfile);
|
|||||||
|
|
||||||
TreeNode* wm_treenode_lmd(TreeNode *node);
|
TreeNode* wm_treenode_lmd(TreeNode *node);
|
||||||
NodeArray* wm_treenode_all_lmds(TreeNode *node);
|
NodeArray* wm_treenode_all_lmds(TreeNode *node);
|
||||||
|
UIntArray* wm_treenode_all_lmds_index(TreeNode *node);
|
||||||
NodeArray* wm_postorder_traversal(TreeNode *tree);
|
NodeArray* wm_postorder_traversal(TreeNode *tree);
|
||||||
bool wm_is_treenode_keyroot(TreeNode *node);
|
bool wm_is_treenode_keyroot(TreeNode *node, NodeArray *postorder);
|
||||||
NodeArray* wm_treenode_all_keyroots(TreeNode *node);
|
NodeArray* wm_treenode_all_keyroots(TreeNode *node);
|
||||||
|
UIntArray* wm_treenode_all_keyroots_index(TreeNode *node);
|
||||||
|
bool wm_nodes_are_equal(TreeNode *node1, TreeNode *node2);
|
||||||
|
|
||||||
|
void wm_treedist(TreeNode *tree1, TreeNode *tree2, size_t i, size_t j,
|
||||||
|
UIntArray *dists, TreeEditDistanceCosts costs);
|
||||||
|
|
||||||
|
size_t wm_tree_edit_distance(TreeNode *tree1, TreeNode *tree2, TreeEditDistanceCosts costs);
|
||||||
|
|
||||||
|
void wm_logfile_init(const char *path);
|
||||||
|
|
||||||
|
/* UIntArray<LogEntry*> */
|
||||||
|
void wm_logentries_free(UIntArray *entries);
|
||||||
|
|
||||||
|
/* UIntArray<LogEntry*> */
|
||||||
|
UIntArray* wm_read_log(const char* filename);
|
||||||
|
|
||||||
|
/* UIntArray<LogEntry*> */
|
||||||
|
void wm_logentries_calculate_distances(UIntArray *log_entries, TreeNode *curr_tree,
|
||||||
|
UpdateCostFunction update_cost_function);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
38
src/wm.c
38
src/wm.c
@ -17,21 +17,21 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "wm.h"
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <X11/X.h>
|
#include <X11/X.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
#include <X11/extensions/Xinerama.h>
|
#include <X11/extensions/Xinerama.h>
|
||||||
#include <asm-generic/errno.h>
|
#include "wm.h"
|
||||||
#include <limits.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "handler.h"
|
#include "handler.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
@ -410,10 +410,11 @@ void wm_mainloop(Wm *wm)
|
|||||||
|
|
||||||
void wm_init(Wm *wm)
|
void wm_init(Wm *wm)
|
||||||
{
|
{
|
||||||
XSetWindowAttributes xa;
|
DEBUG_PRINT("wm_init\n");
|
||||||
Display *d;
|
DEBUG_PRINT("pid: %ld\n", getpid());
|
||||||
|
|
||||||
signal(SIGINT, wm_sigint_handler);
|
XSetWindowAttributes xa;
|
||||||
|
// signal(SIGINT, wm_sigint_handler);
|
||||||
|
|
||||||
wm->config = (Config) {0};
|
wm->config = (Config) {0};
|
||||||
wm_cfg_init_def(&wm->config);
|
wm_cfg_init_def(&wm->config);
|
||||||
@ -426,12 +427,11 @@ void wm_init(Wm *wm)
|
|||||||
ConfigFile configfile = {0};
|
ConfigFile configfile = {0};
|
||||||
wm_configfile_init(&configfile, path);
|
wm_configfile_init(&configfile, path);
|
||||||
wm_configfile_read(&configfile, &wm->config);
|
wm_configfile_read(&configfile, &wm->config);
|
||||||
|
wm_logfile_init(wm->config.log_path);
|
||||||
|
wm->log_entries = wm_read_log(wm->config.log_path);
|
||||||
|
|
||||||
DEBUG_PRINT("wm_init\n")
|
wm->display = wm_connect_display();
|
||||||
DEBUG_PRINT("pid: %ld\n", ((long)getpid()))
|
wm_monitors_open_all(wm, wm->display);
|
||||||
d = wm_connect_display();
|
|
||||||
wm->display = d;
|
|
||||||
wm_monitors_open_all(wm, d);
|
|
||||||
|
|
||||||
char *display_string = DisplayString(wm->display);
|
char *display_string = DisplayString(wm->display);
|
||||||
setenv("DISPLAY", display_string, 1);
|
setenv("DISPLAY", display_string, 1);
|
||||||
@ -443,7 +443,7 @@ void wm_init(Wm *wm)
|
|||||||
|
|
||||||
DEBUG_PRINT("root window: %ld\n", wm->root.window);
|
DEBUG_PRINT("root window: %ld\n", wm->root.window);
|
||||||
|
|
||||||
XSync(d, false);
|
XSync(wm->display, false);
|
||||||
|
|
||||||
xa.event_mask = StructureNotifyMask | StructureNotifyMask |
|
xa.event_mask = StructureNotifyMask | StructureNotifyMask |
|
||||||
SubstructureNotifyMask | SubstructureRedirectMask |
|
SubstructureNotifyMask | SubstructureRedirectMask |
|
||||||
|
13
src/wm.h
13
src/wm.h
@ -67,16 +67,14 @@ if (c == NULL) \
|
|||||||
|
|
||||||
#define WM_PREFIX_LEN 4096
|
#define WM_PREFIX_LEN 4096
|
||||||
|
|
||||||
#define WM_LOGFILENAME "./log"
|
#define WM_LOG_STATE_START(wm) do { \
|
||||||
|
wm_log_state(wm, __func__, (wm)->config.log_path); \
|
||||||
#define WM_LOG_STATE_START(wm) do { \
|
|
||||||
wm_log_state(wm, __func__, WM_LOGFILENAME); \
|
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
#define WM_LOG_STATE_END(wm) do { \
|
#define WM_LOG_STATE_END(wm) do { \
|
||||||
char __prefix[WM_PREFIX_LEN] = {0}; \
|
char __prefix[WM_PREFIX_LEN] = {0}; \
|
||||||
snprintf(__prefix, WM_PREFIX_LEN, "after %s", __func__); \
|
snprintf(__prefix, WM_PREFIX_LEN, "%s:after", __func__); \
|
||||||
wm_log_state(wm, __prefix, WM_LOGFILENAME); \
|
wm_log_state(wm, __prefix, (wm)->config.log_path); \
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
typedef struct Client Client;
|
typedef struct Client Client;
|
||||||
@ -140,6 +138,9 @@ struct Wm {
|
|||||||
|
|
||||||
bool log_after_maprequest;
|
bool log_after_maprequest;
|
||||||
int socket_fd;
|
int socket_fd;
|
||||||
|
|
||||||
|
/* UIntArray<LogEntry*> */
|
||||||
|
UIntArray *log_entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
Monitor wm_monitor_open(Display *d, XineramaScreenInfo info);
|
Monitor wm_monitor_open(Display *d, XineramaScreenInfo info);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user