Re: GtkWidgets validation



Sorry, here is the patch


Santiago Capel escribió:

> 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
>
> _______________________________________________
> gtk-devel-list mailing list
> gtk-devel-list gnome org
> http://mail.gnome.org/mailman/listinfo/gtk-devel-list
--- gtkbutton.c	Mon Feb 12 21:36:37 2001
+++ gtk+-1.2.10-with-validation/gtk/gtkbutton.c	Wed Dec 19 01:35:49 2001
@@ -333,7 +333,10 @@
   g_return_if_fail (button != NULL);
   g_return_if_fail (GTK_IS_BUTTON (button));
 
-  gtk_signal_emit (GTK_OBJECT (button), button_signals[CLICKED]);
+#ifdef VALIDATE
+  if( !GTK_WIDGET_IGNOREACTIVATE(GTK_WIDGET(button)) )
+#endif
+    gtk_signal_emit (GTK_OBJECT (button), button_signals[CLICKED]);
 }
 
 void

--- gtkcombo.c	Thu Mar 15 19:41:40 2001
+++ gtk+-1.2.10-with-validation/gtk/gtkcombo.c	Tue Dec 18 12:03:44 2001
@@ -480,6 +480,10 @@
 gtk_combo_update_entry (GtkList * list, GtkCombo * combo)
 {
   char *text;
+#ifdef VALIDATE
+  if( GTK_WIDGET_IGNOREACTIVATE(GTK_WIDGET(combo->entry)) )
+    return;
+#endif
 
   gtk_grab_remove (GTK_WIDGET (combo));
   gtk_signal_handler_block (GTK_OBJECT (list), combo->list_change_id);

--- gtkwidget.c	Thu Mar  1 10:35:50 2001
+++ gtk+-1.2.10-with-validation/gtk/gtkwidget.c	Tue Jan  1 16:06:53 2002
@@ -97,6 +97,9 @@
   NO_EXPOSE_EVENT,
   VISIBILITY_NOTIFY_EVENT,
   DEBUG_MSG,
+#ifdef VALIDATE
+  VALIDATE_EVENT,
+#endif
   LAST_SIGNAL
 };
 
@@ -506,6 +509,18 @@
 		    gtk_marshal_BOOL__POINTER,
 		    GTK_TYPE_BOOL, 1,
 		    GTK_TYPE_GDK_EVENT);
+
+#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
+
   widget_signals[FOCUS_IN_EVENT] =
     gtk_signal_new ("focus_in_event",
 		    GTK_RUN_LAST,
@@ -760,6 +775,9 @@
   klass->enter_notify_event = NULL;
   klass->leave_notify_event = NULL;
   klass->configure_event = NULL;
+#ifdef VALIDATE
+  klass->validate_event = NULL;
+#endif
   klass->focus_in_event = NULL;
   klass->focus_out_event = NULL;
   klass->map_event = NULL;
@@ -1017,10 +1035,18 @@
   widget->window = NULL;
   widget->parent = NULL;
 
+#ifdef VALIDATE
+  GTK_WIDGET_SET_FLAGS (widget,
+			GTK_SENSITIVE |
+			GTK_PARENT_SENSITIVE |
+			GTK_CAUSESVALIDATION |
+			(composite_child_stack ? GTK_COMPOSITE_CHILD : 0));
+#else
   GTK_WIDGET_SET_FLAGS (widget,
 			GTK_SENSITIVE |
 			GTK_PARENT_SENSITIVE |
 			(composite_child_stack ? GTK_COMPOSITE_CHILD : 0));
+#endif
 
   widget->style = gtk_widget_peek_style ();
   gtk_style_ref (widget->style);
@@ -3119,11 +3145,41 @@
 	       * toplevel window can request the focus if necessary.
 	       * This is needed when the toplevel is a GtkPlug
 	       */
+#ifdef VALIDATE
+    	      GTK_WIDGET_UNSET_FLAGS(focus_widget, GTK_IGNOREACTIVATE); 
+#endif
 	      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_CAUSESVALIDATION(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=4321;
+	      /* I don't really know what is the fourth parameter for */ 
+	      gtk_signal_emit (GTK_OBJECT (widget), widget_signals[VALIDATE_EVENT], 
+			       &validate_return_val, &foo); 
+	      /* Look at the return value of the validation */ 
+	      if( validate_return_val == FALSE ) {
+		/* Ignore the activate event of the focus that 
+		   wanted to get the focus, as it must not get the focus */ 
+		GTK_WIDGET_SET_FLAGS(focus_widget, GTK_IGNOREACTIVATE);
+		/* don't set the focus to the required widget, but to the old one */
+		focus_widget = 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
 	  
 	  if (widget)
 	    {

--- gtkwidget.h	Thu Nov 30 02:59:10 2000
+++ gtk+-1.2.10-with-validation/gtk/gtkwidget.h	Wed Dec 19 01:11:15 2001
@@ -34,6 +34,8 @@
 #include <gtk/gtkstyle.h>
 
 
+#define VALIDATE 1
+
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
@@ -71,6 +73,10 @@
   /* the widget when focused will receive the default action and have
    * HAS_DEFAULT set even if there is a different widget set as default */
   GTK_RECEIVES_DEFAULT = 1 << 20
+#ifdef VALIDATE
+  , GTK_IGNOREACTIVATE = 1 << 21
+  , GTK_CAUSESVALIDATION = 1 << 22
+#endif
 } GtkWidgetFlags;
 
 /* Macro for casting a pointer to a GtkWidget or GtkWidgetClass pointer.
@@ -110,6 +116,11 @@
 #define GTK_WIDGET_COMPOSITE_CHILD(wid)	  ((GTK_WIDGET_FLAGS (wid) & GTK_COMPOSITE_CHILD) != 0)
 #define GTK_WIDGET_APP_PAINTABLE(wid)	  ((GTK_WIDGET_FLAGS (wid) & GTK_APP_PAINTABLE) != 0)
 #define GTK_WIDGET_RECEIVES_DEFAULT(wid)  ((GTK_WIDGET_FLAGS (wid) & GTK_RECEIVES_DEFAULT) != 0)
+
+#ifdef VALIDATE
+#define GTK_WIDGET_CAUSESVALIDATION(wid)  ((GTK_WIDGET_FLAGS (wid) & GTK_CAUSESVALIDATION) != 0)
+#define GTK_WIDGET_IGNOREACTIVATE(wid)  ((GTK_WIDGET_FLAGS (wid) & GTK_IGNOREACTIVATE) != 0)
+#endif
   
 /* Macros for setting and clearing widget flags.
  */
@@ -324,6 +335,10 @@
 				    GdkEventCrossing   *event);
   gint (* configure_event)	   (GtkWidget	       *widget,
 				    GdkEventConfigure  *event);
+#ifdef VALIDATE
+  gint (* validate_event)	   (GtkWidget	       *widget,
+				    GdkEventFocus      *event);
+#endif
   gint (* focus_in_event)	   (GtkWidget	       *widget,
 				    GdkEventFocus      *event);
   gint (* focus_out_event)	   (GtkWidget	       *widget,

--- testgtk.c	Mon Feb 26 21:18:44 2001
+++ gtk+-1.2.10-with-validation/gtk/testgtk.c	Wed Dec 19 00:43:48 2001
@@ -2776,6 +2776,40 @@
 			 GTK_TOGGLE_BUTTON(checkbutton)->active);
 }
 
+#ifdef VALIDATE
+
+static void
+on_entry_validate_event (GtkEntry *entry,
+			 gint *result,
+			 gpointer data)
+{
+  g_print("on_entry_validate_event: result=%d, data=%p\n", *result, data);
+  if( *gtk_entry_get_text(entry) != 'a') {
+    create_dialog();
+    *result = FALSE;
+  }
+}
+
+static void
+on_editable_check_validate_event (GtkWidget *checkbutton,
+				  gint *result,
+				  gpointer user_data)
+{
+  g_warning("on_editable_check_validate_event\n");
+  *result = 1;
+}
+
+static void
+on_cb_validate_event (GtkWidget *checkbutton,
+		      gint *result,
+		      gpointer user_data)
+{
+  g_warning("on_cb_validate_event\n");
+  *result = 1;
+}
+
+#endif
+
 static void
 create_entry (void)
 {
@@ -2876,6 +2910,19 @@
       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
       gtk_widget_grab_default (button);
       gtk_widget_show (button);
+
+#ifdef VALIDATE
+  gtk_signal_connect (GTK_OBJECT (entry), "validate_event",
+                      GTK_SIGNAL_FUNC (on_entry_validate_event),
+                      (gpointer)0x1234);
+  gtk_signal_connect (GTK_OBJECT (cb), "validate_event",
+                      GTK_SIGNAL_FUNC (on_cb_validate_event),
+                      NULL);
+  gtk_signal_connect (GTK_OBJECT (editable_check), "validate_event",
+                      GTK_SIGNAL_FUNC (on_editable_check_validate_event),
+                      NULL);
+#endif
+
     }
 
   if (!GTK_WIDGET_VISIBLE (window))







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