Пример #1
0
QMetaObject::Connection
gtk_combo_box_set_qmodel(GtkComboBox *box, QAbstractItemModel *qmodel, QItemSelectionModel *selection_model)
{
    QMetaObject::Connection connection;
    GtkTreeModel *model;

    model = (GtkTreeModel *)gtk_q_tree_model_new(
        qmodel,
        1,
        0, Qt::DisplayRole, G_TYPE_STRING);

    /* use a filter model to remove disabled items */
    GtkTreeModel *filter_model = gtk_tree_model_filter_new(model, NULL);
    gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filter_model),
                                           (GtkTreeModelFilterVisibleFunc)filter_disabled_items,
                                           NULL, NULL);

    gtk_combo_box_set_model(box, GTK_TREE_MODEL(filter_model));
    GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box), renderer, FALSE);
    gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(box), renderer,
                                   "text", 0, NULL);

    if (!selection_model) return connection;

   /* sync the initial selection */
   gtk_combo_box_set_active_index(box, selection_model->currentIndex());

    /* connect signals to and from the selection model */
    connection = QObject::connect(
        selection_model,
        &QItemSelectionModel::currentChanged,
        [=](const QModelIndex current, G_GNUC_UNUSED const QModelIndex & previous) {
            gtk_combo_box_set_active_index(box, current);
        }
    );
    g_signal_connect(box,
                     "changed",
                     G_CALLBACK(update_selection),
                     selection_model);

    return connection;
}
static void
build_tab_view(AccountDevicesTab *view)
{
    g_return_if_fail(IS_ACCOUNT_DEVICES_TAB(view));
    AccountDevicesTabPrivate *priv = ACCOUNT_DEVICES_TAB_GET_PRIVATE(view);

    g_signal_connect_swapped(priv->button_add_device, "clicked", G_CALLBACK(show_add_device_view), view);
    g_signal_connect_swapped(priv->button_add_device_cancel, "clicked", G_CALLBACK(show_manage_devices_view), view);
    g_signal_connect(priv->button_export_on_the_ring, "clicked", G_CALLBACK(export_on_the_ring_clicked), view);
    g_signal_connect_swapped(priv->button_generated_pin_ok, "clicked", G_CALLBACK(show_manage_devices_view), view);
    g_signal_connect_swapped(priv->button_export_on_ring_error_ok, "clicked", G_CALLBACK(show_add_device_view), view);

    gtk_label_set_text(GTK_LABEL(priv->label_device_id), priv->account->deviceId().toUtf8().constData());

    /* treeview_devices */
    auto *devices_model = gtk_q_tree_model_new(
        (QAbstractItemModel*) priv->account->ringDeviceModel(),
        2,
        RingDevice::Column::Name, Qt::DisplayRole, G_TYPE_STRING,
        RingDevice::Column::Id, Qt::DisplayRole, G_TYPE_STRING);

    gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview_devices), GTK_TREE_MODEL(devices_model));

    GtkCellRenderer* renderer;
    GtkTreeViewColumn* column;

    renderer = gtk_cell_renderer_text_new();
    column = gtk_tree_view_column_new_with_attributes(C_("Device Name Column", "Name"), renderer, "text", 0, NULL);
    gtk_tree_view_column_set_expand(column, TRUE);
    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_devices), column);

    renderer = gtk_cell_renderer_text_new();
    column = gtk_tree_view_column_new_with_attributes(C_("Device ID Column", "ID"), renderer, "text", 1, NULL);
    gtk_tree_view_column_set_expand(column, TRUE);
    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_devices), column);

    /* Show manage-devices view */
    gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_devices), priv->manage_devices);
}
static void
build_tab_view(AccountSecurityTab *self)
{
    g_return_if_fail(IS_ACCOUNT_SECURITY_TAB(self));
    AccountSecurityTabPrivate *priv = ACCOUNT_SECURITY_TAB_GET_PRIVATE(self);

    gboolean not_ring = priv->account->protocol() != Account::Protocol::RING;

    /* SRTP */
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_use_srtp),
                                 priv->account->isSrtpEnabled());
    /* disable options if SRTP is off or if its a RING account */
    gtk_widget_set_sensitive(priv->checkbutton_use_srtp, not_ring);
    gtk_widget_set_sensitive(priv->box_key_exchange,
                             priv->account->isSrtpEnabled() && not_ring);
    gtk_widget_set_sensitive(priv->checkbutton_srtp_fallback,
                             priv->account->isSrtpEnabled() && not_ring);
    g_signal_connect(priv->checkbutton_use_srtp, "toggled", G_CALLBACK(use_srtp_toggled), self);

    /* encryption key exchange type */
    priv->key_exchange_selection =  gtk_combo_box_set_qmodel(
        GTK_COMBO_BOX(priv->combobox_key_exchange),
        (QAbstractItemModel *)priv->account->keyExchangeModel(),
        priv->account->keyExchangeModel()->selectionModel());

    /* SRTP fallback */
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_srtp_fallback),
                                 priv->account->isSrtpRtpFallback());
    g_signal_connect(priv->checkbutton_srtp_fallback, "toggled", G_CALLBACK(use_rtp_fallback_toggled), self);

    /* use TLS */
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_use_tls),
                                 priv->account->isTlsEnabled());

    /* disable certain options if TLS is off, or if its a RING account*/
    gtk_widget_set_sensitive(priv->checkbutton_use_tls, not_ring);
    gtk_widget_set_sensitive(priv->grid_tls_settings_0,
                             priv->account->isTlsEnabled());
    gtk_widget_set_sensitive(priv->grid_tls_settings_1,
                             priv->account->isTlsEnabled() && not_ring);
    gtk_widget_set_sensitive(priv->buttonbox_cipher_list,
                             priv->account->isTlsEnabled() && not_ring);
    gtk_widget_set_sensitive(priv->treeview_cipher_list,
                             priv->account->isTlsEnabled() && not_ring);
    gtk_widget_set_sensitive(priv->checkbutton_verify_certs_server,
                             priv->account->isTlsEnabled() && not_ring);
    gtk_widget_set_sensitive(priv->checkbutton_verify_certs_client,
                             priv->account->isTlsEnabled() && not_ring);
    gtk_widget_set_sensitive(priv->checkbutton_require_incoming_tls_certs,
                             priv->account->isTlsEnabled() && not_ring);
    g_signal_connect(priv->checkbutton_use_tls, "toggled", G_CALLBACK(use_tls_toggled), self);

    /* CA certificate */
    Certificate *ca_cert = priv->account->tlsCaListCertificate();
    if (ca_cert) {
        gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->filechooserbutton_ca_list),
                                      ca_cert->path().toUtf8().constData());
    }
    g_signal_connect(priv->filechooserbutton_ca_list, "file-set", G_CALLBACK(ca_cert_file_set), self);

    /* user certificate */
    if ( (priv->user_cert = priv->account->tlsCertificate()) ) {
        gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->filechooserbutton_certificate),
            priv->user_cert->path().toUtf8().constData()
        );
    }
    g_signal_connect(priv->filechooserbutton_certificate, "file-set", G_CALLBACK(user_cert_file_set), self);

    /* private key */
    if (!priv->account->tlsPrivateKey().isEmpty()) {
        gtk_file_chooser_set_filename(
            GTK_FILE_CHOOSER(priv->filechooserbutton_private_key),
            priv->account->tlsPrivateKey().toUtf8().constData()
        );
    }

    g_signal_connect(priv->filechooserbutton_private_key, "file-set", G_CALLBACK(private_key_file_set), self);

    /* password */
    check_tlspassword_valid(self);
    if (priv->user_cert && priv->user_cert->requirePrivateKeyPassword()) {
        gtk_entry_set_text(
            GTK_ENTRY(priv->entry_password),
            priv->account->tlsPassword().toUtf8().constData()
        );
        gtk_widget_set_sensitive(priv->entry_password, TRUE);
        gtk_widget_set_sensitive(priv->label_private_key_password, TRUE);
    } else {
        /* private key not chosen, or password not required, so disactivate the entry */
        gtk_widget_set_sensitive(priv->entry_password, FALSE);
        gtk_widget_set_sensitive(priv->label_private_key_password, FALSE);
    }

    g_signal_connect(priv->entry_password, "changed", G_CALLBACK(private_key_password_changed), self);

    /* TLS protocol method */
    priv->tls_method_selection = gtk_combo_box_set_qmodel(GTK_COMBO_BOX(priv->combobox_tls_protocol_method),
                                                          (QAbstractItemModel *)priv->account->tlsMethodModel(),
                                                          priv->account->tlsMethodModel()->selectionModel());

    /* outgoing TLS server */
    gtk_entry_set_text(GTK_ENTRY(priv->entry_tls_server_name),
                       priv->account->tlsServerName().toUtf8().constData());
    g_signal_connect(priv->entry_tls_server_name, "changed", G_CALLBACK(tls_server_name_changed), self);


    /* TLS nego timeout */
    gtk_adjustment_set_value(GTK_ADJUSTMENT(priv->adjustment_tls_timeout),
                             priv->account->tlsNegotiationTimeoutSec());
    g_signal_connect(priv->adjustment_tls_timeout, "value-changed", G_CALLBACK(tls_timeout_changed), self);

    /* cipher default or custom */
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->radiobutton_use_default_ciphers),
                                 priv->account->cipherModel()->useDefault());
    /* hide the cipher list if we're using the default ones */
    gtk_revealer_set_reveal_child(GTK_REVEALER(priv->revealer_cipher_list),
                                  !priv->account->cipherModel()->useDefault());
    g_signal_connect(priv->radiobutton_use_default_ciphers,
                     "toggled", G_CALLBACK(use_default_ciphers_toggled), self);

    /* cipher list */
    GtkQTreeModel *cipher_model = gtk_q_tree_model_new(
        (QAbstractItemModel *)priv->account->cipherModel(),
        2,
        Qt::CheckStateRole, G_TYPE_BOOLEAN,
        Qt::DisplayRole, G_TYPE_STRING);
    gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview_cipher_list),
                            GTK_TREE_MODEL(cipher_model));
    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(priv->treeview_cipher_list),
                                      FALSE);

    GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new();
    GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
        "Enabled", renderer, NULL);
    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_cipher_list), column);

    /* we have to use a custom data function here because Qt::Checked and Qt::Unchecked
     * are not the same as true/false as there is an intermediate state */
    gtk_tree_view_column_set_cell_data_func(column,
                                            renderer,
                                            (GtkTreeCellDataFunc)render_check_state,
                                            NULL, NULL);

    g_signal_connect(renderer, "toggled", G_CALLBACK(cipher_enable_toggled), self);

    renderer = gtk_cell_renderer_text_new();
    column = gtk_tree_view_column_new_with_attributes("Cipher", renderer, "text", 1, NULL);
    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_cipher_list), column);

    /* server certs */
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_verify_certs_server),
                                 priv->account->isTlsVerifyServer());
    g_signal_connect(priv->checkbutton_verify_certs_server,
                     "toggled", G_CALLBACK(verify_certs_server_toggled), self);

    /* client certs */
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_verify_certs_client),
                                 priv->account->isTlsVerifyClient());
    g_signal_connect(priv->checkbutton_verify_certs_client,
                     "toggled", G_CALLBACK(verify_certs_client_toggled), self);

    /* incoming certs */
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_require_incoming_tls_certs),
                                 priv->account->isTlsRequireClientCertificate());
    g_signal_connect(priv->checkbutton_require_incoming_tls_certs,
                     "toggled", G_CALLBACK(require_incoming_certs_toggled), self);

    /* update account UI if model is updated */
    priv->account_updated = QObject::connect(
        priv->account,
        &Account::changed,
        [=] () {
            /* SRTP */
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_use_srtp),
                                         priv->account->isSrtpEnabled());

            /* SRTP fallback */
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_srtp_fallback),
                                         priv->account->isSrtpRtpFallback());
            /* use TLS */
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_use_tls),
                                         priv->account->isTlsEnabled());

            /* CA certificate */
            Certificate *ca_cert = priv->account->tlsCaListCertificate();
            if (ca_cert) {
                gtk_file_chooser_set_filename(
                    GTK_FILE_CHOOSER(priv->filechooserbutton_ca_list),
                    ca_cert->path().toUtf8().constData()
                );
            } else {
                /* make sure nothing is selected */
                gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(priv->filechooserbutton_ca_list));
            }


            /* user certificate */
            QObject::disconnect(priv->cert_changed);
            if ( (priv->user_cert = priv->account->tlsCertificate()) ) {
                gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->filechooserbutton_certificate),
                    priv->user_cert->path().toUtf8().constData()
                );
            } else {
                /* make sure nothing is selected */
                gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(priv->filechooserbutton_certificate));
            }

            /* private key */
            if (!priv->account->tlsPrivateKey().isEmpty()) {
                gtk_file_chooser_set_filename(
                    GTK_FILE_CHOOSER(priv->filechooserbutton_private_key),
                    priv->account->tlsPrivateKey().toUtf8().constData()
                );
            } else {
                /* make sure nothing is selected */
                gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(priv->filechooserbutton_private_key));
            }

            /* password */
            check_tlspassword_valid(self);
            if (priv->user_cert && priv->user_cert->requirePrivateKeyPassword()) {
                gtk_entry_set_text(
                    GTK_ENTRY(priv->entry_password),
                    priv->account->tlsPassword().toUtf8().constData()
                );
                gtk_widget_set_sensitive(priv->entry_password, TRUE);
                gtk_widget_set_sensitive(priv->label_private_key_password, TRUE);
            } else {
                /* private key not chosen, or password not required, so disactivate the entry */
                gtk_widget_set_sensitive(priv->entry_password, FALSE);
                gtk_widget_set_sensitive(priv->label_private_key_password, FALSE);
            }

            /* outgoing TLS server */
            gtk_entry_set_text(GTK_ENTRY(priv->entry_tls_server_name),
                               priv->account->tlsServerName().toUtf8().constData());

            /* TLS nego timeout */
            gtk_adjustment_set_value(GTK_ADJUSTMENT(priv->adjustment_tls_timeout),
                                     priv->account->tlsNegotiationTimeoutSec());

            /* cipher default or custom */
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->radiobutton_use_default_ciphers),
                                        priv->account->cipherModel()->useDefault());

            /* server certs */
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_verify_certs_server),
                                        priv->account->isTlsVerifyServer());

            /* client certs */
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_verify_certs_client),
                                        priv->account->isTlsVerifyClient());

            /* incoming certs */
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_require_incoming_tls_certs),
                                        priv->account->isTlsRequireClientCertificate());
        }
    );
}
Пример #4
0
static void
ring_main_window_init(RingMainWindow *win)
{
    RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
    gtk_widget_init_template(GTK_WIDGET(win));

     /* set window icon */
    GError *error = NULL;
    GdkPixbuf* icon = gdk_pixbuf_new_from_resource("/cx/ring/RingGnome/ring-symbol-blue", &error);
    if (icon == NULL) {
        g_debug("Could not load icon: %s", error->message);
        g_clear_error(&error);
    } else
        gtk_window_set_icon(GTK_WINDOW(win), icon);

    /* set menu icon */
    GdkPixbuf* image_ring = gdk_pixbuf_new_from_resource_at_scale("/cx/ring/RingGnome/ring-symbol-blue",
                                                                  -1, 24, TRUE, &error);
    if (image_ring == NULL) {
        g_debug("Could not load icon: %s", error->message);
        g_clear_error(&error);
    } else
        gtk_image_set_from_pixbuf(GTK_IMAGE(priv->image_ring), image_ring);

    /* ring menu */
    GtkBuilder *builder = gtk_builder_new_from_resource("/cx/ring/RingGnome/ringgearsmenu.ui");
    GMenuModel *menu = G_MENU_MODEL(gtk_builder_get_object(builder, "menu"));
    gtk_menu_button_set_menu_model(GTK_MENU_BUTTON(priv->ring_menu), menu);
    g_object_unref(builder);

    /* settings icon */
    gtk_image_set_from_icon_name(GTK_IMAGE(priv->image_settings), "emblem-system-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR);

    /* connect settings button signal */
    g_signal_connect(priv->ring_settings, "clicked", G_CALLBACK(settings_clicked), win);

    /* add the call view to the main stack */
    gtk_stack_add_named(GTK_STACK(priv->stack_main_view),
                        priv->vbox_call_view,
                        CALL_VIEW_NAME);

    if (has_ring_account()) {
        /* user has ring account, so show the call view right away */
        gtk_stack_set_visible_child(GTK_STACK(priv->stack_main_view), priv->vbox_call_view);
    } else {
        /* user has to create the ring account */
        show_account_creation(win);
    }

    /* init the settings views */
    priv->account_settings_view = account_view_new();
    gtk_stack_add_named(GTK_STACK(priv->stack_main_view), priv->account_settings_view, ACCOUNT_SETTINGS_VIEW_NAME);

    priv->media_settings_view = media_settings_view_new();
    gtk_stack_add_named(GTK_STACK(priv->stack_main_view), priv->media_settings_view, MEDIA_SETTINGS_VIEW_NAME);

    priv->general_settings_view = general_settings_view_new();
    gtk_stack_add_named(GTK_STACK(priv->stack_main_view), priv->general_settings_view, GENERAL_SETTINGS_VIEW_NAME);

    /* make the setting we will show first the active one */
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->radiobutton_general_settings), TRUE);
    priv->last_settings_view = priv->general_settings_view;

    /* connect the settings button signals to switch settings views */
    g_signal_connect(priv->radiobutton_media_settings, "toggled", G_CALLBACK(show_media_settings), win);
    g_signal_connect(priv->radiobutton_account_settings, "toggled", G_CALLBACK(show_account_settings), win);
    g_signal_connect(priv->radiobutton_general_settings, "toggled", G_CALLBACK(show_general_settings), win);

    /* populate the notebook */
    auto smart_view = recent_contacts_view_new();
    gtk_container_add(GTK_CONTAINER(priv->scrolled_window_smartview), smart_view);

    auto contacts_view = contacts_view_new();
    gtk_container_add(GTK_CONTAINER(priv->scrolled_window_contacts), contacts_view);

    auto history_view = history_view_new();
    gtk_container_add(GTK_CONTAINER(priv->scrolled_window_history), history_view);

    /* welcome/default view */
    priv->welcome_view = ring_welcome_view_new();
    g_object_ref(priv->welcome_view);
    // gtk_stack_add_named(GTK_STACK(priv->stack_call_view), welcome_view, DEFAULT_VIEW_NAME);
    gtk_container_add(GTK_CONTAINER(priv->frame_call), priv->welcome_view);
    gtk_widget_show(priv->welcome_view);

    /* call/chat selection */
    QObject::connect(
       RecentModel::instance().selectionModel(),
       &QItemSelectionModel::currentChanged,
       [win](const QModelIndex current, G_GNUC_UNUSED const QModelIndex & previous) {
            if (auto call = RecentModel::instance().getActiveCall(current)) {
                /* if the call is on hold, we want to put it off hold automatically
                 * when switching to it */
                if (call->state() == Call::State::HOLD)
                    call << Call::Action::HOLD;
            }
            selection_changed(current, win);
        }
    );

    /* connect to dataChanged of the RecentModel to see if we need to change the view */
    QObject::connect(
        &RecentModel::instance(),
        &RecentModel::dataChanged,
        [win](const QModelIndex & topLeft, G_GNUC_UNUSED const QModelIndex & bottomRight, G_GNUC_UNUSED const QVector<int> & roles) {
            /* it is possible for dataChanged to be emitted inside of a dataChanged handler or
             * some other signal; since the connection is via a lambda, Qt would cause the
             * handler to be called directly. This is not behaviour we usually want, so we call our
             * function via g_idle so that it gets called after the initial handler is done.
             */
            if (topLeft == RecentModel::instance().selectionModel()->currentIndex())
                g_idle_add((GSourceFunc)selected_item_changed, win);
        }
    );

    g_signal_connect(priv->button_placecall, "clicked", G_CALLBACK(search_entry_placecall), win);
    g_signal_connect(priv->search_entry, "activate", G_CALLBACK(search_entry_placecall), win);

    /* autocompletion */
    priv->q_completion_model = new NumberCompletionModel();

    /* autocompletion renderers */
    GtkCellArea *completion_area = gtk_cell_area_box_new();

    /* photo renderer */
    GtkCellRenderer *renderer = gtk_cell_renderer_pixbuf_new();
    gtk_cell_area_box_pack_start(GTK_CELL_AREA_BOX(completion_area),
                                 renderer,
                                 TRUE,  /* expand */
                                 TRUE,  /* align */
                                 TRUE); /* fixed size */

    gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(completion_area),
                                       renderer,
                                       (GtkCellLayoutDataFunc)autocompletion_photo_render,
                                       NULL, NULL);

    /* name renderer */
    renderer = gtk_cell_renderer_text_new();
    g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
    gtk_cell_area_box_pack_start(GTK_CELL_AREA_BOX(completion_area),
                                 renderer,
                                 TRUE,  /* expand */
                                 TRUE,  /* align */
                                 TRUE); /* fixed size */

    gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(completion_area),
                                       renderer,
                                       (GtkCellLayoutDataFunc)autocompletion_name_render,
                                       NULL, NULL);

    /* number renderer */
    renderer = gtk_cell_renderer_text_new();
    g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
    gtk_cell_area_box_pack_start(GTK_CELL_AREA_BOX(completion_area),
                                 renderer,
                                 TRUE,  /* expand */
                                 TRUE,  /* align */
                                 TRUE); /* fixed size */

    gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(completion_area),
                                       renderer,
                                       (GtkCellLayoutDataFunc)autocompletion_number_render,
                                       NULL, NULL);
    /* account renderer */
    renderer = gtk_cell_renderer_text_new();
    g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
    gtk_cell_area_box_pack_start(GTK_CELL_AREA_BOX(completion_area),
                                 renderer,
                                 TRUE,  /* expand */
                                 TRUE,  /* align */
                                 TRUE); /* fixed size */

    gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(completion_area),
                                       renderer,
                                       (GtkCellLayoutDataFunc)autocompletion_account_render,
                                       NULL, NULL);

    GtkEntryCompletion *entry_completion = gtk_entry_completion_new_with_area(completion_area);

    GtkQTreeModel *completion_model = gtk_q_tree_model_new(
        (QAbstractItemModel *)priv->q_completion_model,
        1,
        Qt::DisplayRole, G_TYPE_STRING);

    gtk_entry_completion_set_model(entry_completion, GTK_TREE_MODEL(completion_model));

    gtk_entry_set_completion(GTK_ENTRY(priv->search_entry), entry_completion);
    gtk_entry_completion_set_match_func(
        entry_completion,
        (GtkEntryCompletionMatchFunc) completion_match_func,
        NULL,
        NULL);

    /* connect signal to when text is entered in the entry */
    g_signal_connect(priv->search_entry, "changed", G_CALLBACK(search_entry_text_changed), win);
    g_signal_connect(entry_completion, "match-selected", G_CALLBACK(select_autocompletion), win);

    /* connect to incoming call and focus */
    QObject::connect(
        &CallModel::instance(),
        &CallModel::incomingCall,
        [=](Call* call) {
            CallModel::instance().selectionModel()->setCurrentIndex(
                CallModel::instance().getIndex(call), QItemSelectionModel::ClearAndSelect);
        }
    );

    /* react to digit key press events */
    g_signal_connect(win, "key-press-event", G_CALLBACK(dtmf_pressed), NULL);

    /* set the search entry placeholder text */
    gtk_entry_set_placeholder_text(GTK_ENTRY(priv->search_entry),
                                   C_("Please try to make the translation 50 chars or less so that it fits into the layout", "Search contacts or enter number"));
}