So I’m finally trying to refactor Lgi to do it’s event handling on the BApplication thread, rather than lots of different BWindow threads. Apparently this is how the other GUI libraries on Haiku work. Including the X11 backend. And will hopefully make the Haiku port run is a similar fashion to the Windows, Mac and Linux/GTK ports which all have a single GUI thread.
The issue I see is that the resizing of windows has become very glitchy. The way I’m implementing things is the BView::Draw override sends a BMessage over to the BApplication thread which then locks the attached BWindow and draws over the view in question.
It seems like the BView::Draw override detects that nothing was drawn and draws a grey background. And then very soon after that my app thread handler draws the view over that background and that causes the flickering.
The code sending the message: View impl
…see the “void Draw(BRect updateRect)” override.
This sounds wrong. If it is for a window it should be handled there, one window should not block another which would happen if you do all in the BApplication, other libs doing this in one thread is more out of neccesity afaik.
You can set the view color to B_TRANSPARENT_COLOR and/or set the view flag B_TRANSPARENT_BACKGROUND (there are differences between the two, but I forgot what exactly) to avoid the grey.
You may also want to disable B_FULL_UPDATE_ON_RESIZE in this case.
That should work for what you’re trying to do, but it may not be ideal.
Another option (used for example in WebPositive) is to have the main window thread render everything in a BBitmap that the “real” view then displays, either by using SetViewBitmap() or by DrawBitmap(). In that case, the Draw() call for the visible view always have a version of the bitmap to draw from, there is no flickering, and you can reduce the amount of redrawing in some cases (if the view has not been resized, there is usually no need to redraw anything at all and the bitmap can be reused). The cost is more RAM use due to all the offscreen bitmaps.
I’m one of those libs! lol
Yeah the issue is that the apps that use Lgi have been written around the concept of “there is 1 gui thread” which holds true for win/mac/linux, and while the smaller ones can often be refactored to do things the haiku way the larger ones definitely cannot. I’ve put too much shared data in the main window’s object that everything assumes it can use without locking. While I totally get it that it’s going to cause issues if something locks up the app thread and the whole app gets bogged down, that’s also true of all the other platforms these apps run on. In general they are very good at NOT blocking the gui thread. And offload anything that takes a long time into worker threads or doing it via timers or something. Therefor I’m not too concerned about that.
@PulkoMandy I’ve striped my test app down to a single BWindow and one BView, where all the events are posted across to the application thread. The view has B_TRANSPARENT_BACKGROUND and SetViewColor(B_TRANSPARENT_COLOR) set. The main issue I see is that the white of the BWindow draws before the grey of the BView so as you resize it’s constantly flickering between white and grey, as the BWindow draws and then moments later the BView that covers the whole client area. This is obviously not desirable. Is there some way to stop the BWindow drawing it’s white background?
Did you call SetViewColor(B_TRANSPARENT_COLOR) in your view constructor (directly or indirectly) ?
Iirc, you must call it after your view is attached to the window. Like in its AttachedToWindow() hook method.
The B_TRANSPARENT_BACKGROUND BView flag is for telling that parent view clipping should be rebuild, as one of its child views has no background, so this parent view can’t no more consider it has no role in drawing this area…
In your case (one single view in a window), has your view has no parent view, it will make no difference, even if it’s a good practice to set this flag anyway, in case in the future you decide to allow this view to be used withing another, parent, view.
It is possible to draw in another thread, but then you must unlock BView looper, block BView thread, lock BView looper in your drawind thread, do your drawing, unlock BView looper and finally unblock BView::Draw thread. And be careful for deadlocks.
The point is that you should not let BView::Draw to return until your drawing thread is done.
I didn’t know that, but in any case it didn’t make any difference to the issue I was seeing. It was an easy change to try tho.
Ooo now this is interesting. I’ve tried it out, and yes it gets rid of the white flickering. My question now is, what is the most efficient way to wait for the draw event to be processed? I unlock the BWindow thread, post the event… and wait:
while (!done)
sleep(1ms);
But surely there is a better way? Haiku API specific?
I am doing something similar with the QuitRequested event, so it would make sense to formalize it into the correct way.