#include #include "any_log.h" #include "util.h" #include "layout.h" #include "event.h" #include "block.h" const char *even_type_to_string(event_type_t type) { const char *types[] = { "left_click", "middle_click", "right_click", "trigger", }; assert(type >= EVENT_LEFT_CLICK && type <= EVENT_TRIGGER); return types[type]; } static bool event_click(layout_t *layout, event_t event) { int width = layout->width - 2 * layout->x_padding; int height = layout->height - 2 * layout->y_padding; if (!check_capsule(event.x, event.y, layout->x, layout->y, width, height)) return false; for (int i = 0; i < layout->n_children; i++) { if (event_click(&layout->children[i], event)) return true; } block_event_t event_fn = layout->block->type == BLOCK_SPEC ? ((block_spec_t *)layout->block)->event_fn : NULL; log_value_debug("Block was clicked", "s:type", even_type_to_string(event.type), "i:x", event.x, "i:y", event.y, "s:block_label", layout->block->label, "i:block_x", layout->x, "i:block_y", layout->y, "i:block_width", layout->width, "i:block_height", layout->height, "b:callback", event_fn != NULL); if (event_fn != NULL) { event_fn(layout->block, event); log_trace("Completed event callback"); } return true; } void event_dispatch(display_t *display, layout_t *layout) { xcb_generic_event_t *xevent; while ((xevent = xcb_poll_for_event(display->connection)) != NULL) { int type = xevent->response_type & ~0x80; switch (type) { case 0: { xcb_generic_error_t *error = (xcb_generic_error_t *)xevent; const char *extension; const char *name = xcb_errors_get_name_for_error(display->errors, error->error_code, &extension); const char *major = xcb_errors_get_name_for_major_code(display->errors, error->major_code); const char *minor = xcb_errors_get_name_for_minor_code(display->errors, error->major_code, error->minor_code); log_value_error("Xcb error", "s:name", name, "s:extension", extension ? extension : "none", "s:major", major, "s:minor", minor ? minor : "none", "u:resource", (unsigned int)error->resource_id, "u:sequence", (unsigned int)error->sequence); // TODO: Handle errors instead of aborting abort(); break; } case XCB_EXPOSE: { xcb_expose_event_t *expose = (xcb_expose_event_t *)xevent; log_trace("Processing 'Expose' event"); // Redraw (void)expose; break; } case XCB_CREATE_NOTIFY: { xcb_create_notify_event_t *create = (xcb_create_notify_event_t *)xevent; log_trace("Processing 'CreateNotify' event"); // TODO: Circulate top the window if override_redirect == 0 (void)create; break; } case XCB_BUTTON_RELEASE: { xcb_button_release_event_t *button = (xcb_button_release_event_t *)xevent; log_trace("Processing 'ButtonRelease' event"); event_t event = { .x = button->event_x, .y = button->event_y, }; switch (button->detail) { case XCB_BUTTON_INDEX_1: event.type = EVENT_LEFT_CLICK; event_click(layout, event); break; case XCB_BUTTON_INDEX_2: event.type = EVENT_MIDDLE_CLICK; event_click(layout, event); break; case XCB_BUTTON_INDEX_3: event.type = EVENT_RIGHT_CLICK; event_click(layout, event); break; default: log_value_trace("Ignoring button release", "u:value", button->detail); break; } break; } case XCB_PROPERTY_NOTIFY: { xcb_property_notify_event_t *property = (xcb_property_notify_event_t *)xevent; log_trace("Processing 'PropertyNotify' event"); if (property->atom == XCB_ATOM_RESOURCE_MANAGER) { display_update_xrm(display); display_update_scale(display); // Redraw } break; } default: { const char *extension; const char *name = xcb_errors_get_name_for_xcb_event(display->errors, xevent, &extension); log_value_trace("Ignoring Xcb event", "s:name", name, "u:type", xevent->response_type & 0x7f, "s:extension", extension ? extension : "none"); break; } } free(xevent); } }