octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Debugging and the GUI Editor; Qt help needed


From: Daniel J Sebald
Subject: Re: Debugging and the GUI Editor; Qt help needed
Date: Thu, 28 Mar 2013 14:00:34 -0500
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.24) Gecko/20111108 Fedora/3.1.16-1.fc14 Thunderbird/3.1.16

On 03/28/2013 01:21 PM, John W. Eaton wrote:
On 03/28/2013 02:08 PM, Daniel J Sebald wrote:
On 03/28/2013 02:43 AM, John W. Eaton wrote:

It would be helpful if people could test these new features. There is no
need to report the problems I've listed above, but if you find other
things that don't work correctly, let me know. Or if you'd just like to
say, "Wow, these new features look awesome!" that would be fine too.

I haven't compiled and run yet, so I assume it looks awesome.

I looked at the code, though, e.g.,

http://hg.savannah.gnu.org/hgweb/octave/rev/389b09a914e2

and I would suggest that we try to not introduce callbacks in the way
you have done. The problem with the callbacks is it is connecting two
threads with functions. We should be using the Qt signal/slot mechanism
across threads. Otherwise there is a good chance we're unnecessarily
restricting capabilities and possibly making programming more difficult
down the road.

Then can you please provide an example that shows how to do that for one
of these cases? I don't mind changing the way things are done if it
really does make a difference, but I need some pointers here as I'm
almost clueless about the proper way to do Qt programming. Just saying
"use signals/slots" doesn't help me much.

This evening and tomorrow I can clean up the code I have and create a patch. I think it is easiest to work from a diff file. But for the time being here are a few lines to illustrate, and I'm sure it will be clearer with the whole changeset to follow:

IN THE OCTAVE THREAD

I've written some builtin routines that really don't touch core Octave code. Instead, they act like a driver of sorts. e.g.,

          // Signal GUI thread to put up simple message box using OK
          // as the only button.
uiwidget_creator.signal_dialog (message, title, icon, QStringList (),
                                          QString (), QStringList ());

          // Wait while the user is responding to message box.
          waitcondition.wait (&mutex);

The above uiwidget_creator is just a basic class where I've organized all the signals and slots. It is basically an "emit" with the same input arguments as "signal_dialog()". I do that so that the data transferred across threads can be stored in uiwidget_creator's object. Anyway, you can see that the octave thread emits the signal, then suspends itself, with no function call across to the GUI thread. Later the thread is awaken with:

void
QUIWidgitCreator::dialog_finish_continue (int result)
{
  // Store the value so that builtin functions can retrieve.
  dialog_result = result;

  // Wake up Octave process so that it continues.
  waitcondition.wakeAll();
}

which is a slot that is accessed by the GUI thread emitting the connected signal. The "result" is the data that the GUI thread is sending. Pretty minimal in this case. After the "wakeAll", the Octave thread continues right after the "waitcondition.wait (&mutex);" line in the hunk above.

IN THE GUI THREAD

At startup, the main window makes the connections:

  connect (&uiwidgit_creator, SIGNAL (create_dialog (const QString&,
                              const QString&, const QString&,
                              const QStringList&, const QString&,
                              const QStringList&)),
           this,              SLOT (handle_create_dialog (const QString&,
                              const QString&, const QString&,
                              const QStringList&, const QString&,
                              const QStringList&)));

so that the Octave thread can signal that it would like a QMessageBox placed on the screen.

The "handle_create_dialog" slot in the GUI thread then does this, and it makes connections between the message box it is creating and the slots (analogous to callbacks) in the Octave thread.

// Create a dialog with specified string and connect to a wait condition
// to wake up thread.
void
main_window::handle_create_dialog (const QString& message, const QString& title, const QString& icon, const QStringList& button,
                                   const QString& defbutton,
                                   const QStringList& role)
{
// Process all this stuff

  // Create a NonModal message about error.
  QMessageBox* msgBox = new QMessageBox (eicon, title, message, 0, 0);

  connect (msgBox,            SIGNAL (buttonClicked (QAbstractButton *)),
&uiwidgit_creator, SLOT (dialog_button_clicked (QAbstractButton *)));
  connect (msgBox,            SIGNAL (finished (int)),
           &uiwidgit_creator, SLOT (dialog_finish_continue (int)));
  msgBox->show ();

You can guess that the slot on the Octave thread side (dialog_finish_continue), is that small hunk of code that wakes up the Octave thread. Whenever the button on the QMessageBox is pressed, it signals the slot in the Octave thread that it is finished and gives it the data.

SUMMARY

So, there isn't any function call across threads. This example is a little more dynamic than what might be needed for the debugger because the message box is created and then connections are made. In the debugger case, maybe just the initial connections at startup would be needed. What the example I give does do is it enables the use of the Mutex and other similar concepts in Qt. That's the thing that could prove beneficial down the line. Hard to say, but I just think that remaining within the Qt paradigm as much as possible can only be good.

How might this play out in the debugger case? Well, one can be creative and come up with different ways, but I can imagine that clicking a debug tab issues a signal to some object in the Octave thread that then disables the breakpoint in Octave core code. So on. These things are a bit of trial and error for a while until everything falls in place and then it is like, "I should have used that signal/slot sooner!".

Think in terms like this:

                                      |
OCTAVE CORE <--> BUILTIN COMM OBJECT  |  GUI THREAD
                                      |

and there are signals/slots across the thread.

Dan


reply via email to

[Prev in Thread] Current Thread [Next in Thread]