gyscos / cursive

A Text User Interface library for the Rust programming language
MIT License
4.3k stars 245 forks source link

Cursive app hangs on Windows with pancurses backend #276

Open agavrilov opened 6 years ago

agavrilov commented 6 years ago

Problem description

"Hello world" example hangs on Windows with pancurses backend. Here is the example project where it is reproducible.

Environment

gyscos commented 6 years ago

Doh :( Thanks for reporting! I don't have a windows install at the moment so this wasn't tested much... I'll see what I can do.

gyscos commented 6 years ago

I can confirm the window is unresponsive. :^/ I'm afraid it may be caused by our use of threads with pancurses - we're quite brutally declaring pancurses Sync when it probably shouldn't. :'( Will investigate.

gyscos commented 6 years ago

As I feared, this appears to be caused by accessing the pdcurses backend from two different threads. We "lied" about the backend being Sync, and it's now biting us where it hurts.

Will have to look for alternative solutions. One way would be to poll events at >= 30Hz, and be smart about not redrawing if nothing happened. This may interfere a bit with set_fps, but we can probably manage. Hopefully CPU impact will be reasonable.

inferiorhumanorgans commented 6 years ago

Would it be possible to lock and wait instead of polling more frequently?

gyscos commented 6 years ago

That's the problem: while we wait, we want to be able to react to a callback sent from another thread, which probably involves re-drawing the screen. This means if we block, we must access the backend from 2 different threads (one reading input, one drawing). I hoped this concurrent access would be fine as we're accessing different modules (input vs output), but it seems I was wrong.

Ideally we would have a "interruptable wait" API which could be preempted by a signal/channel/anything (so we could select on it), but I'm not sure it's doable here.

The only other way is to fake this API with polling. I believe we can limit the performance impact; polling itself isn't very expensive, the problem until now is that it cursive would refresh the screen every time, which is expensive.

fawick commented 6 years ago

FWIW: I was able to workaround this problem by putting the following in Cargo.toml

[dependencies.pancurses]
features = ["win32"]

It causes pancurses (or pdcurses-sys, actually) to not use the GDI interface, but the Windows console. Details here: https://github.com/ihalila/pancurses#pdcurses-windows-details