Skip to content

Hidden window is to be ignored due to nk_clear #896

@QuanMz

Description

@QuanMz

There's a issue when you set a window hidden (either manually set its NK_WINDOW_HIDDEN flag or do nk_window_show() ), it will only be hidden only for a period, only then to be reinitialized, which defeats the purpose of hiding and it being a flag in the first place

So this line of code in nk_clear function (defined in nuklear_context.c, is called everytime you render a frame)

/* remove hotness from hidden or closed windows*/
if (((iter->flags & NK_WINDOW_HIDDEN) ||
(iter->flags & NK_WINDOW_CLOSED)) &&
iter == ctx->active) {
ctx->active = iter->prev;
ctx->end = iter->prev;
if (!ctx->end)
ctx->begin = 0;
if (ctx->active)
ctx->active->flags &= ~(unsigned)NK_WINDOW_ROM;
}

(do cleanups for 'active' window that isn't really active)
specifically the line ctx->begin = 0; (reset the start pointer of a linked list of windows)
the problem here is it assumes that the hidden window isn't at the 'ctx->begin' (where the 'win->prev' doesnt exist), which isn't always the case, but it set to that anyway without checking

then it choose the window before the hidden one, which may not exist, so it trigger the code and make Nuklear completely forget the window list,
and what worse is that the forgotten window (and the ones after it) won't be freed from memory by the later section of the code since its win->seq (I guess this is like its heartbeat) is valid with the ctx's

/* window itself is not used anymore so free */
if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) {
next = iter->next;
nk_remove_window(ctx, iter);
nk_free_window(ctx, iter);
iter = next;
} else iter = iter->next;

since the reference is gone, the windows will live in the memory with the program, causing memory leak (thank you sleeptightAnsiC for clearing)

and in the next frame, nk_begin (how you start to draw things) can't find the existing window you're talkiing about (since the list reference is gone) so it will create new one with your spec, that means your hidden window is now reseted and live somewhere else in the memory, and when it's hidden and its 'win->prev' gets invalid (due to some internal reorder for Z indexing or something), that cleanup code (for invalid active window) will be triggered, now you're stuck in a loop where you hide window just to see it popup again

Solution?
because i have no idea how do you edit someone's code on github, i've some suggestions:

  • nk_window_show() should clear ctx->active if it is the target window about to be hidden

  • maybe 'nk_end' should clear ctx->active by default?

  • nk_clear should have some more considerations before doing ctx->begin = 0;, and free the unused

  • or use other approach on finding active window (I have a example code in comment)

  • automatically set ctx->active to 0 if current is hidden and let nk_begin in the next frame handles it?

(this is my first time doing this, im sorry for any mistakes or English errors, thank!)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions