Commit 813a51bf authored by Guido Gunther's avatar Guido Gunther

Hack on call display widget

TODO:
- wire up avatar and name label
- wire up callaudiod
- TODOs in source
- add encryption indicator
Signed-off-by: Guido Gunther's avatarGuido Günther <guido.gunther@puri.sm>
parent 85a2c8a1
Pipeline #66513 passed with stages
in 35 minutes and 35 seconds
......@@ -10,6 +10,7 @@ src/background.c
src/background-manager.c
src/batteryinfo.c
src/bt-info.c
src/call-display.c
src/docked-info.c
src/end-session-dialog.c
src/fader.c
......@@ -55,6 +56,7 @@ src/ui/app-auth-prompt.ui
src/ui/app-grid-button.ui
src/ui/app-grid.ui
src/ui/end-session-dialog.ui
src/ui/call-display.ui
src/ui/home.ui
src/ui/lockscreen.ui
src/ui/media-player.ui
......
/*
* Copyright (C) 2021 Purism SPC
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calls is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calls is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Guido Günther <agx@sigxcpu.org>
* Somewhat based on call's call-display by:
* Author: Bob Ham <bob.ham@puri.sm>
*/
#include "config.h"
#include "call-display.h"
#include "calls-manager.h"
#include <glib.h>
#include <glib/gi18n.h>
#include <handy.h>
enum {
PROP_0,
PROP_CALL,
PROP_LAST_PROP,
};
static GParamSpec *props[PROP_LAST_PROP];
struct _PhoshCallDisplay {
GtkOverlay parent_instance;
PhoshDBusCallsCall *call;
GTimer *timer;
guint timeout;
GtkLabel *incoming_phone_call;
HdyAvatar *avatar;
GtkLabel *primary_contact_info;
GtkLabel *secondary_contact_info;
GtkLabel *status;
GtkBox *controls;
GtkBox *gsm_controls;
GtkBox *general_controls;
GtkToggleButton *speaker;
GtkToggleButton *mute;
GtkButton *hang_up;
GtkButton *answer;
GCancellable *cancel;
GtkRevealer *dial_pad_revealer;
};
G_DEFINE_TYPE (PhoshCallDisplay, phosh_call_display, GTK_TYPE_OVERLAY);
static void
on_call_accept_finish (PhoshDBusCallsCall *proxy,
GAsyncResult *res,
gpointer unused)
{
g_autoptr (GError) err = NULL;
g_return_if_fail (PHOSH_DBUS_IS_CALLS_CALL_PROXY (proxy));
if (!phosh_dbus_calls_call_call_accept_finish (proxy, res, &err)) {
g_warning ("Failed to accept call %p: %s", proxy, err->message);
}
}
static void
on_answer_clicked (GtkButton *button, PhoshCallDisplay *self)
{
g_return_if_fail (PHOSH_IS_CALL_DISPLAY (self));
if (self->cancel) {
g_cancellable_cancel (self->cancel);
g_clear_object (&self->cancel);
}
phosh_dbus_calls_call_call_accept (self->call,
self->cancel,
(GAsyncReadyCallback) on_call_accept_finish,
NULL);
}
static void
on_call_hangup_finish (PhoshDBusCallsCall *proxy,
GAsyncResult *res,
gpointer unused)
{
g_autoptr (GError) err = NULL;
g_return_if_fail (PHOSH_DBUS_IS_CALLS_CALL_PROXY (proxy));
if (!phosh_dbus_calls_call_call_hangup_finish (proxy, res, &err)) {
g_warning ("Failed to hangup call %p: %s", proxy, err->message);
}
}
static void
on_hang_up_clicked (GtkButton *button,
PhoshCallDisplay *self)
{
g_return_if_fail (PHOSH_IS_CALL_DISPLAY (self));
if (self->cancel) {
g_cancellable_cancel (self->cancel);
g_clear_object (&self->cancel);
}
phosh_dbus_calls_call_call_hangup (self->call,
self->cancel,
(GAsyncReadyCallback) on_call_hangup_finish,
NULL);
}
static void
hold_toggled_cb (GtkToggleButton *togglebutton,
PhoshCallDisplay *self)
{
}
static void
mute_toggled_cb (GtkToggleButton *togglebutton,
PhoshCallDisplay *self)
{
#if 0
gboolean want_mute, ret;
g_autoptr (GError) error = NULL;
want_mute = gtk_toggle_button_get_active (togglebutton);
/* TODO: async */
ret = call_audio_mute_mic (want_mute, &error);
if (!ret && error) {
g_warning ("Failed to %smute microphone: %s", want_mute ? "" : "un",
error->message);
}
#endif
}
static void
speaker_toggled_cb (GtkToggleButton *togglebutton,
PhoshCallDisplay *self)
{
#if 0
gboolean want_speaker, ret;
g_autoptr (GError) error = NULL;
want_speaker = gtk_toggle_button_get_active (togglebutton);
/* TODO: async */
ret = call_audio_enable_speaker (want_speaker, &error);
if (!ret && error) {
g_warning ("Failed to %sable speaker: %s", want_speaker ? "en" : "dis",
error->message);
}
#endif
}
static void
add_call_clicked_cb (GtkButton *button,
PhoshCallDisplay *self)
{
}
static void
hide_dial_pad_clicked_cb (PhoshCallDisplay *self)
{
gtk_revealer_set_reveal_child (self->dial_pad_revealer, FALSE);
}
static gboolean
timeout_cb (PhoshCallDisplay *self)
{
#define MINUTE 60
#define HOUR (60 * MINUTE)
#define DAY (24 * HOUR)
gdouble elapsed;
GString *str;
gboolean printing;
guint minutes;
g_return_val_if_fail (PHOSH_IS_CALL_DISPLAY (self), FALSE);
if (!self->call)
return FALSE;
elapsed = g_timer_elapsed (self->timer, NULL);
str = g_string_new ("");
if ( (printing = (elapsed > DAY)) ) {
guint days = (guint)(elapsed / DAY);
g_string_append_printf (str, "%ud ", days);
elapsed -= (days * DAY);
}
if (printing || elapsed > HOUR) {
guint hours = (guint)(elapsed / HOUR);
g_string_append_printf (str, "%u:", hours);
elapsed -= (hours * HOUR);
}
minutes = (guint)(elapsed / MINUTE);
g_string_append_printf (str, "%02u:", minutes);
elapsed -= (minutes * MINUTE);
g_string_append_printf (str, "%02u", (guint)elapsed);
gtk_label_set_text (self->status, str->str);
g_string_free (str, TRUE);
return TRUE;
#undef DAY
#undef HOUR
#undef MINUTE
}
static void
stop_timeout (PhoshCallDisplay *self)
{
if (self->timeout == 0) {
return;
}
g_source_remove (self->timeout);
self->timeout = 0;
}
#if 0
static void
select_mode_complete (gboolean success, GError *error, gpointer data)
{
if (error) {
g_warning ("Failed to select audio mode: %s", error->message);
g_error_free (error);
}
}
#endif
static void
on_call_state_changed (PhoshCallDisplay *self,
GParamSpec *psepc,
PhoshDBusCallsCall *call)
{
GtkStyleContext *hang_up_style;
PhoshCallState state;
g_return_if_fail (PHOSH_IS_CALL_DISPLAY (self));
g_return_if_fail (PHOSH_DBUS_IS_CALLS_CALL (call));
state = phosh_dbus_calls_call_get_state (call);
hang_up_style = gtk_widget_get_style_context
(GTK_WIDGET (self->hang_up));
/* Widgets */
switch (state)
{
case PHOSH_CALL_STATE_INCOMING:
gtk_widget_hide (GTK_WIDGET (self->status));
gtk_widget_hide (GTK_WIDGET (self->controls));
gtk_widget_show (GTK_WIDGET (self->incoming_phone_call));
gtk_widget_show (GTK_WIDGET (self->answer));
gtk_style_context_remove_class
(hang_up_style, GTK_STYLE_CLASS_DESTRUCTIVE_ACTION);
break;
case PHOSH_CALL_STATE_DIALING:
case PHOSH_CALL_STATE_ALERTING:
case PHOSH_CALL_STATE_ACTIVE:
case PHOSH_CALL_STATE_HELD:
case PHOSH_CALL_STATE_WAITING:
gtk_style_context_add_class
(hang_up_style, GTK_STYLE_CLASS_DESTRUCTIVE_ACTION);
gtk_widget_hide (GTK_WIDGET (self->answer));
gtk_widget_hide (GTK_WIDGET (self->incoming_phone_call));
gtk_widget_show (GTK_WIDGET (self->controls));
gtk_widget_show (GTK_WIDGET (self->status));
gtk_widget_set_visible
(GTK_WIDGET (self->gsm_controls),
state != PHOSH_CALL_STATE_DIALING
&& state != PHOSH_CALL_STATE_ALERTING);
#if 0
call_audio_select_mode_async (CALL_AUDIO_MODE_CALL,
select_mode_complete,
NULL);
#endif
break;
case PHOSH_CALL_STATE_DISCONNECTED:
#if 0
call_audio_select_mode_async (CALL_AUDIO_MODE_DEFAULT,
select_mode_complete,
NULL);
#endif
break;
default:
g_warn_if_reached ();
}
/* Status text */
switch (state)
{
case PHOSH_CALL_STATE_INCOMING:
break;
case PHOSH_CALL_STATE_DIALING:
case PHOSH_CALL_STATE_ALERTING:
gtk_label_set_text (self->status, _("Calling…"));
break;
case PHOSH_CALL_STATE_ACTIVE:
case PHOSH_CALL_STATE_HELD:
case PHOSH_CALL_STATE_WAITING:
if (self->timeout == 0) {
self->timeout = g_timeout_add
(500, (GSourceFunc)timeout_cb, self);
timeout_cb (self);
}
break;
case PHOSH_CALL_STATE_DISCONNECTED:
stop_timeout (self);
break;
default:
g_warn_if_reached ();
}
}
static void
on_call_unrefed (PhoshCallDisplay *self,
PhoshDBusCallsCall *call)
{
g_debug ("Dropping call %p", call);
self->call = NULL;
gtk_label_set_label (self->primary_contact_info, "");
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CALL]);
}
static void
set_call (PhoshCallDisplay *self, PhoshDBusCallsCall *call)
{
const gchar *label;
PhoshCallsManager *manager = phosh_calls_manager_get_default ();
g_return_if_fail (PHOSH_IS_CALLS_MANAGER (manager));
if (self->call == call)
return;
self->call = call;
g_object_weak_ref (G_OBJECT (call),
(GWeakNotify) on_call_unrefed,
self);
label = phosh_dbus_calls_call_get_id (call);
if (label == NULL || label[0] == '\0')
label = _("Unknown");
gtk_label_set_label (self->primary_contact_info, label);
g_signal_connect_object (call, "notify::state",
G_CALLBACK (on_call_state_changed),
self,
G_CONNECT_SWAPPED);
on_call_state_changed (self, NULL, call);
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CALL]);
}
static void
get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PhoshCallDisplay *self = PHOSH_CALL_DISPLAY (object);
switch (property_id) {
case PROP_CALL:
g_value_set_object (value, self->call);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PhoshCallDisplay *self = PHOSH_CALL_DISPLAY (object);
switch (property_id) {
case PROP_CALL:
set_call (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
constructed (GObject *object)
{
PhoshCallDisplay *self = PHOSH_CALL_DISPLAY (object);
self->timer = g_timer_new ();
G_OBJECT_CLASS (phosh_call_display_parent_class)->constructed (object);
}
static void
block_delete_cb (GtkWidget *widget)
{
g_signal_stop_emission_by_name (widget, "delete-text");
}
static void
insert_text_cb (GtkEditable *editable,
gchar *text,
gint length,
gint *position,
PhoshCallDisplay *self)
{
gint end_pos = -1;
// phosh_call_tone_start (self->call, *text);
// Make sure that new chars are inserted at the end of the input
*position = end_pos;
g_signal_handlers_block_by_func (editable,
(gpointer) insert_text_cb, self);
gtk_editable_insert_text (editable, text, length, &end_pos);
g_signal_handlers_unblock_by_func (editable,
(gpointer) insert_text_cb, self);
g_signal_stop_emission_by_name (editable, "insert-text");
}
static void
phosh_call_display_init (PhoshCallDisplay *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
#if 0
if (!call_audio_is_inited ()) {
g_critical ("libcallaudio not initialized");
gtk_widget_set_sensitive (GTK_WIDGET (self->speaker), FALSE);
gtk_widget_set_sensitive (GTK_WIDGET (self->mute), FALSE);
}
#endif
}
static void
dispose (GObject *object)
{
PhoshCallDisplay *self = PHOSH_CALL_DISPLAY (object);
/* NOTE: we don't hold a ref on self->call */
stop_timeout (self);
G_OBJECT_CLASS (phosh_call_display_parent_class)->dispose (object);
}
static void
finalize (GObject *object)
{
PhoshCallDisplay *self = PHOSH_CALL_DISPLAY (object);
g_timer_destroy (self->timer);
G_OBJECT_CLASS (phosh_call_display_parent_class)->finalize (object);
}
static void
phosh_call_display_class_init (PhoshCallDisplayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->constructed = constructed;
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->dispose = dispose;
object_class->finalize = finalize;
/**
* PhoshCallDisplay:call-handle:
*
* An opaque handle to a call
*/
props[PROP_CALL] = g_param_spec_object ("call",
"",
"",
PHOSH_DBUS_TYPE_CALLS_CALL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, PROP_LAST_PROP, props);
gtk_widget_class_set_template_from_resource (widget_class, "/sm/puri/phosh/ui/call-display.ui");
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, incoming_phone_call);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, primary_contact_info);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, secondary_contact_info);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, avatar);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, status);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, controls);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, gsm_controls);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, general_controls);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, speaker);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, mute);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, hang_up);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, answer);
gtk_widget_class_bind_template_child (widget_class, PhoshCallDisplay, dial_pad_revealer);
gtk_widget_class_bind_template_callback (widget_class, on_answer_clicked);
gtk_widget_class_bind_template_callback (widget_class, on_hang_up_clicked);
gtk_widget_class_bind_template_callback (widget_class, hold_toggled_cb);
gtk_widget_class_bind_template_callback (widget_class, mute_toggled_cb);
gtk_widget_class_bind_template_callback (widget_class, speaker_toggled_cb);
gtk_widget_class_bind_template_callback (widget_class, add_call_clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, hide_dial_pad_clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, block_delete_cb);
gtk_widget_class_bind_template_callback (widget_class, insert_text_cb);
}
PhoshCallDisplay *
phosh_call_display_new (PhoshDBusCallsCall *call)
{
return g_object_new (PHOSH_TYPE_CALL_DISPLAY,
"call", call,
NULL);
}
PhoshDBusCallsCall *
phosh_call_display_get_call (PhoshCallDisplay *self)
{
g_return_val_if_fail (PHOSH_IS_CALL_DISPLAY (self), NULL);
return self->call;
}
/*
* Copyright (C) 2018 Purism SPC
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calls is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calls is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Guido Günther <agx@sigxcpu.org>
*/
#pragma once
#include "dbus/calls-dbus.h"
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define PHOSH_TYPE_CALL_DISPLAY (phosh_call_display_get_type ())
G_DECLARE_FINAL_TYPE (PhoshCallDisplay, phosh_call_display, PHOSH, CALL_DISPLAY, GtkOverlay);
PhoshCallDisplay *phosh_call_display_new (PhoshDBusCallsCall *call);
PhoshDBusCallsCall *phosh_call_display_get_call (PhoshCallDisplay *self);
G_END_DECLS