Compare commits

..

2 Commits

Author SHA1 Message Date
06c25ff838 free log_entries in wm_exit 2024-04-02 11:42:12 +02:00
5cbe15a899 add comments to function prototype declarations 2024-04-02 11:40:51 +02:00
4 changed files with 363 additions and 49 deletions

View File

@ -49,31 +49,118 @@ struct Client {
bool is_pid_set;
};
/**
* Client functions
*/
/**
* Converts the position of `c` to a `XWindowChanges` structure.
*/
XWindowChanges wm_client_to_xwchanges(Client *c);
/**
* Returns the client associated with `w`.
* Returns NULL if it could not find the client.
*/
Client* wm_client_find(Wm* wm, Window w);
/**
* Initializes a new Client.
*/
Client* wm_client_create(Wm *wm, Window w);
void wm_client_handle_window_types(Wm *wm, Client *c, XMapRequestEvent e);
/**
* Unmaps `c->window` and `c->frame`.
*/
void wm_client_hide(Wm *wm, Client *c);
/**
* Maps `c->window` and `c->frame`.
*/
void wm_client_show(Wm* wm, Client *c);
/**
* Focuses `c`.
*/
void wm_client_focus(Wm* wm, Client *c);
/**
* Focuses the client in the direction `dir`, relative to the current focused
* client.
*/
void wm_client_focus_dir(Wm* wm, Client *c, int dir);
/**
* Swaps the client in the direction `dir`, relative to the current focused
* client.
*/
void wm_client_swap_dir(Wm* wm, Client *c, int dir);
/**
* Frees `c`, and its dynamically allocated fields.
*/
void wm_client_free(Wm *wm, Client *c);
/**
* Destroys the window and frame associated with `c`, frees `c`, and recalculates
* the layout.
*/
void wm_client_kill(Wm *wm, Client *c);
/**
* Sets the window property with the atom of `name`, with the value `data`.
*/
void wm_client_set_atom(Wm *wm, Client *c, const char *name, const unsigned char *data,
Atom type, int nelements);
/**
* Reads the window poperty with the atom of `name`, and returns the value
* in `atom_ret`, and returns the number of read items in `nitems_ret`.
*/
Atom wm_client_get_atom(Wm *wm, Client *c, const char *name, unsigned char **atom_ret,
unsigned long *nitems_ret);
/**
* Finds the client in the direction `dir` relative to `c`.
*/
Client* wm_client_get_dir_rel_c(Client *c, int dir);
/**
* Returns the currently focused client.
*/
Client* wm_client_get_focused(Wm* wm);
/**
* Draws border for client `c`.
*/
void wm_client_border(Wm* wm, Client *c);
/**
* Draws focused border for client `c`.
*/
void wm_client_border_focused(Wm* wm, Client *c);
/**
* Draws borders for all clients in `m`.
*/
void wm_monitor_clients_border(Wm* wm, Monitor *m);
/**
* Returns true if `c` is focused, false if `c` is not focused.
*/
bool wm_client_is_focused(Wm* wm, Client *c);
/**
* Draws server-side decorations for `c`.
*/
void wm_client_draw_frame(Wm *wm, Client *c);
/**
* Draws server-side decorations for all clients in `m`.
*/
void wm_monitor_draw_all_clients_frame(Wm* wm, Monitor *m);
#endif

View File

@ -225,10 +225,8 @@ UIntArray* wm_nonempty_workspaces_to_strptrarray(Wm *wm)
return ret;
}
json_object* wm_state_to_json_object(Wm *wm, const char *prefixstr)
json_object* wm_state_to_json_object(Wm *wm)
{
assert(prefixstr);
json_object *ret = json_object_new_object();
UIntArray *ws_str = wm_nonempty_workspaces_to_strptrarray(wm);
@ -244,6 +242,7 @@ json_object* wm_state_to_json_object(Wm *wm, const char *prefixstr)
free(ws_with_index->str);
free(ws_with_index);
}
wm_uintarray_free(ws_str);
return ret;
}
@ -258,7 +257,7 @@ void wm_log_state(Wm *wm, const char *prefixstr, const char* logfile)
char prefix[WM_PREFIX_LEN + 32] = {0};
snprintf(prefix, sizeof(prefix), "%lu:%s", time(NULL), prefixstr);
json_object *log_entry_obj = wm_state_to_json_object(wm, prefixstr);
json_object *log_entry_obj = wm_state_to_json_object(wm);
int fd = -1;
struct json_object *jobj = NULL;
@ -503,14 +502,6 @@ UIntArray* wm_treenode_all_keyroots_index(TreeNode *node)
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)
@ -798,11 +789,12 @@ static void recursive_mkdir(char *path, mode_t mode)
void wm_logfile_init(const char *path)
{
char *dup = strdup(path);
char *log_file_dir = dirname(dup);
if (access(path, F_OK) == 0) return;
char *dup = strdup(path);
char *log_file_dir = dirname(dup);
int ret = access(log_file_dir, W_OK | R_OK);
if (ret == 0) {
@ -987,16 +979,6 @@ void wm_tree_to_DOT(TreeNode *root, const char *filename)
wm_nodearray_free(all_nodes);
}
int wm_get_node_index(TreeNode *parent, unsigned int node_id)
{
for (size_t i = 0; i < parent->children->size; i++) {
if (node_id == parent->children->nodes[i]->id)
return i;
}
return -1;
}
void wm_treenode_remove_node(Wm *wm, TreeNode *root, TreeNode *node)
{
DEBUG_PRINT("%s\n", __func__);
@ -1393,7 +1375,18 @@ void wm_logentries_free(UIntArray *entries)
for (size_t j = 0; j < entry->workspaces->size; j++) {
TreeNode *node = entry->workspaces->nodes[j];
if (node != NULL) wm_treenode_free(node);
if (node == NULL) continue;
NodeArray *children = wm_postorder_traversal(node);
for (size_t k = 0; k < children->size; k++) {
if (children->nodes[k]->type == NODE_CLIENT) {
free(children->nodes[k]->client->name);
free(children->nodes[k]->client);
}
wm_treenode_free(children->nodes[k]);
}
wm_nodearray_free(children);
}
wm_nodearray_free(entry->workspaces);

View File

@ -77,76 +77,308 @@ typedef struct {
UpdateCostFunction update_cost_function;
} TreeEditDistanceCosts;
/**
* Functions for NodeArray operations
*/
/**
* Initializes a new NodeArray.
*/
NodeArray* wm_nodearray_new();
void wm_nodearray_set(NodeArray *arr, size_t index, uint64_t value);
/**
* Adds `node` to the end of `arr`. If the capacity is lower than the
* new size, it resizes the array.
*/
void wm_nodearray_push(NodeArray *arr, TreeNode *node);
/**
* Removes the last element, and returns it in `ret`.
*/
bool wm_nodearray_pop(NodeArray *arr, TreeNode **ret);
/**
* Removes the first element, and returns it in `ret`.
*/
bool wm_nodearray_pop_front(NodeArray *arr, TreeNode **ret);
/**
* Removes all elements from `arr`, and sets its size to 0.
*/
void wm_nodearray_clear(NodeArray *arr);
/**
* Removes the element at the provided index. Returns true on success, false
* on failure.
*/
bool wm_nodearray_remove(NodeArray *arr, size_t index);
/**
* Frees the array.
*/
void wm_nodearray_free(NodeArray *arr);
TreeNode* wm_nodearray_at(NodeArray *arr, size_t index);
/**
* Functions for TreeNode operations
*/
/**
* Initializes a new TreeNode.
*/
TreeNode* wm_treenode_new(NodeType type, TreeNode *parent);
void wm_treenode_free(TreeNode *node);
bool wm_treenode_is_empty(TreeNode *node);
void wm_treenode_split_space(TreeNode *node, Rect *ret1, Rect *ret2);
void wm_treenode_recalculate_space(TreeNode *node);
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);
void wm_treenode_remove_node(Wm *wm, TreeNode *root, TreeNode *node);
int wm_get_node_index(TreeNode *parent, unsigned int node_id);
/**
* Frees `node`, and the `children` NodeArray field.
*/
void wm_treenode_free(TreeNode *node);
/**
* Returns true if `node` has no children.
*/
bool wm_treenode_is_empty(TreeNode *node);
/**
* Splits the available space between `ret1` and `ret2`, based on `node->type`.
*/
void wm_treenode_split_space(TreeNode *node, Rect *ret1, Rect *ret2);
/**
* Asserts `node->children->size == 2`, and calls split_space on first and second
* child.
*/
void wm_treenode_recalculate_space(TreeNode *node);
/**
* Swaps the clients of the `node1` and `node2`.
*/
void wm_treenode_swap(TreeNode *root, TreeNode *node1, TreeNode* node2);
/**
* Pushes child to `node->children`, and sets `child->parent` to node.
*/
void wm_treenode_add_child(TreeNode *node, TreeNode *child);
/**
* Finds `client` in `root`, removes and frees the node associated with it,
* and recalculates layout.
*/
TreeNode* wm_treenode_remove_client(Wm *wm, TreeNode *root, Client *client);
/**
* Finds `node` in `root`, removes and frees it, and recalculates layout.
*/
void wm_treenode_remove_node(Wm *wm, TreeNode *root, TreeNode *node);
/**
* Converts `tree` to DOT file format.
* Use `dot <filename> -Tsvg > output.svg` to convert the DOT file to svg.
*/
void wm_tree_to_DOT(TreeNode *root, const char *filename);
/**
* Converts `type` to a string, and writes it to `buf`.
*/
void wm_node_type_to_str(NodeType type, char *buf, size_t bufsize);
/**
* Finds non empty workspaces, and converts them to JSON strings.
* Return value: `UIntArray<WmWorkspaceToStrRet*>`
*/
UIntArray* wm_nonempty_workspaces_to_strptrarray(Wm *wm);
/**
* Converts a string to NodeType.
*/
NodeType wm_node_type_from_str(char *buf, size_t bufsize);
/**
* Converts `node` to a JSON string.
*/
char* wm_treenode_to_str(TreeNode *node);
/**
* Converts `node` to a JSON string, and if DEBUG is defined, prints it to stderr.
*/
void wm_treenode_print(TreeNode *node);
/**
* Parses a `json_object` to a TreeNode.
*/
TreeNode* wm_json_obj_to_treenode(struct json_object *jobj);
/**
* Functions for UIntArray operations
* UIntArray can be used as a generic pointer container, if
* `_Static_assert(sizeof(uint64_t) == sizeof(<pointer_type>), "")`.
*/
/**
* Initializes a new UIntArray.
*/
UIntArray* wm_uintarray_new();
/**
* Asserts `index < arr->size`, and returns `arr->elements[index]`.
*/
uint64_t wm_uintarray_at(UIntArray *arr, size_t index);
void wm_uintarray_set(UIntArray *arr, size_t index, uint64_t value);
/**
* Adds `node` to the end of `arr`. If the capacity is lower than the
* new size, it resizes the array.
*/
void wm_uintarray_push(UIntArray *arr, uint64_t element);
/**
* Removes the last element, and returns it in `ret`.
*/
bool wm_uintarray_pop(UIntArray *arr, uint64_t *ret);
/**
* Removes the first element, and returns it in `ret`.
*/
bool wm_uintarray_pop_front(UIntArray *arr, uint64_t *ret);
/**
* Removes the element at the provided index. Returns true on success, false
* on failure.
*/
bool wm_uintarray_remove(UIntArray *arr, size_t index);
/**
* Frees the array.
*/
void wm_uintarray_free(UIntArray *arr);
/**
* Returns ((uint64_t**)arr->elements)[i][j].
*/
uint64_t wm_uintarray_2d_index(UIntArray *arr, size_t i, size_t j);
/**
* TreeNode utility functions
*/
/**
* Find the node associated with the currently focused client, and returns it.
* Returns NULL if no client is focused.
*/
TreeNode* wm_treenode_ptr_find_focused_client_node(TreeNode *root);
/**
* Find the node associated with `client`, and returns it.
* Returns NULL if it could not find `client`.
*/
TreeNode* wm_treenode_ptr_find_client_node(TreeNode *root, Client *client);
/**
* Returns all `NODE_CLIENT` type descendant nodes of `root`.
*/
NodeArray* wm_treenode_find_client_nodes(TreeNode *root);
/**
* Returns the sibling node of `node`.
* Returns NULL on error.
*/
TreeNode* wm_treenode_split_get_sibling(TreeNode *node);
/**
* Returns descendant nodes of `root`.
*/
NodeArray* wm_all_nodes_to_array(TreeNode *root);
json_object* wm_state_to_json_object(Wm *wm, const char *prefixstr);
/**
* Converts all non empty workspace trees to a `json_object`.
*/
json_object* wm_state_to_json_object(Wm *wm);
/**
* Writes current state encoded as JSON to logfile.
* If logfile exists, and is not empty, appends the state to the JSON object in
* logfile.
*/
void wm_log_state(Wm *wm, const char *prefixstr, const char* logfile);
TreeNode* wm_treenode_lmd(TreeNode *node);
NodeArray* wm_treenode_all_lmds(TreeNode *node);
UIntArray* wm_treenode_all_lmds_index(TreeNode *node);
NodeArray* wm_postorder_traversal(TreeNode *tree);
bool wm_is_treenode_keyroot(TreeNode *node, NodeArray *postorder);
NodeArray* wm_treenode_all_keyroots(TreeNode *node);
UIntArray* wm_treenode_all_keyroots_index(TreeNode *node);
bool wm_nodes_are_equal(TreeNode *node1, TreeNode *node2);
/**
* Utility functions for tree edit distance
*/
/**
* Returns the leftmost descendant of `node`.
*/
TreeNode* wm_treenode_lmd(TreeNode *node);
/**
* Returns all leftmost descendants of `node`.
*/
NodeArray* wm_treenode_all_lmds(TreeNode *node);
/**
* Returns all leftmost descendants of `node`, as indexes of a postorder
* traversal array.
*/
UIntArray* wm_treenode_all_lmds_index(TreeNode *node);
/**
* Returns all nodes of `tree`, in postorder traversal order.
*/
NodeArray* wm_postorder_traversal(TreeNode *tree);
/**
* Returns true of `node` is a keyroot.
* LR_keyroots(T) = {k | there exists no k > k such that l(k)= l(k)}.
* l = leftmost descendant
*/
bool wm_is_treenode_keyroot(TreeNode *node, NodeArray *postorder);
/**
* Returns all keyroots of `node`.
*/
NodeArray* wm_treenode_all_keyroots(TreeNode *node);
/**
* Returns all keyroots of `node`, as indexes of a postorder traversal array.
*/
UIntArray* wm_treenode_all_keyroots_index(TreeNode *node);
/**
* Calculates the distance of the subtrees of `tree1` and `tree2`, at indexes
* `i` and `j`.
*/
void wm_treedist(TreeNode *tree1, TreeNode *tree2, size_t i, size_t j,
UIntArray *dists, TreeEditDistanceCosts costs);
/**
* Calculates the distance of `tree1` and `tree2` using the edit costs `costs`.
*/
size_t wm_tree_edit_distance(TreeNode *tree1, TreeNode *tree2, TreeEditDistanceCosts costs);
/**
* Creates the logfile at the provided path.
*/
void wm_logfile_init(const char *path);
/* UIntArray<LogEntry*> */
/**
* Frees all dynamically allocated fields of the array elements, and frees the
* array.
* Type of `entries`: UIntArray<LogEntry*>
*/
void wm_logentries_free(UIntArray *entries);
/* UIntArray<LogEntry*> */
/**
* Parses the JSON objects in the file at path `filename`, and populates a LogEntry*
* array with the parsed values.
* Return type: UIntArray<LogEntry*>
*/
UIntArray* wm_read_log(const char* filename);
/* UIntArray<LogEntry*> */
/**
* Calculates the tree edit distance of `log_entries[i]` and `curr_tree`.
* Stores the distance in `log_entries[i]->workspaces[j]->tree->distance`.
* Type of `log_entries`: UIntArray<LogEntry*>
*/
void wm_logentries_calculate_distances(UIntArray *log_entries, TreeNode *curr_tree,
UpdateCostFunction update_cost_function);

View File

@ -535,6 +535,8 @@ void wm_exit(Wm *wm)
XftColorFree(wm->display, visual, cmap, &wm->titlebar_text_color);
XftFontClose(wm->display, wm->titlebar_font);
wm_logentries_free(wm->log_entries);
XCloseDisplay(wm->display);
exit(EXIT_SUCCESS);