[gnome-todo/gnome-3-22] task-row: rework focus management



commit c2a022dacf179f305d6e33df711e5e93062be848
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Thu Dec 1 01:37:40 2016 -0200

    task-row: rework focus management
    
    Instead of relying on these shady focus-in and focus-out
    events, lets just manually handle them.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=762852

 data/ui/list-view.ui     |    1 +
 data/ui/task-row.ui      |    2 -
 src/gtd-task-list-view.c |   55 +++++++++++++++++++
 src/gtd-task-row.c       |  131 +++++++++++++++++++++-------------------------
 src/gtd-task-row.h       |    5 ++
 5 files changed, 120 insertions(+), 74 deletions(-)
---
diff --git a/data/ui/list-view.ui b/data/ui/list-view.ui
index 719b77a..30bc6aa 100644
--- a/data/ui/list-view.ui
+++ b/data/ui/list-view.ui
@@ -41,6 +41,7 @@
                         <signal name="drag-drop" handler="listbox_drag_drop" object="GtdTaskListView" 
swapped="no" />
                         <signal name="drag-leave" handler="listbox_drag_leave" object="GtdTaskListView" 
swapped="no" />
                         <signal name="drag-motion" handler="listbox_drag_motion" object="GtdTaskListView" 
swapped="no" />
+                        <signal name="row-activated" handler="listbox_row_activated" 
object="GtdTaskListView" swapped="no" />
                         <child>
                           <object class="GtdTaskRow" id="new_task_row">
                             <property name="visible">True</property>
diff --git a/data/ui/task-row.ui b/data/ui/task-row.ui
index 29b899f..89b32f7 100644
--- a/data/ui/task-row.ui
+++ b/data/ui/task-row.ui
@@ -98,7 +98,6 @@
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="hexpand">True</property>
-                        <signal name="focus_out_event" handler="gtd_task_row__entry_focus_out" 
object="GtdTaskRow" swapped="no" />
                       </object>
                       <packing>
                         <property name="name">title</property>
@@ -220,7 +219,6 @@
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <signal name="activate" handler="gtd_task_row__entry_activated" object="GtdTaskRow" 
swapped="no" />
-                        <signal name="focus_out_event" handler="gtd_task_row__entry_focus_out" 
object="GtdTaskRow" swapped="no" />
                       </object>
                       <packing>
                         <property name="name">entry</property>
diff --git a/src/gtd-task-list-view.c b/src/gtd-task-list-view.c
index eadb807..d90997a 100644
--- a/src/gtd-task-list-view.c
+++ b/src/gtd-task-list-view.c
@@ -104,6 +104,8 @@ typedef struct
   /* Custom sorting function data */
   GtdTaskListViewSortFunc sort_func;
   gpointer                sort_user_data;
+
+  GtkWidget             *active_row;
 } GtdTaskListViewPrivate;
 
 struct _GtdTaskListView
@@ -164,6 +166,27 @@ typedef gboolean     (*IterateSubtaskFunc)                       (GtdTaskListVie
                                                                   GtdTask            *task);
 
 /*
+ * Active row management
+ */
+static void
+set_active_row (GtdTaskListView *self,
+                GtkWidget       *row)
+{
+  GtdTaskListViewPrivate *priv = gtd_task_list_view_get_instance_private (self);
+
+  if (priv->active_row == row)
+    return;
+
+  if (priv->active_row)
+    gtd_task_row_set_active (GTD_TASK_ROW (priv->active_row), FALSE);
+
+  priv->active_row = row;
+
+  if (row)
+    gtd_task_row_set_active (GTD_TASK_ROW (row), TRUE);
+}
+
+/*
  * Auxiliary function to iterate through a list of subtasks
  */
 static void
@@ -660,6 +683,9 @@ gtd_task_list_view__remove_task_cb (GtdEditPane *pane,
 
   gtd_window_notify (window, notification);
 
+  /* Clear the active row */
+  set_active_row (user_data, NULL);
+
   g_clear_pointer (&text, g_free);
 
 out:
@@ -679,6 +705,8 @@ gtd_task_list_view__edit_task_finished (GtdEditPane *pane,
 
   priv = GTD_TASK_LIST_VIEW (user_data)->priv;
 
+  set_active_row (user_data, NULL);
+
   gtk_revealer_set_reveal_child (priv->edit_revealer, FALSE);
 
   gtd_task_save (task);
@@ -800,6 +828,8 @@ task_row_entered_cb (GtdTaskListView *self,
 
   gtk_revealer_set_reveal_child (priv->edit_revealer, TRUE);
   gtd_arrow_frame_set_row (priv->arrow_frame, row);
+
+  set_active_row (self, GTK_WIDGET (row));
 }
 
 static void
@@ -822,6 +852,23 @@ task_row_exited_cb (GtdTaskListView *self,
 
   gtk_revealer_set_reveal_child (priv->edit_revealer, FALSE);
   gtd_arrow_frame_set_row (priv->arrow_frame, NULL);
+
+  if (GTK_WIDGET (row) == priv->active_row &&
+      priv->active_row != GTK_WIDGET (priv->new_task_row))
+    {
+      set_active_row (self, NULL);
+    }
+}
+
+static void
+listbox_row_activated (GtkListBox      *listbox,
+                       GtkListBox      *row,
+                       GtdTaskListView *self)
+{
+  if (!GTD_IS_TASK_ROW (row))
+    return;
+
+  set_active_row (self, GTK_WIDGET (row));
 }
 
 static void
@@ -864,6 +911,9 @@ destroy_task_row (GtdTaskListView *self,
   g_signal_handlers_disconnect_by_func (row, task_row_entered_cb, self);
   g_signal_handlers_disconnect_by_func (row, task_row_exited_cb, self);
 
+  if (GTK_WIDGET (row) == self->priv->active_row)
+    set_active_row (self, NULL);
+
   gtd_task_row_destroy (row);
 }
 
@@ -1576,6 +1626,7 @@ gtd_task_list_view_class_init (GtdTaskListViewClass *klass)
   gtk_widget_class_bind_template_callback (widget_class, listbox_drag_drop);
   gtk_widget_class_bind_template_callback (widget_class, listbox_drag_leave);
   gtk_widget_class_bind_template_callback (widget_class, listbox_drag_motion);
+  gtk_widget_class_bind_template_callback (widget_class, listbox_row_activated);
   gtk_widget_class_bind_template_callback (widget_class, task_row_exited_cb);
 
   gtk_widget_class_set_css_name (widget_class, "task-list-view");
@@ -1590,6 +1641,8 @@ gtd_task_list_view_init (GtdTaskListView *self)
 
   gtk_widget_init_template (GTK_WIDGET (self));
 
+  self->priv->active_row = GTK_WIDGET (self->priv->new_task_row);
+
   gtk_drag_dest_set (GTK_WIDGET (self->priv->listbox),
                      0,
                      NULL,
@@ -1828,6 +1881,8 @@ gtd_task_list_view_set_task_list (GtdTaskListView *view,
                             "task-updated",
                             G_CALLBACK (gtk_list_box_invalidate_sort),
                             priv->listbox);
+
+  set_active_row (view, GTK_WIDGET (priv->new_task_row));
 }
 
 /**
diff --git a/src/gtd-task-row.c b/src/gtd-task-row.c
index 456f356..1b21cb1 100644
--- a/src/gtd-task-row.c
+++ b/src/gtd-task-row.c
@@ -59,6 +59,8 @@ struct _GtdTaskRow
   GtdTask                   *task;
 
   gint                       destroy_row_timeout_id;
+
+  gboolean                   active;
 };
 
 #define PRIORITY_ICON_SIZE         8
@@ -69,7 +71,6 @@ G_DEFINE_TYPE (GtdTaskRow, gtd_task_row, GTK_TYPE_LIST_BOX_ROW)
 enum {
   ENTER,
   EXIT,
-  ACTIVATED,
   CREATE_TASK,
   NUM_SIGNALS
 };
@@ -363,49 +364,6 @@ gtd_task_row_new (GtdTask *task)
 }
 
 static gboolean
-gtd_task_row__entry_focus_out (GtkWidget     *widget,
-                               GdkEventFocus *event,
-                               gpointer       user_data)
-{
-  GtdTaskRow *self = GTD_TASK_ROW (user_data);
-
-  g_return_val_if_fail (GTD_IS_TASK_ROW (user_data), FALSE);
-
-  if (self->new_task_mode)
-    gtk_stack_set_visible_child_name (self->new_task_stack, "label");
-  else
-    gtk_stack_set_visible_child_name (self->task_stack, "label");
-
-  return FALSE;
-}
-
-static gboolean
-gtd_task_row__focus_in (GtkWidget     *widget,
-                        GdkEventFocus *event)
-{
-  GtdTaskRow *self = GTD_TASK_ROW (widget);
-
-  g_return_val_if_fail (GTD_IS_TASK_ROW (widget), FALSE);
-
-  if (self->new_task_mode)
-    {
-      gtk_stack_set_visible_child_name (self->new_task_stack, "entry");
-      gtk_widget_grab_focus (GTK_WIDGET (self->new_task_entry));
-
-      g_signal_emit (self, signals[EXIT], 0);
-    }
-  else
-    {
-      gtk_stack_set_visible_child_name (self->task_stack, "title");
-      gtk_widget_grab_focus (GTK_WIDGET (self->title_entry));
-
-      g_signal_emit (self, signals[ENTER], 0);
-    }
-
-  return FALSE;
-}
-
-static gboolean
 gtd_task_row__key_press_event (GtkWidget   *row,
                                GdkEventKey *event)
 {
@@ -414,6 +372,8 @@ gtd_task_row__key_press_event (GtkWidget   *row,
   if (event->keyval == GDK_KEY_Escape && // Esc is pressed
       !(event->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK))) // No modifiers together
     {
+      self->active = FALSE;
+
       if (self->new_task_mode)
         {
           gtk_stack_set_visible_child_name (self->new_task_stack, "label");
@@ -429,6 +389,15 @@ gtd_task_row__key_press_event (GtkWidget   *row,
   return FALSE;
 }
 
+static gboolean
+gtd_task_row_focus_in_event (GtkWidget     *widget,
+                             GdkEventFocus *event)
+{
+  gtd_task_row_set_active (GTD_TASK_ROW (widget), TRUE);
+
+  return GDK_EVENT_PROPAGATE;
+}
+
 static void
 gtd_task_row__entry_activated (GtkEntry *entry,
                                gpointer  user_data)
@@ -546,30 +515,19 @@ gtd_task_row_set_property (GObject      *object,
 }
 
 static void
-gtd_task_row_activate (GtkListBoxRow *row)
-{
-  GTK_LIST_BOX_ROW_CLASS (gtd_task_row_parent_class)->activate (row);
-
-  g_signal_emit (row, signals[ENTER], 0);
-}
-
-static void
 gtd_task_row_class_init (GtdTaskRowClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-  GtkListBoxRowClass *row_class = GTK_LIST_BOX_ROW_CLASS (klass);
 
   object_class->dispose = gtd_task_row_dispose;
   object_class->finalize = gtd_task_row_finalize;
   object_class->get_property = gtd_task_row_get_property;
   object_class->set_property = gtd_task_row_set_property;
 
-  widget_class->focus_in_event = gtd_task_row__focus_in;
+  widget_class->focus_in_event = gtd_task_row_focus_in_event;
   widget_class->key_press_event = gtd_task_row__key_press_event;
 
-  row_class->activate = gtd_task_row_activate;
-
   /**
    * GtdTaskRow::handle-subtasks:
    *
@@ -643,21 +601,6 @@ gtd_task_row_class_init (GtdTaskRowClass *klass)
                                 0);
 
   /**
-   * GtdTaskRow::activate:
-   *
-   * Emitted when the row wants to apply the changes.
-   */
-  signals[ACTIVATED] = g_signal_new ("activated",
-                                     GTD_TYPE_TASK_ROW,
-                                     G_SIGNAL_RUN_LAST,
-                                     0,
-                                     NULL,
-                                     NULL,
-                                     NULL,
-                                     G_TYPE_NONE,
-                                     0);
-
-  /**
    * GtdTaskRow::create-task:
    *
    * Emitted when the row wants the parent widget to create a new task.
@@ -695,7 +638,6 @@ gtd_task_row_class_init (GtdTaskRowClass *klass)
   gtk_widget_class_bind_template_callback (widget_class, mouse_out_event);
   gtk_widget_class_bind_template_callback (widget_class, mouse_over_event);
   gtk_widget_class_bind_template_callback (widget_class, gtd_task_row__entry_activated);
-  gtk_widget_class_bind_template_callback (widget_class, gtd_task_row__entry_focus_out);
 
   gtk_widget_class_set_css_name (widget_class, "taskrow");
 }
@@ -943,3 +885,48 @@ gtd_task_row_set_handle_subtasks (GtdTaskRow *self,
 
   g_object_notify (G_OBJECT (self), "handle-subtasks");
 }
+
+gboolean
+gtd_task_row_get_active (GtdTaskRow *self)
+{
+  g_return_val_if_fail (GTD_IS_TASK_ROW (self), FALSE);
+
+  return self->active;
+}
+
+void
+gtd_task_row_set_active (GtdTaskRow *self,
+                         gboolean    active)
+{
+  g_return_if_fail (GTD_IS_TASK_ROW (self));
+
+  if (self->active == active)
+    return;
+
+  self->active = active;
+
+  if (active)
+    {
+      if (self->new_task_mode)
+        {
+          gtk_stack_set_visible_child_name (self->new_task_stack, "entry");
+          gtk_widget_grab_focus (GTK_WIDGET (self->new_task_entry));
+
+          g_signal_emit (self, signals[EXIT], 0);
+        }
+      else
+        {
+          gtk_stack_set_visible_child_name (self->task_stack, "title");
+          gtk_widget_grab_focus (GTK_WIDGET (self->title_entry));
+
+          g_signal_emit (self, signals[ENTER], 0);
+        }
+    }
+  else
+    {
+      if (self->new_task_mode)
+        gtk_stack_set_visible_child_name (self->new_task_stack, "label");
+      else
+        gtk_stack_set_visible_child_name (self->task_stack, "label");
+    }
+}
diff --git a/src/gtd-task-row.h b/src/gtd-task-row.h
index 0394995..d934670 100644
--- a/src/gtd-task-row.h
+++ b/src/gtd-task-row.h
@@ -54,6 +54,11 @@ gboolean                  gtd_task_row_get_handle_subtasks      (GtdTaskRow
 void                      gtd_task_row_set_handle_subtasks      (GtdTaskRow          *self,
                                                                  gboolean             handle_subtasks);
 
+gboolean                  gtd_task_row_get_active               (GtdTaskRow          *self);
+
+void                      gtd_task_row_set_active               (GtdTaskRow          *self,
+                                                                 gboolean             active);
+
 G_END_DECLS
 
 #endif /* GTD_TASK_ROW_H */


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