From cee972280d46a27c1f6e5c004aa23f4809cfd9d0 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 7 Aug 2010 02:10:05 +0200 Subject: [PATCH] Add comments --- i3bar/include/child.h | 12 ++++ i3bar/include/ipc.h | 16 ++++++ i3bar/include/outputs.h | 31 +++++++--- i3bar/include/workspaces.h | 31 ++++++---- i3bar/include/xcb.h | 39 ++++++++++++- i3bar/src/child.c | 52 ++++++++++++++--- i3bar/src/ipc.c | 54 +++++++++++++++++ i3bar/src/outputs.c | 46 +++++++++++++++ i3bar/src/workspaces.c | 35 +++++++++++ i3bar/src/xcb.c | 115 ++++++++++++++++++++++++++++++++----- 10 files changed, 389 insertions(+), 42 deletions(-) diff --git a/i3bar/include/child.h b/i3bar/include/child.h index 3d3c28c9..5d945235 100644 --- a/i3bar/include/child.h +++ b/i3bar/include/child.h @@ -3,7 +3,19 @@ #define STDIN_CHUNK_SIZE 1024 +/* + * Start a child-process with the specified command and reroute stdin. + * We actually start a $SHELL to execute the command so we don't have to care + * about arguments and such + * + */ void start_child(char *command); + +/* + * kill()s the child-prozess (if existend) and closes and + * free()s the stdin- and sigchild-watchers + * + */ void kill_child(); #endif diff --git a/i3bar/include/ipc.h b/i3bar/include/ipc.h index b3760d2a..c9196044 100644 --- a/i3bar/include/ipc.h +++ b/i3bar/include/ipc.h @@ -3,8 +3,24 @@ #include +/* + * Initiate a connection to i3. + * socket-path must be a valid path to the ipc_socket of i3 + * + */ int init_connection(const char *socket_path); + +/* + * Sends a Message to i3. + * type must be a valid I3_IPC_MESSAGE_TYPE (see i3/ipc.h for further information) + * + */ int i3_send_msg(uint32_t type, const char* payload); + +/* + * Subscribe to all the i3-events, we need + * + */ void subscribe_events(); #endif diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 64fa8563..8a12def4 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -10,23 +10,36 @@ typedef struct i3_output i3_output; SLIST_HEAD(outputs_head, i3_output); struct outputs_head *outputs; +/* + * Start parsing the received json-string + * + */ void parse_outputs_json(char* json); + +/* + * Initiate the output-list + * + */ void init_outputs(); -void free_outputs(); + +/* + * Returns the output with the given name + * + */ i3_output* get_output_by_name(char* name); struct i3_output { - char* name; - bool active; - int ws; - rect rect; + char* name; /* Name of the output */ + bool active; /* If the output is active */ + int ws; /* The number of the currently visible ws */ + rect rect; /* The rect (relative to the root-win) */ - xcb_window_t bar; - xcb_gcontext_t bargc; + xcb_window_t bar; /* The id of the bar of the output */ + xcb_gcontext_t bargc; /* The graphical context of the bar */ - struct ws_head *workspaces; + struct ws_head *workspaces; /* The workspaces on this output */ - SLIST_ENTRY(i3_output) slist; + SLIST_ENTRY(i3_output) slist; /* Pointer for the SLIST-Macro */ }; #endif diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index e32e7c21..1617d0f1 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -9,22 +9,31 @@ typedef struct i3_ws i3_ws; TAILQ_HEAD(ws_head, i3_ws); +/* + * Start parsing the received json-string + * + */ void parse_workspaces_json(); + +/* + * free() all workspace data-structures + * + */ void free_workspaces(); struct i3_ws { - int num; - char *name; - xcb_char2b_t *ucs2_name; - int name_glyphs; - int name_width; - bool visible; - bool focused; - bool urgent; - rect rect; - struct i3_output *output; + int num; /* The internal number of the ws */ + char *name; /* The name (in utf8) of the ws */ + xcb_char2b_t *ucs2_name; /* The name (in ucs2) of the ws */ + int name_glyphs; /* The length (in glyphs) of the name */ + int name_width; /* The rendered width of the name */ + bool visible; /* If the ws is currently visible on an output */ + bool focused; /* If the ws is currently focused */ + bool urgent; /* If the urgent-hint of the ws is set */ + rect rect; /* The rect of the ws (not used (yet)) */ + struct i3_output *output; /* The current output of the ws */ - TAILQ_ENTRY(i3_ws) tailq; + TAILQ_ENTRY(i3_ws) tailq; /* Pointer for the TAILQ-Macro */ }; #endif diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 7bc76e62..c22b1e43 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -3,12 +3,49 @@ int font_height; +/* + * Initialize xcb and use the specified fontname for text-rendering + * + */ void init_xcb(); + +/* + * Cleanup the xcb-stuff. + * Called once, before the program terminates. + * + */ void clean_xcb(); + +/* + * Get the earlier requested atoms and save them in the prepared data-structure + * + */ void get_atoms(); -void destroy_windows(); + +/* + * Destroy the bar of the specified output + * + */ +void destroy_window(i3_output *output); + +/* + * Reconfigure all bars and create new for newly activated outputs + * + */ void reconfig_windows(); + +/* + * Render the bars, with buttons and statusline + * + */ void draw_bars(); + +/* + * Calculate the rendered width of a string with the configured font. + * The string has to be encoded in ucs2 and glyph_len has to be the length + * of the string (in width) + * + */ int get_string_width(xcb_char2b_t *string, int glyph_len); #endif diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 362a56d4..b14f873b 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -10,22 +10,33 @@ #include "common.h" -ev_io *child_io; +/* stdin- and sigchild-watchers */ +ev_io *stdin_io; ev_child *child_sig; +/* + * Stop and free() the stdin- and sigchild-watchers + * + */ void cleanup() { - ev_io_stop(main_loop, child_io); + ev_io_stop(main_loop, stdin_io); ev_child_stop(main_loop, child_sig); - FREE(child_io); + FREE(stdin_io); FREE(child_sig); FREE(statusline); } +/* + * Since we don't use colors and stuff, we strip the dzen-formatstrings + * + */ void strip_dzen_formats(char *buffer) { char *src = buffer; char *dest = buffer; while (*src != '\0') { + /* ^ starts a format-string, ) ends it */ if (*src == '^') { + /* We replace the seperators from i3status by pipe-symbols */ if (!strncmp(src, "^ro", strlen("^ro"))) { *(dest++) = ' '; *(dest++) = '|'; @@ -41,10 +52,16 @@ void strip_dzen_formats(char *buffer) { dest++; } } + /* The last character is \n, which xcb cannot display */ *(--dest) = '\0'; } -void child_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { +/* + * Callbalk for stdin. We read a line from stdin, strip dzen-formats and store + * the result in statusline + * + */ +void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { int fd = watcher->fd; int n = 0; int rec = 0; @@ -85,11 +102,25 @@ void child_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { draw_bars(); } +/* + * We received a sigchild, meaning, that the child-process terminated. + * We simply free the respective data-structures and don't care for input + * anymore + * + */ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { - printf("Child (pid: %d) unexpectedly exited with status %d\n", child_pid, watcher->rstatus); + printf("Child (pid: %d) unexpectedly exited with status %d\n", + child_pid, + watcher->rstatus); cleanup(); } +/* + * Start a child-process with the specified command and reroute stdin. + * We actually start a $SHELL to execute the command so we don't have to care + * about arguments and such + * + */ void start_child(char *command) { child_pid = 0; if (command != NULL) { @@ -123,9 +154,9 @@ void start_child(char *command) { fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); - child_io = malloc(sizeof(ev_io)); - ev_io_init(child_io, &child_io_cb, STDIN_FILENO, EV_READ); - ev_io_start(main_loop, child_io); + stdin_io = malloc(sizeof(ev_io)); + ev_io_init(stdin_io, &stdin_io_cb, STDIN_FILENO, EV_READ); + ev_io_start(main_loop, stdin_io); /* We must cleanup, if the child unexpectedly terminates */ child_sig = malloc(sizeof(ev_io)); @@ -134,6 +165,11 @@ void start_child(char *command) { } +/* + * kill()s the child-prozess (if existend) and closes and + * free()s the stdin- and sigchild-watchers + * + */ void kill_child() { if (child_pid != 0) { kill(child_pid, SIGQUIT); diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 83ae4cec..86c61f86 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -13,6 +13,10 @@ ev_io *i3_connection; typedef void(*handler_t)(char*); +/* + * Get a connect to the IPC-interface of i3 and return a filedescriptor + * + */ int get_ipc_fd(const char *socket_path) { int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); if (sockfd == -1) { @@ -31,21 +35,39 @@ int get_ipc_fd(const char *socket_path) { return sockfd; } +/* + * Called, when we get a reply to a command from i3. + * Since i3 does not give us much feedback on commands, we do not much + * + */ void got_command_reply(char *reply) { /* FIXME: Error handling for command-replies */ } +/* + * Called, when we get a reply with workspaces-data + * + */ void got_workspace_reply(char *reply) { printf("Got Workspace-Data!\n"); parse_workspaces_json(reply); draw_bars(); } +/* + * Called, when we get a reply for a subscription. + * Since i3 does not give us much feedback on commands, we do not much + * + */ void got_subscribe_reply(char *reply) { printf("Got Subscribe Reply: %s\n", reply); /* FIXME: Error handling for subscribe-commands */ } +/* + * Called, when we get a reply with outputs-data + * + */ void got_output_reply(char *reply) { printf("Parsing Outputs-JSON...\n"); parse_outputs_json(reply); @@ -53,6 +75,7 @@ void got_output_reply(char *reply) { reconfig_windows(); } +/* Data-structure to easily call the reply-handlers later */ handler_t reply_handlers[] = { &got_command_reply, &got_workspace_reply, @@ -60,25 +83,40 @@ handler_t reply_handlers[] = { &got_output_reply, }; +/* + * Called, when a workspace-event arrives (i.e. the user changed the workspace) + * + */ void got_workspace_event(char *event) { printf("Got Workspace Event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } +/* + * Called, when an output-event arrives (i.e. the screen-configuration changed) + * + */ void got_output_event(char *event) { printf("Got Output Event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } +/* Data-structure to easily call the reply-handlers later */ handler_t event_handlers[] = { &got_workspace_event, &got_output_event }; +/* + * Called, when we get a message from i3 + * + */ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { printf("Got data!\n"); int fd = watcher->fd; + + /* First we only read the header, because we know it's length */ uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; char *header = malloc(header_len); if (header == NULL) { @@ -108,6 +146,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { exit(EXIT_FAILURE); } + /* Know we read the rest of the message */ char *walk = header + strlen(I3_IPC_MAGIC); uint32_t size = *((uint32_t*) walk); walk += sizeof(uint32_t); @@ -133,6 +172,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { } buffer[size] = '\0'; + /* And call the callback (indexed by the type) */ if (type & (1 << 31)) { type ^= 1 << 31; event_handlers[type](buffer); @@ -144,6 +184,11 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { FREE(buffer); } +/* + * Sends a Message to i3. + * type must be a valid I3_IPC_MESSAGE_TYPE (see i3/ipc.h for further information) + * + */ int i3_send_msg(uint32_t type, const char *payload) { uint32_t len = 0; if (payload != NULL) { @@ -186,6 +231,11 @@ int i3_send_msg(uint32_t type, const char *payload) { return 1; } +/* + * Initiate a connection to i3. + * socket-path must be a valid path to the ipc_socket of i3 + * + */ int init_connection(const char *socket_path) { int sockfd = get_ipc_fd(socket_path); @@ -196,6 +246,10 @@ int init_connection(const char *socket_path) { return 1; } +/* + * Subscribe to all the i3-events, we need + * + */ void subscribe_events() { i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]"); } diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 5fcbd64d..ada297a3 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -6,6 +6,7 @@ #include "common.h" +/* A datatype to pass through the callbacks to save the state */ struct outputs_json_params { struct outputs_head *outputs; i3_output *outputs_walk; @@ -14,10 +15,15 @@ struct outputs_json_params { bool init; }; +/* + * Parse a null-value (current_workspace) + * + */ static int outputs_null_cb(void *params_) { struct outputs_json_params *params = (struct outputs_json_params*) params_; if (strcmp(params->cur_key, "current_workspace")) { + /* FIXME: Is this the correct behavior? */ return 0; } @@ -26,6 +32,10 @@ static int outputs_null_cb(void *params_) { return 1; } +/* + * Parse a booleant-value (active) + * + */ static int outputs_boolean_cb(void *params_, bool val) { struct outputs_json_params *params = (struct outputs_json_params*) params_; @@ -40,6 +50,10 @@ static int outputs_boolean_cb(void *params_, bool val) { return 1; } +/* + * Parse an integer (current_workspace or the rect) + * + */ static int outputs_integer_cb(void *params_, long val) { struct outputs_json_params *params = (struct outputs_json_params*) params_; @@ -76,6 +90,10 @@ static int outputs_integer_cb(void *params_, long val) { return 0; } +/* + * Parse a string (name) + * + */ static int outputs_string_cb(void *params_, const unsigned char *val, unsigned int len) { struct outputs_json_params *params = (struct outputs_json_params*) params_; @@ -94,6 +112,10 @@ static int outputs_string_cb(void *params_, const unsigned char *val, unsigned i return 1; } +/* + * We hit the start of a json-map (rect or a new output) + * + */ static int outputs_start_map_cb(void *params_) { struct outputs_json_params *params = (struct outputs_json_params*) params_; i3_output *new_output = NULL; @@ -116,8 +138,13 @@ static int outputs_start_map_cb(void *params_) { return 1; } +/* + * We hit the end of a map (rect or a new output) + * + */ static int outputs_end_map_cb(void *params_) { struct outputs_json_params *params = (struct outputs_json_params*) params_; + /* FIXME: What is at the end of a rect? */ i3_output *target = get_output_by_name(params->outputs_walk->name); @@ -131,6 +158,12 @@ static int outputs_end_map_cb(void *params_) { return 1; } +/* + * Parse a key. + * + * Essentially we just save it in the parsing-state + * + */ static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) { struct outputs_json_params *params = (struct outputs_json_params*) params_; FREE(params->cur_key); @@ -142,6 +175,7 @@ static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsign return 1; } +/* A datastructure to pass all these callbacks to yajl */ yajl_callbacks outputs_callbacks = { &outputs_null_cb, &outputs_boolean_cb, @@ -156,11 +190,19 @@ yajl_callbacks outputs_callbacks = { NULL }; +/* + * Initiate the output-list + * + */ void init_outputs() { outputs = malloc(sizeof(struct outputs_head)); SLIST_INIT(outputs); } +/* + * Start parsing the received json-string + * + */ void parse_outputs_json(char *json) { struct outputs_json_params params; @@ -191,6 +233,10 @@ void parse_outputs_json(char *json) { yajl_free(handle); } +/* + * Returns the output with the given name + * + */ i3_output *get_output_by_name(char *name) { i3_output *walk; if (name == NULL) { diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index e3efb445..be8a2a41 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -5,6 +5,7 @@ #include "common.h" +/* A datatype to pass through the callbacks to save the state */ struct workspaces_json_params { struct ws_head *workspaces; i3_ws *workspaces_walk; @@ -12,6 +13,10 @@ struct workspaces_json_params { char *json; }; +/* + * Parse a booleant-value (visible, focused, urgent) + * + */ static int workspaces_boolean_cb(void *params_, bool val) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; @@ -38,6 +43,10 @@ static int workspaces_boolean_cb(void *params_, bool val) { return 0; } +/* + * Parse an integer (num or the rect) + * + */ static int workspaces_integer_cb(void *params_, long val) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; @@ -75,6 +84,10 @@ static int workspaces_integer_cb(void *params_, long val) { return 0; } +/* + * Parse a string (name, output) + * + */ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigned int len) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; @@ -82,10 +95,12 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne char *output_name; if (!strcmp(params->cur_key, "name")) { + /* Save the name */ params->workspaces_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); strncpy(params->workspaces_walk->name, (const char*) val, len); params->workspaces_walk->name[len] = '\0'; + /* Convert the name to ucs2, save it's length in glyphs and calculate it'srendered width */ int ucs2_len; xcb_char2b_t *ucs2_name = (xcb_char2b_t*) convert_utf8_to_ucs2(params->workspaces_walk->name, &ucs2_len); params->workspaces_walk->ucs2_name = ucs2_name; @@ -103,6 +118,7 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne } if (!strcmp(params->cur_key, "output")) { + /* We add the ws to the TAILQ of the output, it belongs to */ output_name = malloc(sizeof(const unsigned char) * (len + 1)); strncpy(output_name, (const char*) val, len); output_name[len] = '\0'; @@ -119,6 +135,10 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne return 0; } +/* + * We hit the start of a json-map (rect or a new output) + * + */ static int workspaces_start_map_cb(void *params_) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; @@ -141,6 +161,12 @@ static int workspaces_start_map_cb(void *params_) { return 1; } +/* + * Parse a key. + * + * Essentially we just save it in the parsing-state + * + */ static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) { struct workspaces_json_params *params = (struct workspaces_json_params*) params_; FREE(params->cur_key); @@ -156,6 +182,7 @@ static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, uns return 1; } +/* A datastructure to pass all these callbacks to yajl */ yajl_callbacks workspaces_callbacks = { NULL, &workspaces_boolean_cb, @@ -170,6 +197,10 @@ yajl_callbacks workspaces_callbacks = { NULL }; +/* + * Start parsing the received json-string + * + */ void parse_workspaces_json(char *json) { /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret * JSON in chunks */ @@ -206,6 +237,10 @@ void parse_workspaces_json(char *json) { FREE(params.cur_key); } +/* + * free() all workspace data-structures + * + */ void free_workspaces() { i3_output *outputs_walk; SLIST_FOREACH(outputs_walk, outputs, slist) { diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 75011dac..21d7df39 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -9,6 +9,7 @@ #include "common.h" +/* We save the Atoms in an easy to access array, indexed by an enum */ #define NUM_ATOMS 3 enum { @@ -19,17 +20,22 @@ enum { xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS]; xcb_atom_t atoms[NUM_ATOMS]; +/* Variables, that are the same for all functions at all times */ xcb_connection_t *xcb_connection; xcb_screen_t *xcb_screens; xcb_window_t xcb_root; xcb_font_t xcb_font; +/* Event-Watchers, to interact with the user */ ev_prepare *xcb_prep; ev_check *xcb_chk; ev_io *xcb_io; -xcb_event_handlers_t xcb_event_handlers; - +/* + * Converts a colorstring to a colorpixel as expected from xcb_change_gc. + * s is assumed to be in the format "rrggbb" + * + */ uint32_t get_colorpixel(const char *s) { char strings[3][3] = { { s[0], s[1], '\0'} , { s[2], s[3], '\0'} , @@ -40,8 +46,16 @@ uint32_t get_colorpixel(const char *s) { return (r << 16 | g << 8 | b); } +/* + * Handle a button-press-event (i.c. a mouse click on one of our bars). + * We determine, wether the click occured on a ws-button or if the scroll- + * wheel was used and change the workspace appropriately + * + */ void handle_button(xcb_button_press_event_t *event) { i3_ws *cur_ws; + + /* Determine, which bar was clicked */ i3_output *walk; xcb_window_t bar = event->event; SLIST_FOREACH(walk, outputs, slist) { @@ -55,6 +69,7 @@ void handle_button(xcb_button_press_event_t *event) { return; } + /* TODO: Move this to exern get_ws_for_output() */ TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { if (cur_ws->visible) { break; @@ -72,6 +87,8 @@ void handle_button(xcb_button_press_event_t *event) { switch (event->detail) { case 1: + /* Left Mousbutton. We determine, which button was clicked + * and set cur_ws accordingly */ TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { printf("x = %d\n", x); if (x < cur_ws->name_width + 10) { @@ -84,17 +101,19 @@ void handle_button(xcb_button_press_event_t *event) { } break; case 4: - if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head)) { - cur_ws = TAILQ_FIRST(walk->workspaces); + /* Mouse wheel down. We select the next ws */ + if (cur_ws == TAILQ_FIRST(walk->workspaces, ws_head)) { + cur_ws = TAILQ_LAST(walk->workspaces); } else { - cur_ws = TAILQ_NEXT(cur_ws, tailq); + cur_ws = TAILQ_PREV(cur_ws, tailq); } break; case 5: - if (cur_ws == TAILQ_FIRST(walk->workspaces)) { - cur_ws = TAILQ_LAST(walk->workspaces, ws_head); + /* Mouse wheel up. We select the previos ws */ + if (cur_ws == TAILQ_LAST(walk->workspaces)) { + cur_ws = TAILQ_FIRST(walk->workspaces, ws_head); } else { - cur_ws = TAILQ_PREV(cur_ws, ws_head, tailq); + cur_ws = TAILQ_NEXT(cur_ws, ws_head, tailq); } break; } @@ -104,21 +123,42 @@ void handle_button(xcb_button_press_event_t *event) { i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, buffer); } +/* + * An X-Event occured, we determine, what kind and call the appropriate handler + * + * FIXME: Merge this in ev_chk_cb(), the additional call is superflous + * + */ void handle_xcb_event(xcb_generic_event_t *event) { switch (event->response_type & ~0x80) { case XCB_EXPOSE: + /* Expose-events happen, when the window needs to be redrawn */ draw_bars(); break; case XCB_BUTTON_PRESS: + /* Button-press-events are mouse-buttons clicked on one of our bars */ handle_button((xcb_button_press_event_t*) event); break; } } +/* + * This function is called immediately bevor the main loop locks. We flush xcb + * then (and only then) + * + */ void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revenst) { xcb_flush(xcb_connection); } +/* + * This function is called immediately after the main loop locks, so when one + * of the watchers registered an event. + * We check wether an X-Event arrived and handle it. + * + * FIXME: use a while-loop, to account for the xcb buffer + * + */ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { xcb_generic_event_t *event; if ((event = xcb_poll_for_event(xcb_connection)) != NULL) { @@ -127,11 +167,20 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { FREE(event); } +/* + * Dummy Callback. We only need this, so that the Prepare- and Check-Watchers + * are triggered + * + */ void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { - /* Dummy Callback. We only need this, so that xcb-events trigger - * Prepare- and Check-Watchers */ } +/* + * Calculate the rendered width of a string with the configured font. + * The string has to be encoded in ucs2 and glyph_len has to be the length + * of the string (in width) + * + */ int get_string_width(xcb_char2b_t *string, int glyph_len) { xcb_query_text_extents_cookie_t cookie; xcb_query_text_extents_reply_t *reply; @@ -139,7 +188,8 @@ int get_string_width(xcb_char2b_t *string, int glyph_len) { int width; cookie = xcb_query_text_extents(xcb_connection, xcb_font, glyph_len, string); - if ((reply = xcb_query_text_extents_reply(xcb_connection, cookie, &error)) == NULL) { + reply = xcb_query_text_extents_reply(xcb_connection, cookie, &error); + if (reply == NULL) { printf("ERROR: Could not get text extents!"); return 7; } @@ -149,6 +199,10 @@ int get_string_width(xcb_char2b_t *string, int glyph_len) { return width; } +/* + * Initialize xcb and use the specified fontname for text-rendering + * + */ void init_xcb(char *fontname) { /* FIXME: xcb_connect leaks Memory */ xcb_connection = xcb_connect(NULL, NULL); @@ -160,30 +214,35 @@ void init_xcb(char *fontname) { /* We have to request the atoms we need */ #define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name); - #include "xcb_atoms.def" + #include "xcb_atoms.def" xcb_screens = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; xcb_root = xcb_screens->root; + /* We load and allocate the font */ xcb_font = xcb_generate_id(xcb_connection); xcb_open_font(xcb_connection, xcb_font, strlen(fontname), fontname); + /* We also need the fontheight to configure our bars accordingly */ xcb_list_fonts_with_info_cookie_t cookie; cookie = xcb_list_fonts_with_info(xcb_connection, 1, strlen(fontname), fontname); + /* FIXME: push this to the end of init_xcb() */ xcb_list_fonts_with_info_reply_t *reply; reply = xcb_list_fonts_with_info_reply(xcb_connection, cookie, NULL); font_height = reply->font_ascent + reply->font_descent; FREE(reply); + printf("Calculated Font-height: %d\n", font_height); + /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); xcb_prep = malloc(sizeof(ev_prepare)); xcb_chk = malloc(sizeof(ev_check)); @@ -196,11 +255,17 @@ void init_xcb(char *fontname) { ev_prepare_start(main_loop, xcb_prep); ev_check_start(main_loop, xcb_chk); - /* FIXME: Maybe we can push that further backwards */ + /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); } +/* + * Cleanup the xcb-stuff. + * Called once, before the program terminates. + * + */ void clean_xcb() { + /* FIXME: destroy() the bars first */ xcb_disconnect(xcb_connection); ev_check_stop(main_loop, xcb_chk); @@ -212,6 +277,10 @@ void clean_xcb() { FREE(xcb_io); } +/* + * Get the earlier requested atoms and save them in the prepared data-structure + * + */ void get_atoms() { xcb_intern_atom_reply_t *reply; #define ATOM_DO(name) reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \ @@ -222,6 +291,10 @@ void get_atoms() { printf("Got Atoms\n"); } +/* + * Destroy the bar of the specified output + * + */ void destroy_window(i3_output *output) { if (output == NULL) { return; @@ -233,6 +306,10 @@ void destroy_window(i3_output *output) { output->bar = XCB_NONE; } +/* + * Reconfigure all bars and create new for newly activated outputs + * + */ void reconfig_windows() { uint32_t mask; uint32_t values[4]; @@ -240,6 +317,8 @@ void reconfig_windows() { i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { + /* If an output is not active, we destroy it's bar */ + /* FIXME: Maybe we rather want to unmap? */ printf("Destroying window for output %s\n", walk->name); destroy_window(walk); continue; @@ -249,7 +328,9 @@ void reconfig_windows() { walk->bar = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; + /* Black background */ values[0] = xcb_screens->black_pixel; + /* The events we want to receive */ values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; xcb_create_window(xcb_connection, @@ -264,6 +345,7 @@ void reconfig_windows() { mask, values); + /* We want dock-windows (for now) */ xcb_change_property(xcb_connection, XCB_PROP_MODE_REPLACE, walk->bar, @@ -273,6 +355,7 @@ void reconfig_windows() { 1, (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); + /* We also want a graphics-context (the "canvas" on which we draw) */ walk->bargc = xcb_generate_id(xcb_connection); mask = XCB_GC_FONT; values[0] = xcb_font; @@ -282,8 +365,10 @@ void reconfig_windows() { mask, values); + /* We finally map the bar (display it on screen) */ xcb_map_window(xcb_connection, walk->bar); } else { + /* We already have a bar, so we just reconfigure it */ mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | @@ -301,6 +386,10 @@ void reconfig_windows() { } } +/* + * Render the bars, with buttons and statusline + * + */ void draw_bars() { printf("Drawing Bars...\n"); int i = 0;