z-index system for wayland
All checks were successful
pyrite-dev/milsko/pipeline/head This commit looks good
All checks were successful
pyrite-dev/milsko/pipeline/head This commit looks good
fixes clicks penetrating to widgets behind one another and allows MwLLRaiseImpl to be implemented
This commit is contained in:
parent
af472c625c
commit
e1824cffa0
3 changed files with 122 additions and 106 deletions
|
|
@ -341,6 +341,9 @@ struct _MwLLWayland {
|
|||
|
||||
MwBool is_toplevel;
|
||||
|
||||
/* Stacking order among sibling sublevels. Higher values are drawn on top and get the pointer first. */
|
||||
MwI32 z_index;
|
||||
|
||||
MwBool is_clipping;
|
||||
MwRect clip;
|
||||
|
||||
|
|
@ -505,6 +508,11 @@ void MwLLWaylandClipboardRead(wl_clipboard_device_context_t* ctx, int clipboard_
|
|||
/* Flush Wayland events */
|
||||
void MwLLWaylandFlush(MwLL handle);
|
||||
|
||||
/* Get the sublevel children of a widget ordered from lowest to highest z-index (ties keep creation order). Free the result with arrfree. */
|
||||
MwLL* MwLLWaylandSublevelsByZIndex(MwLL handle);
|
||||
/* Set a sublevel's z-index and schedule a redraw so the new stacking order is shown. */
|
||||
void MwLLWaylandSetZIndex(MwLL handle, MwI32 z_index);
|
||||
|
||||
/* recursively dispatch the key event to focused widgets. */
|
||||
void MwLLRecursiveKeyDispatch(MwLL self, int* k, MwBool down);
|
||||
|
||||
|
|
|
|||
|
|
@ -721,33 +721,6 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time
|
|||
}
|
||||
};
|
||||
|
||||
static void recursive_dispatch_mouse_down(MwLL handle, MwMouse* p) {
|
||||
MwWidget h = (MwWidget)handle->common.internal;
|
||||
MwLLDispatch(handle, down, p);
|
||||
if(h) {
|
||||
int i;
|
||||
for(i = 0; i < arrlen(h->children); i++) {
|
||||
MwLLDispatch(h->children[i]->lowlevel, down, p);
|
||||
if(arrlen(h->children[i]->children) > 0) {
|
||||
recursive_dispatch_mouse_down(h->children[i]->lowlevel, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
static void recursive_dispatch_mouse_up(MwLL handle, MwMouse* p) {
|
||||
MwWidget h = (MwWidget)handle->common.internal;
|
||||
MwLLDispatch(handle, up, p);
|
||||
if(h) {
|
||||
int i;
|
||||
for(i = 0; i < arrlen(h->children); i++) {
|
||||
MwLLDispatch(h->children[i]->lowlevel, up, p);
|
||||
if(arrlen(h->children[i]->children) > 0) {
|
||||
recursive_dispatch_mouse_up(h->children[i]->lowlevel, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static MwBool hit_detect(MwLL child, MwLL* _topmost_parent, MwPoint* _point, MwPoint* _relative_mouse_pos, MwPoint* _absolute_pos) {
|
||||
MwLL topmost_parent = child;
|
||||
MwPoint point;
|
||||
|
|
@ -761,9 +734,7 @@ static MwBool hit_detect(MwLL child, MwLL* _topmost_parent, MwPoint* _point, MwP
|
|||
if(topmost_parent) {
|
||||
/* if the topmost parent is a popup/subwindow then its x/y is irrelevant to us. */
|
||||
if(topmost_parent->wayland.type != MwLL_WAYLAND_POPUP && topmost_parent->wayland.type != MwLL_WAYLAND_TOPLEVEL) {
|
||||
if(topmost_parent->wayland.x > 0)
|
||||
absolute_pos.x += topmost_parent->wayland.x;
|
||||
if(topmost_parent->wayland.y > 0)
|
||||
absolute_pos.y += topmost_parent->wayland.y;
|
||||
}
|
||||
}
|
||||
|
|
@ -783,22 +754,42 @@ static MwBool hit_detect(MwLL child, MwLL* _topmost_parent, MwPoint* _point, MwP
|
|||
point.y >= absolute_pos.y && point.y <= absolute_pos.y + child->wayland.wh;
|
||||
}
|
||||
|
||||
static void mouse_dispatch(MwLL self, MwMouse p, MwU32 state) {
|
||||
switch(state) {
|
||||
case WL_POINTER_BUTTON_STATE_PRESSED:
|
||||
MwLLDispatch(self, down, &p);
|
||||
break;
|
||||
case WL_POINTER_BUTTON_STATE_RELEASED:
|
||||
MwLLDispatch(self, up, &p);
|
||||
/* deepest, topmost-z sublevel under the pointer, or self if none */
|
||||
static MwLL find_target(MwLL self, MwPoint* local) {
|
||||
MwLL* children = MwLLWaylandSublevelsByZIndex(self);
|
||||
MwLL target = self;
|
||||
int i;
|
||||
for(i = arrlen(children) - 1; i >= 0; i--) {
|
||||
MwLL tp;
|
||||
MwPoint pt, rel, abs;
|
||||
if(hit_detect(children[i], &tp, &pt, &rel, &abs)) {
|
||||
*local = rel;
|
||||
target = find_target(children[i], local);
|
||||
break;
|
||||
}
|
||||
}
|
||||
arrfree(children);
|
||||
return target;
|
||||
}
|
||||
|
||||
if(self->common.internal) {
|
||||
MwWidget w = self->common.internal;
|
||||
static void mouse_dispatch(MwLL self, MwMouse p, MwU32 state) {
|
||||
MwLL target = find_target(self, &p.point);
|
||||
|
||||
switch(state) {
|
||||
case WL_POINTER_BUTTON_STATE_PRESSED:
|
||||
MwLLDispatch(target, down, &p);
|
||||
break;
|
||||
case WL_POINTER_BUTTON_STATE_RELEASED:
|
||||
MwLLDispatch(target, up, &p);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
/* walk from the top of the stack down so that only the highest z-index sublevel under the pointer gets the click */
|
||||
MwLL* children = MwLLWaylandSublevelsByZIndex(self);
|
||||
int i, n;
|
||||
for(i = 0; i < arrlen(w->children); i++) {
|
||||
if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) {
|
||||
MwLL child = w->children[i]->lowlevel;
|
||||
for(i = arrlen(children) - 1; i >= 0; i--) {
|
||||
MwLL child = children[i];
|
||||
MwLL topmost_parent = child;
|
||||
MwPoint point;
|
||||
MwPoint relative_mouse_pos;
|
||||
|
|
@ -827,9 +818,10 @@ static void mouse_dispatch(MwLL self, MwMouse p, MwU32 state) {
|
|||
}
|
||||
|
||||
mouse_dispatch(child, p, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
arrfree(children);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,17 +13,48 @@ MwBool MwWaylandVulkan = MwFALSE;
|
|||
|
||||
MwBool MwWaylandCairoOnly = MwFALSE;
|
||||
|
||||
void MwLLWaylandChildrenIterate(MwLL handle, void (*func)(MwLL handle, MwLL child)) {
|
||||
MwLL* MwLLWaylandSublevelsByZIndex(MwLL handle) {
|
||||
MwLL* r = NULL;
|
||||
if(handle->common.internal) {
|
||||
MwWidget w = handle->common.internal;
|
||||
int i;
|
||||
int i, j;
|
||||
for(i = 0; i < arrlen(w->children); i++) {
|
||||
if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) {
|
||||
MwLL child = w->children[i]->lowlevel;
|
||||
func(handle, child);
|
||||
if(child->wayland.type != MwLL_WAYLAND_SUBLEVEL) continue;
|
||||
|
||||
/* insertion sort, stable so that equal z-indexes keep their creation order */
|
||||
arrput(r, child);
|
||||
for(j = arrlen(r) - 1; j > 0 && r[j - 1]->wayland.z_index > child->wayland.z_index; j--) {
|
||||
r[j] = r[j - 1];
|
||||
}
|
||||
r[j] = child;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void MwLLWaylandSetZIndex(MwLL handle, MwI32 z_index) {
|
||||
MwLL root = handle;
|
||||
|
||||
if(handle->wayland.z_index == z_index) return;
|
||||
handle->wayland.z_index = z_index;
|
||||
|
||||
/* sublevels are composited by their root, so that's what needs to redraw */
|
||||
while(root->wayland.type == MwLL_WAYLAND_SUBLEVEL && root->wayland.parent) {
|
||||
root = root->wayland.parent;
|
||||
}
|
||||
root->wayland.do_cascading_draw = MwTRUE;
|
||||
root->wayland.events_pending = 1;
|
||||
}
|
||||
|
||||
/* Iterate over the sublevel children of a widget, from the bottom of the stack to the top */
|
||||
void MwLLWaylandChildrenIterate(MwLL handle, void (*func)(MwLL handle, MwLL child)) {
|
||||
MwLL* children = MwLLWaylandSublevelsByZIndex(handle);
|
||||
int i;
|
||||
for(i = 0; i < arrlen(children); i++) {
|
||||
func(handle, children[i]);
|
||||
}
|
||||
arrfree(children);
|
||||
}
|
||||
|
||||
static int event_loop(MwLL handle);
|
||||
|
|
@ -813,35 +844,21 @@ static void clip(MwLL handle) {
|
|||
cy = 0;
|
||||
mx = toplevel->wayland.ww;
|
||||
my = toplevel->wayland.wh;
|
||||
// ws is traversed result
|
||||
// ws[ws.length - 1] is ignored bc it's toplevel
|
||||
/* ws is traversed result */
|
||||
/* ws[arrlen(ws) - 1] is the toplevel, which is the origin */
|
||||
for(i = arrlen(ws) - 2; i >= 0; i--) {
|
||||
int j;
|
||||
int l = 0;
|
||||
|
||||
x += ws[i]->wayland.x;
|
||||
y += ws[i]->wayland.y;
|
||||
|
||||
for(j = i - 1; j >= 0; j--) {
|
||||
if(ws[j]->wayland.x > cx) l = 1;
|
||||
if(ws[j]->wayland.y > cy) l = 1;
|
||||
if(l) break;
|
||||
cx = MAX(cx, x);
|
||||
cy = MAX(cy, y);
|
||||
mx = MIN(mx, x + (int)ws[i]->wayland.ww);
|
||||
my = MIN(my, y + (int)ws[i]->wayland.wh);
|
||||
}
|
||||
|
||||
if(!l) {
|
||||
cx = MAX(cx, ws[i]->wayland.x);
|
||||
cy = MAX(cy, ws[i]->wayland.y);
|
||||
}
|
||||
|
||||
mx = MIN(mx, x + ws[i]->wayland.ww);
|
||||
my = MIN(my, y + ws[i]->wayland.wh);
|
||||
}
|
||||
|
||||
if(mx < cx) mx = cx;
|
||||
if(my < cy) my = cy;
|
||||
|
||||
arrfree(ws);
|
||||
|
||||
/* fully hidden, clip to an empty rectangle */
|
||||
if(mx < cx) mx = cx;
|
||||
if(my < cy) my = cy;
|
||||
|
||||
|
|
@ -1937,21 +1954,20 @@ static MwBool MwLLDoModernImpl(MwLL handle) {
|
|||
}
|
||||
|
||||
static void MwLLRaiseImpl(MwLL handle) {
|
||||
(void)handle;
|
||||
/*
|
||||
MwLL* siblings;
|
||||
int n;
|
||||
|
||||
if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL) {
|
||||
MwLL topmost_parent = handle;
|
||||
int children_num;
|
||||
while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent;
|
||||
children_num = arrlen(((MwWidget)topmost_parent->common.internal)->children);
|
||||
|
||||
if(children_num > 1) {
|
||||
printf("%d\n", children_num);
|
||||
MwWidget last_child = ((MwWidget)topmost_parent->common.internal)->children[children_num - 1];
|
||||
wl_subsurface_place_above(handle->wayland.sublevel->subsurface, last_child->lowlevel->wayland.framebuffer.surface);
|
||||
if(handle->wayland.type != MwLL_WAYLAND_SUBLEVEL || !handle->wayland.parent) {
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
/* put it one above whichever sibling is currently on top */
|
||||
siblings = MwLLWaylandSublevelsByZIndex(handle->wayland.parent);
|
||||
n = arrlen(siblings);
|
||||
if(n > 0 && siblings[n - 1] != handle) {
|
||||
MwLLWaylandSetZIndex(handle, siblings[n - 1]->wayland.z_index + 1);
|
||||
}
|
||||
arrfree(siblings);
|
||||
}
|
||||
|
||||
static void MwLLClipImpl(MwLL handle, MwRect* rect) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue