Re: GtkWidgets validation



Hello all again and happy new year:

I have attached a patch to implement validation to gtk+-1.2.10 and solve
the following feature request:

http://bugzilla.gnome.org/show_bug.cgi?id=50276

To apply the patch, make:

cd gtk+-1.2.10/gtk
patch -p0 < patch_gtk+-1.2.10-with-validation

and then make the project.

Once made, you can run the program testgtk and choose the entry button.
Then set the focus to the first entry widget and try to exit with TAB (or
another key) or the mouse. You won't be able to leave that entry widget
unless you type some text in it starting with 'a'

Otherwise, a dialog will appear and when you close it, the focus will
return to that 'invalid' widget.

Is this the preferred method to advice these kind of patchs, or shoud I use
the bugzilla engine?


Regards,
    Santiago Capel


Santiago Capel escribió:

> Hello all again:
>
> Here is an explanation of the code to implement validation of gtk
> widgets.
> This is just a little sample, but it works fine. It needs only a bit
> more of hacking and a bit of testing, but I think that this is a correct
> way (and low-cost) of getting to the validation of widgets.
>
> The main changes are in the gtkwidget module.
>
> I need to create two new flags lor the widgets. lets say
> GTK_IGNOREACTIVATE and GTK_CAUSESVALIDATION
>
> ** gtkwidget.h **
>
> typedef enum
> {
>   GTK_TOPLEVEL         = 1 << 4,
>     ...
>   GTK_RECEIVES_DEFAULT = 1 << 20
> #ifdef VALIDATE
>   , GTK_IGNOREACTIVATE = 1 << 21
>   , GTK_CAUSESVALIDATION = 1 << 22
> #endif
> } GtkWidgetFlags;
>
> // The flag GTK_CAUSESVALIDATION, when is set by the programmer on a
> widget that get the focus, causes the validate event of the widget that
> has just lost the focus to be emitted.
> // The flag GTK_IGNOREACTIVATE is set and unset internally by gtk. It is
> needed to avoid the emission of the activate event of a control in the
> middle of the validate event of another.
>
> ** gtkwidget.c **
>
> enum {
>   SHOW,
>   HIDE,
>     ...
>   VISIBILITY_NOTIFY_EVENT,
>   DEBUG_MSG,
> #ifdef VALIDATE
>   VALIDATE_EVENT,
> #endif
>   LAST_SIGNAL
> };
>
> // Added a new event to all the widgets. The validate event, which will
> be called when the widget loses the focus and the
> widget that gets the focus has the CAUSESVALIDATION flag set.
>
> static void
> gtk_widget_class_init (GtkWidgetClass *klass)
> {
>   GtkObjectClass *object_class;
>
>     .....
> #ifdef VALIDATE
>   widget_signals[VALIDATE_EVENT] =
>     gtk_signal_new ("validate_event",
>       GTK_RUN_LAST,
>       object_class->type,
>       GTK_SIGNAL_OFFSET (GtkWidgetClass, validate_event),
>       gtk_marshal_BOOL__POINTER,
>       GTK_TYPE_BOOL, 1,
>       GTK_TYPE_GDK_EVENT);
> #endif
>
> //                This is the initialization of the event callback.
>
> #ifdef VALIDATE
>   klass->validate_event = NULL;
> #endif
>   klass->focus_in_event = NULL;
>
> //                For analogy with focus_in_event
> }
>
> // This function makes all of this work!
>
> static void
> gtk_widget_real_grab_focus (GtkWidget *focus_widget)
> {
>   g_return_if_fail (focus_widget != NULL);
>   g_return_if_fail (GTK_IS_WIDGET (focus_widget));
>
>   if (GTK_WIDGET_CAN_FOCUS (focus_widget))
>     {
>       GtkWidget *toplevel;
>       GtkWidget *widget;
>
>       /* clear the current focus setting, break if the current widget
>        * is the focus widget's parent, since containers above that will
>        * be set by the next loop.
>        */
>       toplevel = gtk_widget_get_toplevel (focus_widget);
>       if (GTK_IS_WINDOW (toplevel))
>  {
>    widget = GTK_WINDOW (toplevel)->focus_widget;
>
>    if (widget == focus_widget)
>      {
>        /* We call gtk_window_set_focus() here so that the
>         * toplevel window can request the focus if necessary.
>         * This is needed when the toplevel is a GtkPlug
>         */
>        if (!GTK_WIDGET_HAS_FOCUS (widget))
>               gtk_window_set_focus (GTK_WINDOW (toplevel),
> focus_widget);
>        return;
>      }
>
> #ifdef VALIDATE
>
>    /* Check if the widget that get the focus causes validation */
>     if( GTK_WIDGET_CAUSES_VALIDATION(focus_widget) ) {
>
>         /* Check if the there exists a previously focused widget  */
>        if( widget ) {
>
>         /* Start of the validation process */
>         /* Initialize the return value of the validate event to TRUE,
> Just in case there is no validate event handler for this widget */
>              int validate_return_val = TRUE, foo=9876543210;
>
>              gtk_signal_emit (GTK_OBJECT (widget),
> widget_signals[VALIDATE_EVENT],
>                     &validate_return_val, &foo); /* I don't really know
> what is the fourth parameter for */
>
>              /* See the return value of the validation */
>              if( validate_return_val == FALSE ) { /* The widget is
> invalid */
>
>                     /* Ignore the activate event of the focus that
> wanted to get the focus, as it had never had to get the focus */
>                    GTK_WIDGET_SET_FLAGS(focus_widget,
> GTK_IGNOREACTIVATE);
>                    return; /* don't set the focus to the required widget
> */
>
>              } else {  /* The widget is valid */
>                     /* Unset the IGNOREACTIVATE flag, as now the widget
> is allowed to get the focus */
>                    GTK_WIDGET_UNSET_FLAGS(focus_widget,
> GTK_IGNOREACTIVATE);
>              }
>        }
>
> #endif
>
>     /* The rest of the function doesn't change  */
>
> ** gtkbutton.c **
>
> void
> gtk_button_clicked (GtkButton *button)
> {
>   g_return_if_fail (button != NULL);
>   g_return_if_fail (GTK_IS_BUTTON (button));
>
> #ifdef VALIDATE
>   if( !GTK_WIDGET_IGNOREACTIVATE(GTK_WIDGET(button)) )
> #endif
>     gtk_signal_emit (GTK_OBJECT (button), button_signals[CLICKED]);
> }
>
> Don't emit the activate window while other widget is validating and the
> validation has been unsuccessful.
> This must be done for other widgets that can be focused and activated
> with just one mouse click.
>
> The testgtk program just add a validate event handler to the entry
> widget:
>
> #ifdef VALIDATE
>
> static void
> on_entry_validate_event (GtkEntry *entry,
>     gint *result,
>     gpointer data)
> {
>   if( *gtk_entry_get_text(entry) != 'a') {
>     create_dialog();
>     *result = FALSE;
>   }
> }
>
> #endif
>
> static void
> create_entry (void)
> {
>
>     ....
>
> #ifdef VALIDATE
>   gtk_signal_connect (GTK_OBJECT (entry), "validate_event",
>                       GTK_SIGNAL_FUNC (on_entry_validate_event),
>                       (gpointer)NULL);
> #endif
>
> Regards,
>     Santiago Capel
>
> _______________________________________________
> gtk-devel-list mailing list
> gtk-devel-list gnome org
> http://mail.gnome.org/mailman/listinfo/gtk-devel-list




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