GtkEntry::activate and GtkWindow default activation severely broken



widgets have the concept of actiavation, that is ::clicked for a button
or a menu_item and ::activate for an entry. the actiavate signal is
intended to be used to hook up client callbacks to a widget, not to
invoke widget specific magic (in fact, a widget should never need to
implement an activate handler, this is purely meant for user notification).

then there are convenience functions on gtkwindow to activate the
current default or the current focus widget.

recent changes involved changing gtk_window_activate_default() to
activate the focus widget if there's no default widget, and also
GtkEntry::activate to call gtk_window_activate_default(). now usually,
an entry is activated when it has the focus, if there's no default
widget for the window which GtkEntry calls gtk_window_activate_default()
for, this triggers an infinite loop of signal emissions.

things that went wrong here:

  window_signals[ACTIVATE_DEFAULT] =
    g_signal_new ("activate_default",
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  GTK_SIGNAL_OFFSET (GtkWindowClass, activate_default),
                  NULL, NULL,
                  gtk_marshal_VOID__VOID,
                  G_TYPE_NONE,
                  0);

GtkWindow::activate_default is a G_SIGNAL_ACTION signal which means it
needs to be freely emittable from user code (to be used in key bindings)
with no pre or post handling required around the signal emission.
also, by convention, functions named bar_frobnicate() should just
trigger a signal emission of Bar:frobnicate if there is such a signal
(and may not contain pre/post emission stuff if the signal in question is
a RUN_ACTION one). one reason for that convention is for instance
that people can rely on their signal handlers getting called if they
connect to Bar::frobnicate and call bar_frobnicate().

static void
gtk_window_real_activate_default (GtkWindow *window)
{
  gtk_window_activate_default (window);
}

gboolean
gtk_window_activate_default (GtkWindow *window)
{
  g_return_val_if_fail (window != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);

  if (window->default_widget && GTK_WIDGET_IS_SENSITIVE (window->default_widget) &&
      (!window->focus_widget || !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget)))
    {
      gtk_widget_activate (window->default_widget);
      return TRUE;
    }
  else if (window->focus_widget)
    {
      if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
        gtk_widget_activate (window->focus_widget);
      return TRUE;
    }

  return FALSE;
}

so the checks currently being done in gtk_window_activate_default()
have to be moved into gtk_window_real_activate_default(), and
gtk_window_activate_default() should do _nothing_ else than ref/emit/unref
GtkWidget::activate_default since it is a RUN_ACTION signal.
the same applies to gtk_window_activate_focus().
also, it's probably _not_ a good idea to activate the focus
widget from gtk_window_activate_default() since legacy code
can rely on this only activating the default widget.

for GtkEntry, there shouldn't be a gtk_entry_real_activate()
implementation at all, instead, whether Return/Enter on an entry
should activate the entry, or call gtk_window_activate_default()
instead, needs to be determined before the signal is being emitted.
that is, entry->activates_default should indicate whether Return/
Enter on an entry trigegrs entry activation or a window's default
widget activation, not what extra actions occour once ::activate
is emitted on the entry which is a GTK_RUN_ACTION signal
btw, so might be called from anywhere any time.

---
ciaoTJ





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