Briliant, thanks a lot ! Looks like I misunderstood Adam's reply,
sorry about that !
I tried different things but I didn't think of calling invoke
from within the worker thread, that solved the freezing problem.
I ended up using the Thread class; spawn complained about the
mutability of the given arguments. I realize what I did may be an
ugly solution for the problem at hand, so I'll try to modify the
code in order to avoid giving the thread UI elements altogether,
thus being able to take advantage of more.. modern techniques
like std.concurrency.
I'm using the Timer trick on another part of the project. Right
now I'm running instances of a Downloader class in the
background, a class that extends Thread and provides some useful
functionality : a way to track the progress, to set rate limits,
to abort the download, etc. It seems to be working fine, I'm
using the (incomplete) program to download Visual Studio as we
speak.
I set up a timer to periodically retrieve the progress of a
download from the instances then update the ListView accordingly.
Right now I'm hesitating between continuing with this approach vs
using std.concurrency or even std.parallelism since the downloads
are supposed to run in parallel without communicating with one
another, but the only way I see would be to place the message
handling code inside a loop, which for some reason doesn't sit
right with me. I'm still learning concurrency (courtesy of Ali
Çehreli and his book), so maybe my doubts are unfounded. Here's
what I'll probably end up using, minus the error handling :
void dlWorker(HTTP client, string local, string remote, bool
resume = true)
{
auto fh = File(local, resume ? a : w);
scope(exit)
fh.close;
size_t size;
size_t progress;
client.onProgress = (size_t dlTotal, size_t dlNow, size_t
ulTotal, size_t ulNow) {
size = dlTotal;
progress = dlNow;
};
client.onReceive = (ubyte[] data) {
fh.rawWrite(data);
return data.length;
};
client.perform;
while(!client.isStopped)
{
auto msg = receiveOnly!(MsgType, int)();
switch(msg[0])
{
case MsgType.progress: send(ownerTid, progress); break;
case MsgType.size: send(ownerTid, size); break;
case MsgType.abort:
client.shutdown;
send(ownerTid, 1);
break;
default:
client.handle.set(CurlOption.recv_rate_speed_large, msg[1]);
send(ownerTid, 1);
break;
}
}
}
enum MsgType
{
progress, size, abort, limit;
}
Though I'm not entirely sure how I would tie the ListView rows to
their respective workers. But I'll cross that bridge when I get
to it.
Again, thanks for all the help. You guys are definitely going to
be mentioned in the About section of the finished product.