Re: GtkWidgets validation
- From: Santiago Capel <bluefish ono com>
- To: gtk-devel-list gnome org
- Subject: Re: GtkWidgets validation
- Date: Tue, 01 Jan 2002 16:40:23 +0100
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]