aboutsummaryrefslogtreecommitdiff
path: root/src/event.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/event.c')
-rw-r--r--src/event.c281
1 files changed, 159 insertions, 122 deletions
diff --git a/src/event.c b/src/event.c
index c07f2e8..3c1ae81 100644
--- a/src/event.c
+++ b/src/event.c
@@ -9,22 +9,26 @@
const char *event_type_to_string(event_type_t type)
{
const char *types[] = {
- "hover",
+ "trigger",
"left_click",
"middle_click",
"right_click",
"scroll_up",
"scroll_down",
- "trigger",
+ "hover_start",
+ "hover_move",
+ "hover_stop",
};
- assert(type >= EVENT_HOVER && type <= EVENT_TRIGGER);
+ assert(type >= EVENT_TRIGGER && type <= EVENT_HOVER_STOP);
return types[type];
}
bool event_is_hover(event_t event)
{
- return event.type == EVENT_HOVER;
+ return event.type == EVENT_HOVER_START
+ || event.type == EVENT_HOVER_MOVE
+ || event.type == EVENT_HOVER_STOP;
}
bool event_is_click(event_t event)
@@ -40,27 +44,13 @@ bool event_is_scroll(event_t event)
|| event.type == EVENT_SCROLL_DOWN;
}
-static bool event_dispatch_mouse(layout_t *layout, event_t event)
+static void event_dispatch_callback(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_dispatch_mouse(&layout->children[i], event))
- return true;
- }
-
- // XXX
- if (event_is_hover(event)) return false;
-
block_event_t event_fn = layout->block->type == BLOCK_SPEC
? ((block_spec_t *)layout->block)->event_fn
: NULL;
- log_value_debug("Block received a mouse interaction",
+ log_value_debug("Block received a mouse event",
"s:event", event_type_to_string(event.type),
"i:event_x", event.x,
"i:event_y", event.y,
@@ -75,143 +65,190 @@ static bool event_dispatch_mouse(layout_t *layout, event_t event)
event_fn(layout, event);
log_trace("Completed event callback");
}
+}
- return true;
+static bool event_dispatch_block(layout_t *layout, block_t *block, event_t event)
+{
+ if (layout->block == block) {
+ event_dispatch_callback(layout, event);
+ return true;
+ }
+
+ for (int i = 0; i < layout->n_children; i++) {
+ if (event_dispatch_block(&layout->children[i], block, event))
+ return true;
+ }
+
+ return false;
}
-static void event_dispatch_once(window_t *window, layout_t *layout, xcb_generic_event_t *xevent)
+static bool event_dispatch_mouse(event_state_t *state, layout_t *layout, event_t event)
{
- int type = xevent->response_type & ~0x80;
- switch (type) {
- case 0: {
- xcb_generic_error_t *error = (xcb_generic_error_t *)xevent;
-
- const char *extension = NULL;
- const char *name = xcb_errors_get_name_for_error(window->display->errors, error->error_code, &extension);
- const char *major = xcb_errors_get_name_for_major_code(window->display->errors, error->major_code);
- const char *minor = xcb_errors_get_name_for_minor_code(window->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;
- }
+ 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_dispatch_mouse(state, &layout->children[i], event))
+ return true;
+ }
- case XCB_EXPOSE: {
- xcb_expose_event_t *expose = (xcb_expose_event_t *)xevent;
- log_trace("Processing 'Expose' event");
+ if (event_is_hover(event)) {
+ if (layout->block != state->hovered) {
+ event.type = EVENT_HOVER_STOP;
+ event_dispatch_block(state->layout, state->hovered, event);
- // Redraw
- (void)expose;
- break;
+ event.type = EVENT_HOVER_START;
+ state->hovered = layout->block;
}
+ }
+
+ event_dispatch_callback(layout, event);
+ return true;
+}
- case XCB_CREATE_NOTIFY: {
- xcb_create_notify_event_t *create = (xcb_create_notify_event_t *)xevent;
- log_trace("Processing 'CreateNotify' event");
+void event_dispatch(event_state_t *state, window_t *window)
+{
+ xcb_generic_event_t *xevent;
+ xcb_motion_notify_event_t *motion = NULL;
- (void)create;
+ while ((xevent = xcb_poll_for_event(window->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 = NULL;
+ const char *name = xcb_errors_get_name_for_error(window->display->errors, error->error_code, &extension);
+ const char *major = xcb_errors_get_name_for_major_code(window->display->errors, error->major_code);
+ const char *minor = xcb_errors_get_name_for_minor_code(window->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;
+ }
- if (window->cw_params.override_redirect) break;
- xcb_circulate_window(window->display->connection, XCB_CIRCULATE_RAISE_LOWEST, window->window);
- break;
- }
+ case XCB_EXPOSE: {
+ xcb_expose_event_t *expose = (xcb_expose_event_t *)xevent;
+ log_trace("Processing 'Expose' event");
- case XCB_LEAVE_NOTIFY: {
- xcb_leave_notify_event_t *leave = (xcb_leave_notify_event_t *)xevent;
- log_trace("Processing 'LeaveNotify' event");
+ // Redraw
+ (void)expose;
+ break;
+ }
- if (leave->event != window->window) break;
- // Leaving
- break;
- }
+ case XCB_CREATE_NOTIFY: {
+ xcb_create_notify_event_t *create = (xcb_create_notify_event_t *)xevent;
+ log_trace("Processing 'CreateNotify' event");
- case XCB_BUTTON_RELEASE: {
- xcb_button_release_event_t *button = (xcb_button_release_event_t *)xevent;
- log_trace("Processing 'ButtonRelease' event");
+ (void)create;
- if (button->detail < XCB_BUTTON_INDEX_1 || button->detail > XCB_BUTTON_INDEX_5) {
- log_value_trace("Ignoring button release",
- "u:value", button->detail);
+ if (window->cw_params.override_redirect) break;
+ xcb_circulate_window(window->display->connection, XCB_CIRCULATE_RAISE_LOWEST, window->window);
break;
}
- event_t event = {
- .x = button->event_x,
- .y = button->event_y,
- .type = button->detail,
- };
+ case XCB_LEAVE_NOTIFY: {
+ xcb_leave_notify_event_t *leave = (xcb_leave_notify_event_t *)xevent;
+ log_trace("Processing 'LeaveNotify' event");
- event_dispatch_mouse(layout, event);
- break;
- }
+ if (leave->event != window->window) break;
+ if (state->hovered == NULL) break;
- case XCB_PROPERTY_NOTIFY: {
- xcb_property_notify_event_t *property = (xcb_property_notify_event_t *)xevent;
- log_trace("Processing 'PropertyNotify' event");
+ event_t event = {
+ .x = leave->event_x,
+ .y = leave->event_y,
+ .type = EVENT_HOVER_STOP,
+ };
- if (property->atom == XCB_ATOM_RESOURCE_MANAGER) {
- display_update_xrm(window->display);
- display_update_scale(window->display);
- // Redraw
+ event_dispatch_block(state->layout, state->hovered, event);
+ state->hovered = NULL;
+
+ if (motion != NULL && motion->time <= leave->time) {
+ log_trace("Suppressed older 'MotionNotify' event");
+
+ free(motion);
+ motion = NULL;
+ }
+ break;
}
- break;
- }
- case XCB_MOTION_NOTIFY: {
- xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)xevent;
- log_trace("Processing 'MotionNotify' event");
+ 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 = motion->event_x,
- .y = motion->event_y,
- .type = EVENT_HOVER,
- };
+ if (button->detail < XCB_BUTTON_INDEX_1 || button->detail > XCB_BUTTON_INDEX_5) {
+ log_value_trace("Ignoring button release",
+ "u:value", button->detail);
+ break;
+ }
- event_dispatch_mouse(layout, event);
- break;
- }
+ event_t event = {
+ .x = button->event_x,
+ .y = button->event_y,
+ .type = button->detail,
+ };
+
+ event_dispatch_mouse(state, state->layout, event);
+ break;
+ }
- default: {
- const char *extension = NULL;
- const char *name = xcb_errors_get_name_for_xcb_event(window->display->errors, xevent, &extension);
+ case XCB_PROPERTY_NOTIFY: {
+ xcb_property_notify_event_t *property = (xcb_property_notify_event_t *)xevent;
+ log_trace("Processing 'PropertyNotify' event");
- log_value_trace("Ignoring Xcb event",
- "s:name", name,
- "u:type", type,
- "s:extension", extension ? extension : "none");
- break;
- }
- }
-}
+ if (property->atom == XCB_ATOM_RESOURCE_MANAGER) {
+ display_update_xrm(window->display);
+ display_update_scale(window->display);
+ // Redraw
+ }
+ break;
+ }
-void event_dispatch(window_t *window, layout_t *layout)
-{
- xcb_generic_event_t *xevent, *motion = NULL;
- while ((xevent = xcb_poll_for_event(window->display->connection)) != NULL) {
+ case XCB_MOTION_NOTIFY: {
+ log_trace("Deferred processing 'MotionNotify' event");
- int type = xevent->response_type & ~0x80;
- if (type == XCB_MOTION_NOTIFY) {
- free(motion);
- motion = xevent;
- continue;
- }
+ free(motion);
+ motion = (xcb_motion_notify_event_t *)xevent;
+ continue;
+ }
- event_dispatch_once(window, layout, xevent);
+ default: {
+ const char *extension = NULL;
+ const char *name = xcb_errors_get_name_for_xcb_event(window->display->errors, xevent, &extension);
+
+ log_value_trace("Ignoring Xcb event",
+ "s:name", name,
+ "u:type", type,
+ "s:extension", extension ? extension : "none");
+ break;
+ }
+ }
free(xevent);
}
// We only consider the last motion notify received
//
if (motion != NULL) {
- event_dispatch_once(window, layout, motion);
+ log_trace("Processing 'MotionNotify' event");
+
+ event_t event = {
+ .x = motion->event_x,
+ .y = motion->event_y,
+ .type = EVENT_HOVER_MOVE,
+ };
+
+ event_dispatch_mouse(state, state->layout, event);
free(motion);
}
}