Project directory structure
Thiago Macieira
thiago at macieira.org
Wed Apr 3 13:07:27 PDT 2013
On quarta-feira, 3 de abril de 2013 12.13.40, Dirk Hohndel wrote:
> > For Subsurface, the notification that the download from the divecomputer
> > finished would be a signal. Since that code is in C, we'd simply do with a
> > regular callback that in turn emits the signal. The UI will react soon.
> > Similarly for a progress bar, if any: the callback from the download
> > routine with the update emits a signal.
>
> So how would this be handled from C code? Right now (because of
> limitations with the way Gtk does things) the main thread does something
> like this:
>
> while (!import_thread_done) {
> if (!import_thread_cancelled) {
> int result;
> g_timeout_add(100, timeout_func, dialog);
> update_progressbar(&data->progress, progress_bar_fraction);
> update_progressbar_text(&data->progress, progress_bar_text);
> result = gtk_dialog_run(dialog);
> switch (result) {
> case GTK_RESPONSE_CANCEL:
> import_thread_cancelled = TRUE;
> progress_bar_text = _("Cancelled...");
> break;
> default:
> /* nothing */
> break;
> }
> } else {
> update_progressbar(&data->progress, progress_bar_fraction);
> update_progressbar_text(&data->progress, progress_bar_text);
> usleep(100000);
> }
> }
Hmm... let me see... showing a modal dialog with a progress bar and a Cancel
button that tells the import thread to stop. Right?
sleep, usleep and other arbitrary timeouts are evil. Don't tell Arjan you're
waking up 10 times a second to update a progress bar. So the first question is:
is there a callback from the download thread when there's and update to the
progress?
If there is no such callback, the UI thread will need to do the polling. The
code could use QProgressDialog, which provides the dialog and the cancel
button, and look very similar to the current Gtk code. Or it could change a
little by using a QTimer and letting the event loop run unimpeded.
If there is such a callback, we can connect the adapted Qt signals to a
QProgressDialog and to the main window.
Something like:
// in the main window's constructor:
// range is [0..100]
progress_dialog = new QProgressDialog(_("Downloading..."),
_("Stop download"), 0, 100, this);
connect(progress_dialog, SIGNAL(canceled()), SLOT(cancel_download());
#if we have to poll
timer.setInterval(100);
connect(&timer, SIGNAL(timeout()), SLOT(update_progress_bar()));
#endif
// slots
void MainWindow::cancel_download()
{
download_job->cancel();
progress_dialog->hide();
// dispose of download_job somehow later
}
void MainWindow::on_download_button_clicked()
{
download_job = new DownloadJob;
connect(download_job, SIGNAL(progress(int)),
progress_dialog, SLOT(setValue(int)));
connect(download_job, SIGNAL(updated_text(QString)),
progress_dialog, SLOT(setLabelText(QString)));
connect(download_job, SIGNAL(finished()), SLOT(process_results()));
progress_dialog->setValue(0);
download->start();
}
The above might look a little more complex, but it has two added benefits
compared to the Gtk code you pasted:
1) no polling, the main thread can sleep for as long as it wants
2) no nested event loops
> And we use the global variables import_thread_cancelled,
> import_thread_done progress_bar_text and progress_bar_fraction to
> communicate from the download thread to the UI thread.
> The stupid timeout mechanism is working around Gtk's inability to do the
> updates from a separate thread (I understand the same is true for Qt).
Indeed. But the code above neatly works around the issue by using signals and
slots. Qt will take care of crossing the thread barrier for you. All slots
associated with MainWindow or QProgressDialog will be executed in the main
(UI) thread automatically.
> We use pthreads right now:
>
> pthread_create(&pthread, NULL, pthread_wrapper, data);
>
> and then
>
> if (pthread_join(pthread, &retval) < 0)
> retval = _("Odd pthread error return");
Even on Windows?
If the threading code is inside libdivecomputer, I'd leave it where it is. If
it's in Subsurface, I'd recommend wrapping it with that DownloadJob class
above. It would create a QThread and provide a few C callbacks for the actual
download (written in C). The callbacks would emit the signals I listed.
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 190 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.hohndel.org/pipermail/subsurface/attachments/20130403/9ec66961/attachment-0001.sig>
More information about the subsurface
mailing list