Refining the concept of focus
- From: Owen Taylor <otaylor redhat com>
- To: gtk-devel-list gnome org
- Subject: Refining the concept of focus
- Date: Tue, 21 May 2002 18:29:12 -0400 (EDT)
To fully implement the XEMBED spec, some refinement of how GTK+ deals with focus
was necessary.
The following patch adds three properties:
GtkWidget::is_focus - is this focus the focus widget within it's (in-process) GtkWindow
GtkWindow::is_active - is the (possibly out-of-process) toplevel of the window the X focus
GtkWIndow::has_toplevel_focus - does this toplevel window contain the focus widget
+----------- GtkWindow (A)--------------+
| |
| GtkPlug (B)------+ GtkPlug-(D)------+ |
| | GtkEntry (C)-+ | | GtkEntry (E)-+ | |
| | | | | | |[focus here] | | |
| | +------------+ | | +------------+ | |
| +----------------+ +----------------+ |
+---------------------------------------+
So, in a situation like the above, we might have
is_focus set on C and E
is_active set on A, B, and D
has_toplevel_focus set on A and E
is_focus is quite useful independent of embedding
is_active is relatively useful independent of embedding ... the most important
use would be a theme that wanted to draw active widgets differently.
has_toplevel_focus is really an internal implementation detail.
I've made is_active and has_toplevel_focus read-only with private settors,
because
- The setters just reflect state changes, and have no meaning to an app
- Making properties read-only will reduce the chance
of people trying to use them to change the focused window. (And will keep them
from appearing in GUI-builders.)
GtkWidget::has-focus really should be read-only with GtkWidget::is-focus
being the only read-write property, but making that change at this point
isn't possible.
Regards,
Owen
Index: gtk/gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.319
diff -u -p -r1.319 gtkwidget.c
--- gtk/gtkwidget.c 13 May 2002 22:35:42 -0000 1.319
+++ gtk/gtkwidget.c 21 May 2002 21:58:43 -0000
@@ -131,6 +131,7 @@ enum {
PROP_APP_PAINTABLE,
PROP_CAN_FOCUS,
PROP_HAS_FOCUS,
+ PROP_IS_FOCUS,
PROP_CAN_DEFAULT,
PROP_HAS_DEFAULT,
PROP_RECEIVES_DEFAULT,
@@ -454,6 +455,13 @@ gtk_widget_class_init (GtkWidgetClass *k
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
+ PROP_HAS_FOCUS,
+ g_param_spec_boolean ("is_focus",
+ _("Is focus"),
+ _("Whether the widget is the focus widget within the toplevel"),
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class,
PROP_CAN_DEFAULT,
g_param_spec_boolean ("can_default",
_("Can default"),
@@ -1142,6 +1150,10 @@ gtk_widget_set_property (GObject
if (g_value_get_boolean (value))
gtk_widget_grab_focus (widget);
break;
+ case PROP_IS_FOCUS:
+ if (g_value_get_boolean (value))
+ gtk_widget_grab_focus (widget);
+ break;
case PROP_CAN_DEFAULT:
saved_flags = GTK_WIDGET_FLAGS (widget);
if (g_value_get_boolean (value))
@@ -1229,6 +1241,9 @@ gtk_widget_get_property (GObject
break;
case PROP_HAS_FOCUS:
g_value_set_boolean (value, (GTK_WIDGET_HAS_FOCUS (widget) != FALSE));
+ break;
+ case PROP_IS_FOCUS:
+ g_value_set_boolean (value, (gtk_widget_is_focus (widget)));
break;
case PROP_CAN_DEFAULT:
g_value_set_boolean (value, (GTK_WIDGET_CAN_DEFAULT (widget) != FALSE));
Index: gtk/gtkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.c,v
retrieving revision 1.208
diff -u -p -r1.208 gtkwindow.c
--- gtk/gtkwindow.c 16 May 2002 23:59:23 -0000 1.208
+++ gtk/gtkwindow.c 21 May 2002 21:58:43 -0000
@@ -70,6 +70,10 @@ enum {
PROP_DESTROY_WITH_PARENT,
PROP_ICON,
PROP_SCREEN,
+
+ /* Readonly properties */
+ PROP_IS_ACTIVE,
+ PROP_HAS_TOPLEVEL_FOCUS,
LAST_ARG
};
@@ -504,6 +508,22 @@ gtk_window_class_init (GtkWindowClass *k
GDK_TYPE_SCREEN,
G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class,
+ PROP_IS_ACTIVE,
+ g_param_spec_boolean ("is_active",
+ _("Is Active"),
+ _("Whether the toplevel is the current active window"),
+ FALSE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_HAS_TOPLEVEL_FOCUS,
+ g_param_spec_boolean ("has_toplevel_focus",
+ _("Focus in Toplevel"),
+ _("Whether the input focus is within this GtkWindow"),
+ FALSE,
+ G_PARAM_READABLE));
+
window_signals[SET_FOCUS] =
g_signal_new ("set_focus",
G_TYPE_FROM_CLASS (object_class),
@@ -770,6 +790,12 @@ gtk_window_get_property (GObject *o
case PROP_SCREEN:
g_value_set_object (value, window->screen);
break;
+ case PROP_IS_ACTIVE:
+ g_value_set_boolean (value, window->is_active);
+ break;
+ case PROP_HAS_TOPLEVEL_FOCUS:
+ g_value_set_boolean (value, window->has_toplevel_focus);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -3766,14 +3792,10 @@ gtk_window_focus_in_event (GtkWidget
*/
if (GTK_WIDGET_VISIBLE (widget))
{
- window->has_focus = TRUE;
-
- if (window->focus_widget &&
- window->focus_widget != widget &&
- !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
- do_focus_change (window->focus_widget, TRUE);
+ _gtk_window_set_has_toplevel_focus (window, TRUE);
+ _gtk_window_set_is_active (window, TRUE);
}
-
+
return FALSE;
}
@@ -3783,12 +3805,8 @@ gtk_window_focus_out_event (GtkWidget
{
GtkWindow *window = GTK_WINDOW (widget);
- window->has_focus = FALSE;
-
- if (window->focus_widget &&
- window->focus_widget != widget &&
- GTK_WIDGET_HAS_FOCUS (window->focus_widget))
- do_focus_change (window->focus_widget, FALSE);
+ _gtk_window_set_has_toplevel_focus (window, FALSE);
+ _gtk_window_set_is_active (window, FALSE);
return FALSE;
}
@@ -3928,6 +3946,8 @@ gtk_window_real_set_focus (GtkWindow *wi
if (window->has_focus)
do_focus_change (window->focus_widget, FALSE);
+
+ g_object_notify (G_OBJECT (window->focus_widget), "is_focus");
}
window->focus_widget = focus;
@@ -3946,6 +3966,8 @@ gtk_window_real_set_focus (GtkWindow *wi
if (window->has_focus)
do_focus_change (window->focus_widget, TRUE);
+
+ g_object_notify (G_OBJECT (window->focus_widget), "is_focus");
}
if (window->default_widget &&
@@ -6077,4 +6099,82 @@ _gtk_window_activate_key (GtkWindow *w
}
else
return FALSE;
+}
+
+static void
+window_update_has_focus (GtkWindow *window)
+{
+ GtkWidget *widget = GTK_WIDGET (window);
+ gboolean has_focus = window->has_toplevel_focus && window->is_active;
+
+ if (has_focus != window->has_focus)
+ {
+ window->has_focus = has_focus;
+
+ if (has_focus)
+ {
+ if (window->focus_widget &&
+ window->focus_widget != widget &&
+ !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
+ do_focus_change (window->focus_widget, TRUE);
+ }
+ else
+ {
+ if (window->focus_widget &&
+ window->focus_widget != widget &&
+ GTK_WIDGET_HAS_FOCUS (window->focus_widget))
+ do_focus_change (window->focus_widget, FALSE);
+ }
+ }
+}
+
+/**
+ * _gtk_window_set_is_active:
+ * @window: a #GtkWindow
+ * @is_active: %TRUE if the window is in the currently active toplevel
+ *
+ * Internal function that sets whether the #GtkWindow is part
+ * of the currently active toplevel window (taking into account inter-process
+ * embedding.)
+ **/
+void
+_gtk_window_set_is_active (GtkWindow *window,
+ gboolean is_active)
+{
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ is_active = is_active != FALSE;
+
+ if (is_active != window->is_active)
+ {
+ window->is_active = is_active;
+ window_update_has_focus (window);
+
+ g_object_notify (G_OBJECT (window), "is_active");
+ }
+}
+
+/**
+ * _gtk_window_set_has_toplevel_focus:
+ * @window: a #GtkWindow
+ * @has_toplevel_focus: %TRUE if the in
+ *
+ * Internal function that sets whether the keyboard focus for the
+ * toplevel window (taking into account inter-process embedding.)
+ **/
+void
+_gtk_window_set_has_toplevel_focus (GtkWindow *window,
+ gboolean has_toplevel_focus)
+{
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ has_toplevel_focus = has_toplevel_focus != FALSE;
+
+ if (has_toplevel_focus != window->has_toplevel_focus)
+ {
+ window->has_toplevel_focus = has_toplevel_focus;
+ window_update_has_focus (window);
+
+ g_object_notify (G_OBJECT (window), "has_toplevel_focus");
+ }
}
Index: gtk/gtkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.h,v
retrieving revision 1.62
diff -u -p -r1.62 gtkwindow.h
--- gtk/gtkwindow.h 29 Apr 2002 22:53:45 -0000 1.62
+++ gtk/gtkwindow.h 21 May 2002 21:58:43 -0000
@@ -98,7 +98,10 @@ struct _GtkWindow
guint decorated : 1;
guint type_hint : 3; /* GdkWindowTypeHint */
- guint gravity : 5; /* GdkGravity */
+ guint gravity : 5; /* GdkGravity */
+
+ guint is_active : 1;
+ guint has_toplevel_focus : 1;
guint frame_left;
guint frame_top;
@@ -343,6 +346,11 @@ void _gtk_window_constrain_si
GtkWindowGroup *_gtk_window_get_group (GtkWindow *window);
gboolean _gtk_window_activate_key (GtkWindow *window,
GdkEventKey *event);
+
+void _gtk_window_set_has_toplevel_focus (GtkWindow *window,
+ gboolean has_toplevel_focus);
+void _gtk_window_set_is_active (GtkWindow *window,
+ gboolean is_active);
typedef void (*GtkWindowKeysForeachFunc) (GtkWindow *window,
guint keyval,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]