QWebView setContent in a separate thread - multithreading

I have an application that requires to use QWebView::setContent() to load some HTML content to a QWebView. All of this happens on an embedded device with ARMv5 processor (think 400 MHz). Most of the time, I can load the page in reasonable time (up to 5 seconds), however sometimes I have content that takes long time to load (~30 seconds for 300KB of content).
The problem is that the setContent call blocks the main thread. I need to be able to process events during the loading, and maybe even cancel the load if the user decides not to wait any longer.
I was thinking about running the setContent call in other thread, so that it does not block the event processing and I can cancel it if necessary. However, I get the dreaded "widgets must be created in the GUI thread", and I see no way of solving this easily.
Is it possible to run QWebView::setContent in a separate thread? If so, how? If not, is it possible to handle GUI events while setContent is running? Is it possible to "cancel" the setContent call?
EDIT
To clarify a bit more, what really interests me is how to be able to stop the setContent call and/or handle GUI messages, so that the interface remains responsive, with large amounts of data passed using setContent.
EDIT 2
To clarify even further, I am dealing with long, static content, i.e. no JavaScript, just a lot of static HTML, through which the user wants to scroll even while it is loading more content. The main idea is to allow her/him to go down a page even when the page is not fully loaded.

Some time ago I faced a similar problem. As far as I know, only the main contents of the page is acting synchronously.
The fact is that the GUI core "paints" the page and this is time consuming. So, the main thread gets freezed until the main contents is loaded completely.
In my case, the solution was simple: make the main contents a secondary one and work with local files!!!
So, what is my proposal:
1) Prepare a local file (/tmp/loader.html) that contains something like this:
<html>
<body onload='setTimeout(function() { window.location="contents.html"; }, 1000);'>
Loading...
</body>
</html>
2) Each time you need to load a new content, save it to the secondary file (/tmp/contents.html) and force the update of the loader (maybe also a refresh). Easy:
QFile f("/tmp/contents.html");
if (f.open(QFile::WriteOnly)) {
qint64 pos = 0;
while (pos < contents.length()) {
pos += f.write(contents.mid(pos, 1024)); // chunk of 1024
qApp->processEvents();
}
f.close();
webview->setUrl(QUrl::fromLocalFile("/tmp/loader.html"));
}
Observe that I permit the event loop to process pending events if the file saving is also slow...
3) Anytime you need to cancel the loading, you can load another contents, remove the contents file, or other possible approaches.
Note that, as far as I know, you would never make asynchronous the painting of the contents. And that is the real issue in embedded systems.

Since QWebView::setContent() is a blocking call, I ended up using a work-around. The main idea is that XML processing is much faster than rendering the page. Therefore I do the following:
Parse the document as XML DOM document (a reasonable assumption in my case), and find the body element.
Keep only a pre-defined number of child elements of body (something like 20 elements). Store the remaining elements in another XML DOM document.
Show the initial document (serialized XML) using QWebView::setContent(), which is relatively fast. Start a timer with timeout 0 on SLOT(loadNextChunk()).
loadNextChunk() moves another 20 or so elements from the backup document at the end of the body using body->appendInside(html), where body is a QWebElement.
Stop when no more elements are available.
This works because in between the calls to loadNextChunk(), the GUI has a chance to react to events.

QWebView, as its name suggests, is a widget. QWebPage, on the other hand, is a plain old QObject, with all the threading goodness you could possibly want.
Now tie it together:
void QWebView::setPage ( QWebPage * page )

Related

can i correctly finish an android app in Kotlin, when i swipe it out?

I hope, I can formulate my question correctly and understandable.
When I write an Android App in Kotlin, I normally have a button to close the app and for example finish it with writing a file or something like that.
Now, sometimes I don't finish it with the button, but swipe it out. Then, the file is not wirtten..
Is there a Kotlin statement to catch the "swipe out" and perform some code? When I Inflate another view, at the end I have a dismiss-statement or dismiss.listener and can do some code.
example:
dialog.dismiss() or popupwindow.dismiss()
So question: is there a dismiss.app or something like that?
When your app's Activity is destroyed (either by the user swiping it away, or the system killing the app to free up some resources) it goes through the usual lifecycle steps, ending with onDestroy.
These steps also get pushed to any lifecycle-aware components that are observing that activity's lifecycle, including Fragments (like a DialogFragment) - so that will also get an onDestroy() call. Fragments can be destroyed at other times too, but you can look at the activity's lifecycle to see what's going on there if you need to.
But really, as a general rule you want to save data in something like onStop(), when the activity/fragment is going to stop being visible, i.e. it's going into the background. That's a good time to make sure you've saved all your important data and state, because the user may not be coming back, and you can't be sure onDestroy will be neatly called (e.g. there could be a crash, or the phone might suddenly lose power).
Don't rely on persisting data with the onSaveInstanceState() callback though - that's intended for saving UI state, and if the user backs out of the app / swipes it away, that's counted as a fresh start for the next time they load the app, so onSaveInstanceState won't be called (since the UI state isn't being saved). Use onStop instead (or onPause if you like - have a look at those links for more info on what the difference is)

Phaser3 Scenes transitions

I'm new to Phaser3 and before starting a crazy project, I want to know how I should start, switch between scenes. I saw that there are several functions, start, launch, switch, run, resume, pause, etc.
Example, lets say I want to have 2 scenes, a Menu and a Game. I boot on the Menu and I want to go to the Game scene and if I click on a button then come back to the Menu scene.
I've achieved this by calling the start function, but I noticed that the all, init, preload and create functions are called every time and therefore I'm loading all the images, setting all the listener over and over again.
This seems wrong, should I be using the launch or switch functions and pausing and resuming? But how do I hide the previous scene?
Thanks in advance.
This question might be a little too broad, but with Phaser 3 in mind, it still depends upon what purpose your menu serves.
I think most games have a main menu that will generally be called when the game first starts, and then won't be called again.
If this is an in-game menu, where settings can be changed or part of the game can be reset/restarted, then it might not make sense to redirect to a completely different scene.
With Phaser 3's support of multiple scenes - with Dev Log #119 and Dev Log #121 probably being the best current sources of information - another option would be to start a new scene within the current scene to handle this.
However, if this is really just UI, there's nothing to stop you from creating an overlay, instead of spawning an entire scene.
If you're concerned about performance I might think about whether the entire menu needs to be called, or if a simplified menu would work. Also, make sure that you're preloading assets before you're in the menu and main game.
I personally use Boot > Preloader > Splash Screen > Main Menu > Main Game scenes, where the Preloader loads the majority of the assets I'll need. This has the downside of a longer initial load, but the upside of minimal loading after this point.
Scene Transitions
How I handle these in my starter templates is to add the scenes to the Scene Manager when creating the scene. Then I transition by start to the first scene.
this.scene.add(Boot.Name, Boot);
this.scene.add(Preloader.Name, Preloader);
this.scene.add(SplashScreen.Name, SplashScreen);
this.scene.add(MainMenu.Name, MainMenu);
this.scene.start(Boot.Name);
Then I simply keep starting the next scenes as needed.
this.scene.start(Preloader.Name);
For another game that uses multiple scenes I ended up creating the following function (TypeScript) to handle this:
private sleepPreviousParallelScene(sceneToStart: string): Phaser.Scene {
if (this.uiSceneRunning !== sceneToStart) {
// Make sure that we properly handle the initial state, when no scene is set as running yet.
if (this.uiSceneRunning !== "") {
this.scene.get(this.uiSceneRunning).scene.sleep();
}
const newScene = this.scene.get(sceneToStart);
newScene.scene.start();
this.scene.bringToTop(sceneToStart);
this.uiSceneRunning = sceneToStart;
return newScene;
} else {
return this.scene.get(this.uiSceneRunning);
}
}
In the game I was using this for, I was trying to replicate a standard tab interface (like what's see in the Dev Logs above with the file folder-like interface).
Ok, here is the deal. In phaser 3, the start function actually SHUTS DOWN the previous scene as it starts the new one. This is why you see the init, preload ext every time. If however, you 'launch' your scenes instead, then they will not go through the whole shut down, restart sequence. You can move them to the top or bottom, set to receive input or not, etc. HOWEVER, BEWARE! As of phaser 3.16, sleep or pause of a scene does NOT shut down the update. As a result, if you launch a scene, then sleep it, it basically does nothing other than maybe set the flag, saying it's asleep even though it really isn't. So any update processing will continue in any launched scene. You can short circuit the update with a flag of some sort at the beginning, (that's what I've resorted to), but the other gotcha is the camera size. All the scenes must therefore have the same camera size or they will render (even if "sleeping") and mess up your display.
So, bottom line, it's going to be messy until sleep and pause actually work.

Reliably waiting for page to load or reflow in Awesomium.NET 1.7+

Which is the recommended way of waiting for a page to load/reflow in Awesomium.NET 1.7+ when running in a non-UI environment? I've tried this approach:
using (var view = WebCore.CreateWebView(...))
{
// Load page, resize view etc.
// ...
do
{
System.Threading.Thread.Sleep(50);
WebCore.Update();
} while (view.IsLoading);
// Do something with the page
// ...
}
However, this doesn't seem to work reliably - if I render the page to a bitmap after the loop it pretty often comes out blank (but not always). Is there a better way of waiting for page load/reflow?
Try subscribing to the WebView.DocumentReady event.
How you do it depends on what you are waiting for. The code in the question should work when waiting for a page to load, but resizing the view is different - check out the BitmapSurface.Resized event, it fires when the BitmapSurface has been resized and updated its buffer.

Cocoa Stop Button

I load a file from the disk, chunk by chunk, and I would like to grant the user the opportunity to click on a button and stop loading. I already know how to do that with threads (e.g. detachDrawingThread) but here I wouldn't use that way. The loading method in facts should return a bool value, it's called from different points and it's usually followed by many other lines of code. So I can't launch the thread and leave it work in a separated thread. And I can't split my code so easily. It's really complicated.
I just need to detect if the user clicked on a given button. That's all.
Is a quick and simple way to do that without rewriting my whole app?
Your loading routine must be using some sort of loop. Create a boolean and in your loop test for the condition of the boolean. Then in your button selector, set the selector to change the status of the boolean. Once your loop goes around again, it will exit and stop loading data.
First rule of good Mac apps:
Don't block the main thread
Some options:
Do the work on a background thread. Sounds like you don't want to/can't in this case
Use something like NSURLConnection to process the data in small chunks on the main thread as it's read in, rather than running a continuous loop
Run the event loop periodically while loading data so UI events can be processed
Thanks, I usually use threads, but in this case in order to use a thread I should almost re-write my app... So I have found a quick solution. Within the loop I added:
while(event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]){
[NSApp sendEvent:event];
}
So when the user clicks on the button to stop the loop, I post a notification and exit the loop. It works well.

C# IE BHO: Do work asynchroniously while keeping to the same thread?

I have an IE BHO that's in development in C#. It is supposed to wait for the user to do some stuff, contact our server and download some data, and then alter the DOM of the currently loaded web page with the results.
I am running into some seemingly insurmountable issues relating to the rules of COM compartmentalization and threading -- namely, I can't seem access the IE DOMDocument outside of the current thread and I can't think of any way to run something asynchronously without locking up IE until it's finished.
My first attempt had the background server-communication stuff do its thing in an event-driven fashion: my program would initiate communications from within an mshtml event (BeforeNaviagate2 or DocumentComplete, for example), and would post the results from within a separate event handler fired by the server communication object when it finished its work.
That techniqued worked fine in a quick simulator I cobbled together (just a simple app with a WebBrowser control) but in IE it would throw a COM exception because I was attempting to alter page DOM through a separate thread.
So I tried keeping everything in the same function, and having my code wait for the server communications object to do its work with a while loop, like this:
int waited = 0;
while (!OurServerCommRequest.ready) {
System.Threading.Thread.Sleep(1);
Application.DoEvents();
waited++;
if (waited > constants.TIMEOUT_OURSERVER_REQUEST) {
log.wL("Timed out");
}
}
The problem with this approach is while the code stays in the original thread, it executes synchroniously with the IE process it fired in (in IE8, it's one process per tab -- like Google Chrome -- it seems) ... therefore locking up the IE interface until my server communications completes.
Initially I wanted to start processing as soon as the URL was available (via NavigationComplete2 event) but I discovered that waiting for the <body> tag to become available should my server communications finish before the user's page loaded would also lock up IE -- throwing it into an infinite loop while my code waits for the HTML body, while the page is prevented from updating itself do to the aforementioned loop.
I've thought about moving all this into the actual user's page javascript but it seems that by doing so I am opening up a can of worms in wrangling with XSS security issues.
So... my question is such: is it possible to run code asynchroniously in an C# IE BHO while still being able to manipulate the user's page DOM? I've asked around some friends and most people tell me that it is not likely. I'm still new at COM and C#, having come from C/VB.net/JS/AS.
Thank you!
-Tom
You need to marshal the DOM object from the thread it was created on to your worker thread. Here is a very detailed breakdown of how COM and C# play together.
All of the IE DOM objects are STA objects.

Resources