summaryrefslogtreecommitdiff
path: root/tests/x11
diff options
context:
space:
mode:
Diffstat (limited to 'tests/x11')
-rw-r--r--tests/x11/test_tablet.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/tests/x11/test_tablet.c b/tests/x11/test_tablet.c
index 39717df..c35a266 100644
--- a/tests/x11/test_tablet.c
+++ b/tests/x11/test_tablet.c
@@ -9,6 +9,257 @@ static struct yasl_mouse_event next(struct x11_surface *surface)
return event.mouse;
}
+struct drag_test_recorder {
+ int over_count;
+ int leave_count;
+ int drop_count;
+ struct yasl_vector2i last_pos;
+};
+
+static void on_test_drag(struct yasl_surface *s, enum yasl_drag_event ev,
+ struct yasl_vector2i pos, void *ud)
+{
+ (void)s;
+ struct drag_test_recorder *rec = ud;
+ rec->last_pos = pos;
+ if (ev == YASL_DRAG_OVER) rec->over_count++;
+ else if (ev == YASL_DRAG_LEAVE) rec->leave_count++;
+ else if (ev == YASL_DRAG_DROP) rec->drop_count++;
+}
+
+struct drop_test_recorder {
+ int over_count;
+ int leave_count;
+ struct yasl_vector2i last_pos;
+};
+
+static void on_test_drop(struct yasl_surface *s, enum yasl_drop_event ev,
+ struct yasl_vector2i pos, void *ud)
+{
+ (void)s;
+ struct drop_test_recorder *rec = ud;
+ rec->last_pos = pos;
+ if (ev == YASL_DROP_OVER) rec->over_count++;
+ else if (ev == YASL_DROP_LEAVE) rec->leave_count++;
+}
+
+static void on_test_drag_end(void *ud, enum yasl_drag_end how)
+{
+ enum yasl_drag_end *res = ud;
+ *res = how;
+}
+
+static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
+{
+ /* 1. Caps */
+ assert(caps(&d->base) & YASL_CAP_POPUPS);
+ assert(caps(&d->base) & YASL_CAP_DRAG);
+ assert(caps(&d->base) & YASL_CAP_DRAG_CARRY);
+
+ /* 2. Popups: spec validation, calculation, creation, reposition, destruction */
+ struct yasl_popup_spec invalid_specs[] = {
+ {.size = {0, 100}},
+ {.size = {100, 0}},
+ {.size = {35000, 100}},
+ {.size = {100, 100}, .content_offset = {-1, 0}},
+ {.size = {100, 100}, .content_offset = {100, 0}, .content_size = {10, 0}},
+ {.size = {100, 100}, .anchor = {INT_MIN, 0, 1, 1}},
+ };
+ for (size_t i = 0; i < sizeof(invalid_specs)/sizeof(invalid_specs[0]); i++) {
+ assert(!popup_spec_valid(s, &invalid_specs[i]));
+ assert(!surface_create_popup(&s->base, &invalid_specs[i]));
+ }
+
+ struct yasl_popup_spec valid_spec = {
+ .size = {100, 120},
+ .anchor = {30, 40, 50, 60},
+ .beside = false,
+ .content_offset = {5, 10},
+ };
+ assert(popup_spec_valid(s, &valid_spec));
+ int x = 0, y = 0;
+ popup_calculate_position(d, s, &valid_spec, &x, &y);
+ assert(x == 30 - 5);
+ assert(y == 40 + 60 - 10);
+
+ valid_spec.beside = true;
+ popup_calculate_position(d, s, &valid_spec, &x, &y);
+ assert(x == 30 + 50 - 5);
+ assert(y == 40 - 10);
+
+ struct yasl_surface *popup_base = surface_create_popup(&s->base, &valid_spec);
+ assert(popup_base != NULL);
+ struct x11_surface *popup = (struct x11_surface *)popup_base;
+ assert(popup->is_popup);
+ assert(popup->parent == s);
+ assert(popup->size.x == 100 && popup->size.y == 120);
+
+ struct yasl_popup_spec repo_spec = {
+ .size = {150, 180},
+ .anchor = {10, 20, 30, 40},
+ .beside = false,
+ .content_offset = {0, 0},
+ };
+ assert(surface_popup_reposition(popup_base, &repo_spec));
+ assert(popup->size.x == 150 && popup->size.y == 180);
+
+ surface_destroy(popup_base);
+ assert(d->surfaces == s);
+
+ /* 3. Drag-and-drop target events */
+ struct x11_surface s2 = {.base.display = &d->base, .window = 43};
+ s->next = &s2;
+ s2.next = NULL;
+
+ struct drag_test_recorder rec1 = {0};
+ struct drag_test_recorder rec2 = {0};
+ struct yasl_surface_cbs cbs1 = {.drag = on_test_drag};
+ struct yasl_surface_cbs cbs2 = {.drag = on_test_drag};
+ set_callbacks(&s->base, &cbs1, &rec1);
+ set_callbacks(&s2.base, &cbs2, &rec2);
+
+ enum yasl_drag_end end_reason = (enum yasl_drag_end)-1;
+ struct yasl_drag_listener l = {.end = on_test_drag_end};
+ assert(drag_start(&d->base, &s->base, NULL, &l, &end_reason));
+ assert(d->drag.active);
+
+ /* Motion on s (window 42) -> YASL_DRAG_OVER on s */
+ XIDeviceEvent mev = {.evtype = XI_Motion, .sourceid = 8, .event = 42, .event_x = 12.0, .event_y = 34.0};
+ XGenericEventCookie cookie = {.evtype = XI_Motion, .data = &mev};
+ xi_event(d, &cookie);
+ assert(rec1.over_count == 1);
+ assert(rec1.last_pos.x == 12 && rec1.last_pos.y == 34);
+
+ /* Motion on s2 (window 43) -> YASL_DRAG_LEAVE on s, YASL_DRAG_OVER on s2 */
+ mev.event = 43;
+ mev.event_x = 56.0;
+ mev.event_y = 78.0;
+ xi_event(d, &cookie);
+ assert(rec1.leave_count == 1);
+ assert(rec2.over_count == 1);
+ assert(rec2.last_pos.x == 56 && rec2.last_pos.y == 78);
+
+ /* ButtonRelease -> YASL_DRAG_DROP on s2 and drag end */
+ XIDeviceEvent rel = {.evtype = XI_ButtonRelease, .sourceid = 8, .event = 43, .detail = 1};
+ cookie = (XGenericEventCookie){.evtype = XI_ButtonRelease, .data = &rel};
+ xi_event(d, &cookie);
+ assert(rec2.drop_count == 1);
+ assert(end_reason == YASL_DRAG_DROPPED);
+ assert(!d->drag.active);
+
+ /* Drag cancel */
+ assert(drag_start(&d->base, &s->base, NULL, &l, &end_reason));
+ cookie = (XGenericEventCookie){.evtype = XI_Motion, .data = &mev};
+ mev.event = 42;
+ xi_event(d, &cookie);
+ assert(rec1.over_count == 2);
+ drag_cancel(&d->base);
+ assert(rec1.leave_count == 2);
+ assert(end_reason == YASL_DRAG_CANCELLED);
+ assert(!d->drag.active);
+
+ /* Hierarchy change cancels drag and pushes reset */
+ input_queue_clear(&s->input);
+ assert(drag_start(&d->base, &s->base, NULL, &l, &end_reason));
+ XIHierarchyEvent hiev = {.evtype = XI_HierarchyChanged, .flags = XISlaveRemoved};
+ cookie = (XGenericEventCookie){.evtype = XI_HierarchyChanged, .data = &hiev};
+ xi_event(d, &cookie);
+ assert(end_reason == YASL_DRAG_CANCELLED);
+ assert(!d->drag.active);
+ struct yasl_input_event reset_ev;
+ assert(yasl_surface_input_poll(&s->base, &reset_ev));
+ assert(reset_ev.kind == YASL_INPUT_RESET);
+
+ /* 4. Drag image parameter */
+ uint32_t pixels[16] = {0xFF00FF00};
+ struct yasl_drag_image img = {.pixels = pixels, .size = {4, 4}, .hotspot = {2, 2}};
+ assert(drag_start(&d->base, &s->base, &img, &l, &end_reason));
+ assert(d->drag.active);
+ assert(drag_carry(&s->base, (struct yasl_vector2i){10, 10}));
+ drag_cancel(&d->base);
+
+ /* 5. XDND drop-target events and URI parsing */
+ size_t out_len = 0;
+ char *parsed = parse_file_uris("file:///tmp/doc.txt\r\n", 21, &out_len);
+ assert(parsed && !strcmp(parsed, "file:///tmp/doc.txt\r\n") && out_len == 21);
+ free(parsed);
+
+ parsed = parse_file_uris("# comment\nfile:///a\nfile:///b\n", 30, &out_len);
+ assert(parsed && !strcmp(parsed, "file:///a\r\nfile:///b\r\n") && out_len == 22);
+ free(parsed);
+
+ parsed = parse_file_uris("http://example.com\r\n", 20, &out_len);
+ assert(parsed == NULL && out_len == 0);
+
+ /* Test XDND ClientMessages */
+ d->protocols = 1;
+ d->delete_window = 2;
+ d->xdnd_enter = 10;
+ d->xdnd_position = 11;
+ d->xdnd_leave = 12;
+ d->xdnd_drop = 13;
+ d->uri_list = 20;
+
+ struct drop_test_recorder drec = {0};
+ cbs1.drop = on_test_drop;
+ set_callbacks(&s->base, &cbs1, &drec);
+
+ XClientMessageEvent enter_msg = {
+ .type = ClientMessage,
+ .message_type = d->xdnd_enter,
+ .format = 32,
+ .data.l = {99, 5 << 24, d->uri_list, 0, 0},
+ };
+ handle_client_message(d, s, &enter_msg);
+ assert(d->xdnd.accepts);
+
+ XClientMessageEvent pos_msg = {
+ .type = ClientMessage,
+ .message_type = d->xdnd_position,
+ .format = 32,
+ .data.l = {99, 0, (100 << 16) | 200, 1000, 0},
+ };
+ handle_client_message(d, s, &pos_msg);
+ assert(drec.over_count == 1);
+ assert(drec.last_pos.x == 100 && drec.last_pos.y == 200);
+
+ XClientMessageEvent leave_msg = {
+ .type = ClientMessage,
+ .message_type = d->xdnd_leave,
+ .format = 32,
+ .data.l = {99, 0, 0, 0, 0},
+ };
+ handle_client_message(d, s, &leave_msg);
+ assert(drec.leave_count == 1);
+
+ handle_client_message(d, s, &enter_msg);
+ handle_client_message(d, s, &pos_msg);
+ assert(drec.over_count == 2);
+
+ XClientMessageEvent drop_msg = {
+ .type = ClientMessage,
+ .message_type = d->xdnd_drop,
+ .format = 32,
+ .data.l = {99, 0, 1005, 0, 0},
+ };
+ handle_client_message(d, s, &drop_msg);
+ assert(drec.leave_count == 2);
+ assert(d->pending_drop.active);
+
+ /* Push YASL_INPUT_DROP_FILES */
+ push(s, (struct yasl_input_event){.kind = YASL_INPUT_DROP_FILES}, "file:///sample.png\r\n", 20);
+ struct yasl_input_event drop_ev;
+ assert(yasl_surface_input_poll(&s->base, &drop_ev));
+ assert(drop_ev.kind == YASL_INPUT_DROP_FILES);
+ assert(drop_ev.drop_files.len == 20);
+ assert(!strcmp(drop_ev.drop_files.files, "file:///sample.png\r\n"));
+
+ /* Clean up s2 */
+ s->next = NULL;
+ input_queue_clear(&s->input);
+ input_queue_clear(&s2.input);
+}
+
int main(void)
{
struct x11_display display = {
@@ -99,5 +350,6 @@ int main(void)
assert(tilt_value(&pointer.tilt_x) == 90);
display.pointers = NULL;
input_queue_clear(&surface.input);
+ test_x11_gaps(&display, &surface);
return 0;
}