Re: Autoupdating EntryCompletion (was Selectively trapping keypresses)




On Apr 17, 2007, at 10:42 AM, Jeffrey Ratcliffe wrote:

On 17/04/07, muppet <scott asofyet org> wrote:
I couldn't reproduce that after tinkering for just a few moments, but i think
i see it in the code...

Replace "one" with "twelve" twice, and during the second replacement,
the error comes.

Any change to a TreeModel invalidates existing TreeIters.

$cmp_model -> signal_connect('row-inserted' => sub {
  my ($model, $path, $iter) = @_;
  my ($val) = $cmp_model->get($iter, 0);
warn "inserted $val\n";

# Weed out duplicates
  my $iter2 = $cmp_model->iter_next($iter);
 while ($iter2) {
  my ($val2) = $cmp_model->get($iter2, 0);
warn "list $val2\n";
  if ($val eq $val2) {
warn "removing $val2\n";
   $cmp_model->remove ($iter2);
warn "removed $val2\n";

I can add a return statement here, as there will only ever one
duplicate, and then there are no problems with iters. But the error
still comes.

I spent a few minutes running this code under gdb with the --g-fatal- warnings option...

The EntryCompletion uses a TreeModelFilter to narrow down the contents of the completion model to match what you've already typed. By the time we're doing that, the completion model is in a rather hosed state, and we get warnings about iters not being valid. Specifically, the iter's stamp does not match the model, which means that something Very Bad has happened.

The basic situation in which i've seen this happen before is modifying the model while iterating over it, which is exactly what your row-inserted handler is doing. I can't pinpoint exactly *how* it is getting corrupted; it would take a lot of tracing and digging through unfamiliar code, since the error happens quite a way after the actual corruption occurs, and i'm just not up for that tonight.

On a hunch that the problem stems from modifying the completion model in a handler for a signal that is emitted when the model is modified... i tried a slightly different approach.

Your code is unconditionally adding the user's text to the completion model, and then scraping out any duplicates. Why let the duplicates in there in the first place?

I removed the entire row-inserted handler, and did this, instead:

  sub update_completion_model {
      my ($model, $new_value) = @_;
      # If not already in there, append.

      my $iter = $model->get_iter_first;
      while ($iter) {
          my $old_value = $model->get ($iter, 0);
          return if $old_value eq $new_value;
          $iter = $model->iter_next ($iter);
      }

      $model->insert_with_values (-1, 0, $new_value);
  }

  $slist -> get_model -> signal_connect('row-changed' => sub {
      my ($model, $path, $iter) = @_;
      my $text = $slist->get_model->get($iter, 0);
      update_completion_model ($cmp_model, $text);
  });


And i can no longer trigger the assertion failures.


--
If the monkey could type one keystroke every nanosecond, the expected waiting time until the monkey types out Hamlet is so long that the estimated age of the universe is insignificant by comparison ... this is not a practical method for writing plays.
  -- Gian-Carlo Rota





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