[gdl] Add focus handling functionality to GdlDockItem.
- From: Johannes Schmid <jhs src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gdl] Add focus handling functionality to GdlDockItem.
- Date: Sun, 26 Feb 2012 11:36:57 +0000 (UTC)
commit 2ac4a8f96d3c6061b3c7c74d250f6b731949f966
Author: Alex Valavanis <a valavanis leeds ac uk>
Date: Sun Jan 1 16:23:15 2012 +0000
Add focus handling functionality to GdlDockItem.
Dock items may now gain focus upon mouse click. The ::move-focus-child
signal has been added, along with arrow-key and tab bindings to signal
requests for the focus to be moved inside the child widget of the dock.
The public gdl_dock_item_or_child_has_focus method has been added to
test whether a dock, or its child currently has focus.
docs/reference/gdl-docs.sgml | 1 -
docs/reference/gdl-sections.txt | 2 +
gdl/gdl-dock-item.c | 140 +++++++++++++++++++++++++++++++++++++++
gdl/gdl-dock-item.h | 3 +
gdl/libgdlmarshal.list | 1 +
5 files changed, 146 insertions(+), 1 deletions(-)
---
diff --git a/docs/reference/gdl-docs.sgml b/docs/reference/gdl-docs.sgml
index d293108..68e9cc5 100644
--- a/docs/reference/gdl-docs.sgml
+++ b/docs/reference/gdl-docs.sgml
@@ -18,6 +18,5 @@
<xi:include href="xml/gdl-dock-object.xml" />
<xi:include href="xml/gdl-dock-bar.xml" />
<xi:include href="xml/gdl-dock-placeholder.xml" />
- <xi:include href="xml/gdl-tools.xml" />
</chapter>
</book>
diff --git a/docs/reference/gdl-sections.txt b/docs/reference/gdl-sections.txt
index 6a4bf59..c3fa373 100644
--- a/docs/reference/gdl-sections.txt
+++ b/docs/reference/gdl-sections.txt
@@ -85,6 +85,7 @@ gdl_dock_item_new_with_pixbuf_icon
gdl_dock_item_new_with_stock
gdl_dock_item_notify_deselected
gdl_dock_item_notify_selected
+gdl_dock_item_or_child_has_focus
gdl_dock_item_preferred_size
gdl_dock_item_set_default_position
gdl_dock_item_set_orientation
@@ -333,6 +334,7 @@ gdl_switcher_get_type
<FILE>libgdlmarshal</FILE>
gdl_marshal_VOID__BOOLEAN
gdl_marshal_VOID__BOXED
+gdl_marshal_VOID__ENUM
gdl_marshal_VOID__INT_INT
gdl_marshal_VOID__OBJECT_ENUM_BOXED
gdl_marshal_VOID__UINT_UINT
diff --git a/gdl/gdl-dock-item.c b/gdl/gdl-dock-item.c
index 189f781..4a299d2 100644
--- a/gdl/gdl-dock-item.c
+++ b/gdl/gdl-dock-item.c
@@ -86,12 +86,18 @@ static void gdl_dock_item_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural);
+static void gdl_dock_item_set_focus_child (GtkContainer *container,
+ GtkWidget *widget);
+
static void gdl_dock_item_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gdl_dock_item_map (GtkWidget *widget);
static void gdl_dock_item_unmap (GtkWidget *widget);
static void gdl_dock_item_realize (GtkWidget *widget);
+static void gdl_dock_item_move_focus_child (GdlDockItem *item,
+ GtkDirectionType dir);
+
static gint gdl_dock_item_button_changed (GtkWidget *widget,
GdkEventButton *event);
static gint gdl_dock_item_motion (GtkWidget *widget,
@@ -158,6 +164,7 @@ enum {
DOCK_DRAG_END,
SELECTED,
DESELECTED,
+ MOVE_FOCUS_CHILD,
LAST_SIGNAL
};
@@ -201,6 +208,40 @@ G_DEFINE_TYPE_WITH_CODE (GdlDockItem, gdl_dock_item, GDL_TYPE_DOCK_OBJECT,
g_type_add_class_private (g_define_type_id, sizeof (GdlDockItemClassPrivate)))
static void
+add_tab_bindings (GtkBindingSet *binding_set,
+ GdkModifierType modifiers,
+ GtkDirectionType direction)
+{
+ gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
+ "move_focus_child", 1,
+ GTK_TYPE_DIRECTION_TYPE, direction);
+ gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
+ "move_focus_child", 1,
+ GTK_TYPE_DIRECTION_TYPE, direction);
+}
+
+static void
+add_arrow_bindings (GtkBindingSet *binding_set,
+ guint keysym,
+ GtkDirectionType direction)
+{
+ guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
+
+ gtk_binding_entry_add_signal (binding_set, keysym, 0,
+ "move_focus_child", 1,
+ GTK_TYPE_DIRECTION_TYPE, direction);
+ gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
+ "move_focus_child", 1,
+ GTK_TYPE_DIRECTION_TYPE, direction);
+ gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
+ "move_focus_child", 1,
+ GTK_TYPE_DIRECTION_TYPE, direction);
+ gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
+ "move_focus_child", 1,
+ GTK_TYPE_DIRECTION_TYPE, direction);
+}
+
+static void
gdl_dock_item_class_init (GdlDockItemClass *klass)
{
GObjectClass *object_class;
@@ -211,6 +252,7 @@ gdl_dock_item_class_init (GdlDockItemClass *klass)
"* {\n"
"padding: 0;\n"
"}";
+ GtkBindingSet *binding_set;
object_class = G_OBJECT_CLASS (klass);
widget_class = GTK_WIDGET_CLASS (klass);
@@ -237,6 +279,7 @@ gdl_dock_item_class_init (GdlDockItemClass *klass)
container_class->remove = gdl_dock_item_remove;
container_class->forall = gdl_dock_item_forall;
container_class->child_type = gdl_dock_item_child_type;
+ container_class->set_focus_child = gdl_dock_item_set_focus_child;
gtk_container_class_handle_border_width (container_class);
dock_object_class->is_compound = FALSE;
@@ -248,6 +291,7 @@ gdl_dock_item_class_init (GdlDockItemClass *klass)
klass->dock_drag_begin = NULL;
klass->dock_drag_motion = NULL;
klass->dock_drag_end = NULL;
+ klass->move_focus_child = gdl_dock_item_move_focus_child;
klass->set_orientation = gdl_dock_item_real_set_orientation;
/* properties */
@@ -393,6 +437,30 @@ gdl_dock_item_class_init (GdlDockItemClass *klass)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
+
+ /**
+ * GdlDockItem::move-focus-child:
+ * @gdldockitem: The dock item in which a change of focus is requested
+ * @dir: The direction in which to move focus
+ *
+ * The ::move-focus-child signal is emitted when a change of focus is
+ * requested for the child widget of a dock item. The @dir parameter
+ * specifies the direction in which focus is to be shifted.
+ *
+ * Since: 3.3.2
+ */
+ gdl_dock_item_signals [MOVE_FOCUS_CHILD] =
+ g_signal_new ("move_focus_child",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GdlDockItemClass, move_focus_child),
+ NULL, /* accumulator */
+ NULL, /* accu_data */
+ gdl_marshal_VOID__ENUM,
+ G_TYPE_NONE,
+ 1,
+ GTK_TYPE_DIRECTION_TYPE);
+
/**
* GdlDockItem::deselected:
@@ -410,6 +478,20 @@ gdl_dock_item_class_init (GdlDockItemClass *klass)
G_TYPE_NONE,
0);
+ /* key bindings */
+
+ binding_set = gtk_binding_set_by_class (klass);
+
+ add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
+ add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
+ add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
+ add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
+
+ add_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
+ add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
+ add_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
+ add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
+
g_type_class_add_private (object_class, sizeof (GdlDockItemPrivate));
/* set the style */
@@ -427,6 +509,7 @@ gdl_dock_item_init (GdlDockItem *item)
GdlDockItemPrivate);
gtk_widget_set_has_window (GTK_WIDGET (item), TRUE);
+ gtk_widget_set_can_focus (GTK_WIDGET (item), TRUE);
item->child = NULL;
@@ -742,6 +825,19 @@ gdl_dock_item_child_type (GtkContainer *container)
}
static void
+gdl_dock_item_set_focus_child (GtkContainer *container,
+ GtkWidget *child)
+{
+ g_return_if_fail (GDL_IS_DOCK_ITEM (container));
+
+ if (GTK_CONTAINER_CLASS (gdl_dock_item_parent_class)->set_focus_child) {
+ (* GTK_CONTAINER_CLASS (gdl_dock_item_parent_class)->set_focus_child) (container, child);
+ }
+
+ gdl_dock_item_showhide_grip (GDL_DOCK_ITEM (container));
+}
+
+static void
gdl_dock_item_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural)
@@ -995,6 +1091,14 @@ gdl_dock_item_realize (GtkWidget *widget)
gtk_widget_set_parent_window (item->priv->grip, window);
}
+static void
+gdl_dock_item_move_focus_child (GdlDockItem *item,
+ GtkDirectionType dir)
+{
+ g_return_if_fail (GDL_IS_DOCK_ITEM (item));
+ gtk_widget_child_focus (GTK_WIDGET (item->child), dir);
+}
+
#define EVENT_IN_GRIP_EVENT_WINDOW(ev,gr) \
((gr) != NULL && (ev)->window == GDL_DOCK_ITEM_GRIP (gr)->title_window)
@@ -1042,6 +1146,10 @@ gdl_dock_item_button_changed (GtkWidget *widget,
/* Left mousebutton click on dockitem. */
if (!locked && event->button == 1 && event->type == GDK_BUTTON_PRESS) {
+
+ if (!gdl_dock_item_or_child_has_focus (item))
+ gtk_widget_grab_focus (GTK_WIDGET (item));
+
/* Set in_drag flag, grab pointer and call begin drag operation. */
if (in_handle) {
item->priv->start_x = event->x;
@@ -1062,6 +1170,7 @@ gdl_dock_item_button_changed (GtkWidget *widget,
if (GDL_DOCK_ITEM_IN_DRAG (item)) {
/* User dropped widget somewhere. */
gdl_dock_item_drag_end (item, FALSE);
+ gtk_widget_grab_focus (GTK_WIDGET (item));
event_handled = TRUE;
}
else if (GDL_DOCK_ITEM_IN_PREDRAG (item)) {
@@ -2273,6 +2382,37 @@ gdl_dock_item_preferred_size (GdlDockItem *item,
req->height = MAX (item->priv->preferred_height, allocation.height);
}
+/**
+ * gdl_dock_item_or_child_has_focus:
+ * @item: The dock item to be checked
+ *
+ * Checks whether a given #GdlDockItem or its child widget has focus.
+ * This check is performed recursively on child widgets.
+ *
+ * Returns: %TRUE if the dock item or its child widget has focus;
+ * %FALSE otherwise.
+ *
+ * Since: 3.3.2
+ */
+gboolean
+gdl_dock_item_or_child_has_focus (GdlDockItem *item)
+{
+ GtkWidget *item_child;
+ gboolean item_or_child_has_focus;
+
+ g_return_val_if_fail (GDL_IS_DOCK_ITEM (item), FALSE);
+
+ for (item_child = gtk_container_get_focus_child (GTK_CONTAINER (item));
+ item_child && GTK_IS_CONTAINER (item_child) && gtk_container_get_focus_child (GTK_CONTAINER (item_child));
+ item_child = gtk_container_get_focus_child (GTK_CONTAINER (item_child))) ;
+
+ item_or_child_has_focus =
+ (gtk_widget_has_focus (GTK_WIDGET (item)) ||
+ (GTK_IS_WIDGET (item_child) && gtk_widget_has_focus (item_child)));
+
+ return item_or_child_has_focus;
+}
+
/* ----- gtk orientation type exporter/importer ----- */
diff --git a/gdl/gdl-dock-item.h b/gdl/gdl-dock-item.h
index 33ad7e9..e48f657 100644
--- a/gdl/gdl-dock-item.h
+++ b/gdl/gdl-dock-item.h
@@ -130,6 +130,8 @@ struct _GdlDockItemClass {
gint y);
void (* dock_drag_end) (GdlDockItem *item,
gboolean cancelled);
+ void (* move_focus_child) (GdlDockItem *item,
+ GtkDirectionType direction);
void (* set_orientation) (GdlDockItem *item,
GtkOrientation orientation);
};
@@ -218,6 +220,7 @@ void gdl_dock_item_set_default_position (GdlDockItem *item,
void gdl_dock_item_preferred_size (GdlDockItem *item,
GtkRequisition *req);
+gboolean gdl_dock_item_or_child_has_focus (GdlDockItem *item);
G_END_DECLS
diff --git a/gdl/libgdlmarshal.list b/gdl/libgdlmarshal.list
index f3200d6..750989a 100644
--- a/gdl/libgdlmarshal.list
+++ b/gdl/libgdlmarshal.list
@@ -1,4 +1,5 @@
VOID:VOID
+VOID:ENUM
VOID:INT,INT
VOID:UINT,UINT
VOID:BOOLEAN
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]