gnome: play DTMF tones on keypress

If the selected call is in progress and the
input focus is not in an entry, the client will pass
keyboard keys pressed as input to for DTMF tones
to be played by the daemon. The daemon is responsible
for filtering invalid DTMF characters.

Note: this commit disables the GTK built-in treeview
search so it does not steal input focus.

Refs #71632

Change-Id: I127ff814f8bdd84b51f1f8c62132e028189c8f68
diff --git a/src/contactsview.cpp b/src/contactsview.cpp
index 04cd7e3..789dee0 100644
--- a/src/contactsview.cpp
+++ b/src/contactsview.cpp
@@ -338,6 +338,10 @@
     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview_contacts), FALSE);
     gtk_container_add(GTK_CONTAINER(self), treeview_contacts);
 
+    /* disable default search, we will handle it ourselves via LRC;
+     * otherwise the search steals input focus on key presses */
+    gtk_tree_view_set_enable_search(GTK_TREE_VIEW(treeview_contacts), FALSE);
+
     CategorizedContactModel::instance()->setUnreachableHidden(true);
     priv->q_contact_model = new ActiveItemProxyModel(CategorizedContactModel::instance());
     priv->q_contact_model->setSortRole(Qt::DisplayRole);
diff --git a/src/historyview.cpp b/src/historyview.cpp
index 0d96808..16d958f 100644
--- a/src/historyview.cpp
+++ b/src/historyview.cpp
@@ -214,6 +214,10 @@
     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview_history), TRUE);
     gtk_container_add(GTK_CONTAINER(self), treeview_history);
 
+    /* disable default search, we will handle it ourselves via LRC;
+     * otherwise the search steals input focus on key presses */
+    gtk_tree_view_set_enable_search(GTK_TREE_VIEW(treeview_history), FALSE);
+
     /* sort the history in descending order by date */
     priv->q_history_model = new QSortFilterProxyModel();
     priv->q_history_model->setSourceModel(CategorizedHistoryModel::instance());
diff --git a/src/incomingcallview.cpp b/src/incomingcallview.cpp
index 4c057a5..c2d1f6a 100644
--- a/src/incomingcallview.cpp
+++ b/src/incomingcallview.cpp
@@ -84,6 +84,7 @@
 incoming_call_view_init(IncomingCallView *view)
 {
     gtk_widget_init_template(GTK_WIDGET(view));
+    gtk_widget_add_events(GTK_WIDGET(view), GDK_KEY_PRESS_MASK);
 }
 
 static void
diff --git a/src/ringmainwindow.cpp b/src/ringmainwindow.cpp
index 81ccd63..7a37a55 100644
--- a/src/ringmainwindow.cpp
+++ b/src/ringmainwindow.cpp
@@ -185,7 +185,6 @@
         gtk_stack_add_named(GTK_STACK(priv->stack_call_view), new_call_view, new_call_view_name);
         gtk_stack_set_visible_child(GTK_STACK(priv->stack_call_view), new_call_view);
         g_free(new_call_view_name);
-
     } else {
         /* nothing selected in the call model, so show the default screen */
 
@@ -823,6 +822,41 @@
     return TRUE;
 }
 
+static gboolean
+dtmf_pressed(RingMainWindow *win,
+              GdkEventKey *event,
+              G_GNUC_UNUSED gpointer user_data)
+{
+    g_return_val_if_fail(event->type == GDK_KEY_PRESS, GDK_EVENT_PROPAGATE);
+
+    /* we want to react to digit key presses, as long as a GtkEntry is not the
+     * input focus
+     */
+    GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(win));
+    if (GTK_IS_ENTRY(focus))
+        return GDK_EVENT_PROPAGATE;
+
+    /* make sure that a call is selected*/
+    QItemSelectionModel *selection = CallModel::instance()->selectionModel();
+    QModelIndex idx = selection->currentIndex();
+    if (!idx.isValid())
+        return GDK_EVENT_PROPAGATE;
+
+    /* make sure that the selected call is in progress */
+    Call *call = CallModel::instance()->getCall(idx);
+    Call::LifeCycleState state = call->lifeCycleState();
+    if (state != Call::LifeCycleState::PROGRESS)
+        return GDK_EVENT_PROPAGATE;
+
+    /* pass the character that was entered to be played by the daemon;
+     * the daemon will filter out invalid DTMF characters */
+    guint32 unicode_val = gdk_keyval_to_unicode(event->keyval);
+    QString val = QString::fromUcs4(&unicode_val, 1);
+    call->playDTMF(val);
+    g_debug("attemptingto play DTMF tone during ongoing call: %s", val.toUtf8().constData());
+    return GDK_EVENT_STOP;
+}
+
 static void
 ring_main_window_init(RingMainWindow *win)
 {
@@ -1095,6 +1129,9 @@
             get_active_ring_account(win);
         }
     );
+
+    /* react to digit key press events */
+    g_signal_connect(win, "key-press-event", G_CALLBACK(dtmf_pressed), NULL);
 }
 
 static void
diff --git a/ui/ringmainwindow.ui b/ui/ringmainwindow.ui
index 60a8dcd..712107a 100644
--- a/ui/ringmainwindow.ui
+++ b/ui/ringmainwindow.ui
@@ -195,6 +195,7 @@
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="headers_visible">False</property>
+                    <property name="enable-search">False</property>
                     <child internal-child="selection">
                       <object class="GtkTreeSelection" id="treeview-selection1"/>
                     </child>