From 2a0d28d8362038ea37c9ed50a4e30a763529835a Mon Sep 17 00:00:00 2001 From: gustav_b Date: Sun, 16 Sep 2007 15:30:50 +0000 Subject: [PATCH] Add handling of focus tabbing for GdlDockItem + various DockItem focus fixes. --- src/libgdl/gdl-dock-item-grip.c | 11 +-- src/libgdl/gdl-dock-item.c | 120 ++++++++++++++++++++++++++++++++ src/libgdl/gdl-dock-item.h | 20 +++--- src/libgdl/libgdlmarshal.c | 13 ++-- src/libgdl/libgdlmarshal.h | 13 ++-- src/libgdl/libgdlmarshal.list | 1 + src/ui/widget/dock-item.cpp | 13 +++- 7 files changed, 166 insertions(+), 25 deletions(-) diff --git a/src/libgdl/gdl-dock-item-grip.c b/src/libgdl/gdl-dock-item-grip.c index d1ba2372c..86e7bc14c 100644 --- a/src/libgdl/gdl-dock-item-grip.c +++ b/src/libgdl/gdl-dock-item-grip.c @@ -135,14 +135,17 @@ gdl_dock_item_grip_expose (GtkWidget *widget, gint layout_height; gint text_x; gint text_y; + gboolean item_or_child_has_focus; grip = GDL_DOCK_ITEM_GRIP (widget); gdl_dock_item_grip_get_title_area (grip, &title_area); - /* draw background, highlight it if the dock item has focus */ - bg_style = (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (grip->item)) ? - gtk_widget_get_style (widget)->mid_gc[widget->state] : - gtk_widget_get_style (widget)->dark_gc[widget->state]); + /* draw background, highlight it if the dock item or any of its + * descendants have focus */ + bg_style = (gdl_dock_item_or_child_has_focus (grip->item) ? + gtk_widget_get_style (widget)->dark_gc[widget->state] : + gtk_widget_get_style (widget)->mid_gc[widget->state]); + gdk_draw_rectangle (GDK_DRAWABLE (widget->window), bg_style, TRUE, 1, 0, widget->allocation.width - 1, widget->allocation.height); diff --git a/src/libgdl/gdl-dock-item.c b/src/libgdl/gdl-dock-item.c index 87fbb41a0..3be8dd3e2 100644 --- a/src/libgdl/gdl-dock-item.c +++ b/src/libgdl/gdl-dock-item.c @@ -81,6 +81,10 @@ static void gdl_dock_item_forall (GtkContainer *container, gpointer callback_data); static GtkType gdl_dock_item_child_type (GtkContainer *container); +static void gdl_dock_item_set_focus_child (GtkContainer *container, + GtkWidget *widget, + gpointer callback_data); + static void gdl_dock_item_size_request (GtkWidget *widget, GtkRequisition *requisition); static void gdl_dock_item_size_allocate (GtkWidget *widget, @@ -93,6 +97,9 @@ static void gdl_dock_item_style_set (GtkWidget *widget, static gint gdl_dock_item_expose (GtkWidget *widget, GdkEventExpose *event); +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, @@ -157,6 +164,7 @@ enum { DOCK_DRAG_BEGIN, DOCK_DRAG_MOTION, DOCK_DRAG_END, + MOVE_FOCUS_CHILD, LAST_SIGNAL }; @@ -191,6 +199,40 @@ struct _GdlDockItemPrivate { GDL_CLASS_BOILERPLATE (GdlDockItem, gdl_dock_item, GdlDockObject, GDL_TYPE_DOCK_OBJECT); +static void +add_tab_bindings (GtkBindingSet *binding_set, + GdkModifierType modifiers, + GtkDirectionType direction) +{ + gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers, + "move_focus_child", 1, + GTK_TYPE_DIRECTION_TYPE, direction); + gtk_binding_entry_add_signal (binding_set, GDK_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_Left + GDK_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) { @@ -201,6 +243,7 @@ gdl_dock_item_class_init (GdlDockItemClass *klass) GtkWidgetClass *widget_class; GtkContainerClass *container_class; GdlDockObjectClass *object_class; + GtkBindingSet *binding_set; g_object_class = G_OBJECT_CLASS (klass); gtk_object_class = GTK_OBJECT_CLASS (klass); @@ -230,6 +273,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; object_class->is_compound = FALSE; @@ -332,10 +376,38 @@ gdl_dock_item_class_init (GdlDockItemClass *klass) 1, G_TYPE_BOOLEAN); + 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); + + + /* key bindings */ + + binding_set = gtk_binding_set_by_class (klass); + + add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP); + add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN); + add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT); + add_arrow_bindings (binding_set, GDK_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); + klass->has_grip = TRUE; 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; if (!style_initialized) @@ -623,6 +695,19 @@ gdl_dock_item_child_type (GtkContainer *container) return G_TYPE_NONE; } +static void +gdl_dock_item_set_focus_child (GtkContainer *container, + GtkWidget *child, + gpointer callback_data) +{ + g_return_if_fail (GDL_IS_DOCK_ITEM (container)); + + if (GTK_CONTAINER_CLASS (parent_class)->set_focus_child) + (* GTK_CONTAINER_CLASS (parent_class)->set_focus_child) (container, child); + + gdl_dock_item_showhide_grip (GDL_DOCK_ITEM (container)); +} + static void gdl_dock_item_size_request (GtkWidget *widget, GtkRequisition *requisition) @@ -879,6 +964,14 @@ gdl_dock_item_expose (GtkWidget *widget, return FALSE; } +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) @@ -923,6 +1016,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; @@ -943,6 +1040,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)) { @@ -1348,6 +1446,8 @@ gdl_dock_item_dock (GdlDockObject *object, gdl_dock_object_thaw (new_parent); if (parent) gdl_dock_object_thaw (parent); + + } static void @@ -1917,6 +2017,26 @@ gdl_dock_item_preferred_size (GdlDockItem *item, } +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 (item)->focus_child; + item_child && GTK_IS_CONTAINER (item_child) && GTK_CONTAINER (item_child)->focus_child; + item_child = GTK_CONTAINER (item_child)->focus_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 ----- */ static void diff --git a/src/libgdl/gdl-dock-item.h b/src/libgdl/gdl-dock-item.h index 6eec28aeb..17484ad04 100644 --- a/src/libgdl/gdl-dock-item.h +++ b/src/libgdl/gdl-dock-item.h @@ -93,15 +93,17 @@ struct _GdlDockItemClass { gboolean has_grip; /* virtuals */ - void (* dock_drag_begin) (GdlDockItem *item); - void (* dock_drag_motion) (GdlDockItem *item, - gint x, - gint y); - void (* dock_drag_end) (GdlDockItem *item, - gboolean cancelled); + void (* dock_drag_begin) (GdlDockItem *item); + void (* dock_drag_motion) (GdlDockItem *item, + gint x, + 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); + void (* set_orientation) (GdlDockItem *item, + GtkOrientation orientation); }; /* additional macros */ @@ -186,6 +188,8 @@ 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 #endif diff --git a/src/libgdl/libgdlmarshal.c b/src/libgdl/libgdlmarshal.c index 06a4e7596..764f6fed0 100644 --- a/src/libgdl/libgdlmarshal.c +++ b/src/libgdl/libgdlmarshal.c @@ -1,4 +1,3 @@ -#include "libgdlmarshal.h" #include @@ -50,7 +49,9 @@ /* VOID:VOID (./libgdlmarshal.list:1) */ -/* VOID:INT,INT (./libgdlmarshal.list:2) */ +/* VOID:ENUM (./libgdlmarshal.list:2) */ + +/* VOID:INT,INT (./libgdlmarshal.list:3) */ void gdl_marshal_VOID__INT_INT (GClosure *closure, GValue *return_value, @@ -87,7 +88,7 @@ gdl_marshal_VOID__INT_INT (GClosure *closure, data2); } -/* VOID:UINT,UINT (./libgdlmarshal.list:3) */ +/* VOID:UINT,UINT (./libgdlmarshal.list:4) */ void gdl_marshal_VOID__UINT_UINT (GClosure *closure, GValue *return_value, @@ -124,9 +125,9 @@ gdl_marshal_VOID__UINT_UINT (GClosure *closure, data2); } -/* VOID:BOOLEAN (./libgdlmarshal.list:4) */ +/* VOID:BOOLEAN (./libgdlmarshal.list:5) */ -/* VOID:OBJECT,ENUM,BOXED (./libgdlmarshal.list:5) */ +/* VOID:OBJECT,ENUM,BOXED (./libgdlmarshal.list:6) */ void gdl_marshal_VOID__OBJECT_ENUM_BOXED (GClosure *closure, GValue *return_value, @@ -165,5 +166,5 @@ gdl_marshal_VOID__OBJECT_ENUM_BOXED (GClosure *closure, data2); } -/* VOID:BOXED (./libgdlmarshal.list:6) */ +/* VOID:BOXED (./libgdlmarshal.list:7) */ diff --git a/src/libgdl/libgdlmarshal.h b/src/libgdl/libgdlmarshal.h index 3e0116e1a..2d6bc800f 100644 --- a/src/libgdl/libgdlmarshal.h +++ b/src/libgdl/libgdlmarshal.h @@ -9,7 +9,10 @@ G_BEGIN_DECLS /* VOID:VOID (./libgdlmarshal.list:1) */ #define gdl_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID -/* VOID:INT,INT (./libgdlmarshal.list:2) */ +/* VOID:ENUM (./libgdlmarshal.list:2) */ +#define gdl_marshal_VOID__ENUM g_cclosure_marshal_VOID__ENUM + +/* VOID:INT,INT (./libgdlmarshal.list:3) */ extern void gdl_marshal_VOID__INT_INT (GClosure *closure, GValue *return_value, guint n_param_values, @@ -17,7 +20,7 @@ extern void gdl_marshal_VOID__INT_INT (GClosure *closure, gpointer invocation_hint, gpointer marshal_data); -/* VOID:UINT,UINT (./libgdlmarshal.list:3) */ +/* VOID:UINT,UINT (./libgdlmarshal.list:4) */ extern void gdl_marshal_VOID__UINT_UINT (GClosure *closure, GValue *return_value, guint n_param_values, @@ -25,10 +28,10 @@ extern void gdl_marshal_VOID__UINT_UINT (GClosure *closure, gpointer invocation_hint, gpointer marshal_data); -/* VOID:BOOLEAN (./libgdlmarshal.list:4) */ +/* VOID:BOOLEAN (./libgdlmarshal.list:5) */ #define gdl_marshal_VOID__BOOLEAN g_cclosure_marshal_VOID__BOOLEAN -/* VOID:OBJECT,ENUM,BOXED (./libgdlmarshal.list:5) */ +/* VOID:OBJECT,ENUM,BOXED (./libgdlmarshal.list:6) */ extern void gdl_marshal_VOID__OBJECT_ENUM_BOXED (GClosure *closure, GValue *return_value, guint n_param_values, @@ -36,7 +39,7 @@ extern void gdl_marshal_VOID__OBJECT_ENUM_BOXED (GClosure *closure, gpointer invocation_hint, gpointer marshal_data); -/* VOID:BOXED (./libgdlmarshal.list:6) */ +/* VOID:BOXED (./libgdlmarshal.list:7) */ #define gdl_marshal_VOID__BOXED g_cclosure_marshal_VOID__BOXED G_END_DECLS diff --git a/src/libgdl/libgdlmarshal.list b/src/libgdl/libgdlmarshal.list index f3200d6d2..750989abc 100644 --- a/src/libgdl/libgdlmarshal.list +++ b/src/libgdl/libgdlmarshal.list @@ -1,4 +1,5 @@ VOID:VOID +VOID:ENUM VOID:INT,INT VOID:UINT,UINT VOID:BOOLEAN diff --git a/src/ui/widget/dock-item.cpp b/src/ui/widget/dock-item.cpp index d615de1ff..372fe5d9d 100644 --- a/src/ui/widget/dock-item.cpp +++ b/src/ui/widget/dock-item.cpp @@ -291,10 +291,19 @@ DockItem::present() void DockItem::grab_focus() { - if (GTK_WIDGET_REALIZED (_gdl_dock_item)) + if (GTK_WIDGET_REALIZED (_gdl_dock_item)) { + + // make sure the window we're in is present + Gtk::Widget *toplevel = getWidget().get_toplevel(); + if (Gtk::Window *window = dynamic_cast(toplevel)) { + window->present(); + } + gtk_widget_grab_focus (_gdl_dock_item); - else + + } else { _grab_focus_on_realize = true; + } } -- 2.30.2