Commit 24356d47 authored by Hugo Lefeuvre's avatar Hugo Lefeuvre Committed by Sébastien Blin

accountcreationwizard: close preview when hidden

Whenever the preview is created and run in the account creation
wizard, there is no way to stop it. This is very annoying because
it grabs the webcam rights without releasing them, and the camera
led stays on, giving the user the impression to be observed.

In this patch we add a mechanism similar to what is done in the
general settings tab: we destroy and create the preview each time
the preview is made visible / hidden. While not the most elegant
solution it allows us to run the preview if and only if it is
displayed & stop it otherwise.

Also, we fix various issues in the account view:
 - when + icon is double clicked, the settings space becomes blank.
   Now if + is clicked while account wizard is open, the account
   wizard gets closed.
 - when an account is selected in the account selection tab while
   the wizard is displayed, nothing "seems to happen". Instead,
   quit the wizard and open the selected tab.
 - when account view is openened for the first time, the settings
   space is blank. Instead, default select an account.

Change-Id: I1e12333e654f70d590886e2aa4f5112154f3068a
Reviewed-by: Sébastien Blin's avatarSebastien Blin <sebastien.blin@savoirfairelinux.com>
parent b8a8057e
/*
* Copyright (C) 2016-2018 Savoir-faire Linux Inc.
* Author: Alexandre Viau <alexandre.viau@savoirfairelinux.com>
* Author: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -17,7 +18,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
// GTK+ related
#include <glib/gi18n.h>
#include <gtk/gtk.h>
......@@ -36,7 +36,6 @@
#include "accountcreationwizard.h"
#include "usernameregistrationbox.h"
struct _AccountCreationWizard
{
GtkBox parent;
......@@ -115,26 +114,14 @@ enum {
static guint account_creation_wizard_signals[LAST_SIGNAL] = { 0 };
static void
destroy_avatar_manipulation(AccountCreationWizard *view)
{
AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
/* make sure the AvatarManipulation widget is destroyed so the VideoWidget inside of it is too;
* NOTE: destorying its parent (box_avatarselection) first will cause a mystery 'BadDrawable'
* crash due to X error */
if (priv->avatar_manipulation)
{
gtk_container_remove(GTK_CONTAINER(priv->box_avatarselection), priv->avatar_manipulation);
priv->avatar_manipulation = nullptr;
}
}
static void
account_creation_wizard_dispose(GObject *object)
{
AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(object);
destroy_avatar_manipulation(ACCOUNT_CREATION_WIZARD(object));
// make sure preview is stopped and destroyed
account_creation_wizard_show_preview(ACCOUNT_CREATION_WIZARD(object), FALSE);
QObject::disconnect(priv->account_state_changed);
G_OBJECT_CLASS(account_creation_wizard_parent_class)->dispose(object);
}
......@@ -257,7 +244,7 @@ create_ring_account(AccountCreationWizard *view,
priv->username = new QString(username);
priv->password = new QString(password);
g_object_ref(view); // ref so its not desroyed too early
g_object_ref(view); // ref so its not destroyed too early
/* create account and set UPnP enabled, as its not by default in the daemon */
Account *account = nullptr;
......@@ -412,6 +399,10 @@ create_new_ring_account(AccountCreationWizard *win)
auto status = create_ring_account(win, display_name, username, password, nullptr, nullptr);
// Now that we've use the preview to generate the avatar, we can safely close it. Don't
// assume owner will do it for us, this might not always be the case
account_creation_wizard_show_preview(win, FALSE);
g_free(display_name);
g_free(password);
g_free(username);
......@@ -508,31 +499,24 @@ show_choose_account_type(AccountCreationWizard *view)
}
static void
show_existing_account(AccountCreationWizard *view)
account_creation_previous_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
{
AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account);
// make sure to stop preview before going back to choose account type
account_creation_wizard_show_preview(view, FALSE);
show_choose_account_type(view);
}
static void
show_account_creation(AccountCreationWizard *win)
show_existing_account(AccountCreationWizard *view)
{
AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
/* avatar manipulation widget */
if (!priv->avatar_manipulation)
{
priv->avatar_manipulation = avatar_manipulation_new_from_wizard();
gtk_box_pack_start(GTK_BOX(priv->box_avatarselection), priv->avatar_manipulation, true, true, 0);
}
gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->account_creation);
AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account);
}
static void
wizard_cancel_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
{
g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED], 0);
account_creation_wizard_cancel(view);
}
static void
......@@ -660,14 +644,14 @@ build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_but
gtk_widget_set_visible(priv->button_wizard_cancel, show_cancel_button);
/* choose_account_type signals */
g_signal_connect_swapped(priv->button_new_account, "clicked", G_CALLBACK(show_account_creation), view);
g_signal_connect_swapped(priv->button_new_account, "clicked", G_CALLBACK(account_creation_wizard_show_preview), view);
g_signal_connect_swapped(priv->button_existing_account, "clicked", G_CALLBACK(show_existing_account), view);
g_signal_connect(priv->button_wizard_cancel, "clicked", G_CALLBACK(wizard_cancel_clicked), view);
/* account_creation signals */
g_signal_connect_swapped(priv->button_account_creation_previous, "clicked", G_CALLBACK(show_choose_account_type), view);
g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
g_signal_connect(priv->button_account_creation_next, "clicked", G_CALLBACK(account_creation_next_clicked), view);
g_signal_connect(priv->button_account_creation_previous, "clicked", G_CALLBACK(account_creation_previous_clicked), view);
g_signal_connect_swapped(priv->entry_password, "changed", G_CALLBACK(entries_new_account_changed), view);
g_signal_connect_swapped(priv->entry_password_confirm, "changed", G_CALLBACK(entries_new_account_changed), view);
g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
......@@ -696,3 +680,32 @@ account_creation_wizard_new(bool show_cancel_button)
build_creation_wizard_view(ACCOUNT_CREATION_WIZARD(view), show_cancel_button);
return (GtkWidget *)view;
}
void
account_creation_wizard_show_preview(AccountCreationWizard *win, gboolean show_preview)
{
AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
/* Similarily to general settings view, we construct and destroy the avatar manipulation widget
each time the profile is made visible / hidden. While not the most elegant solution, this
allows us to run the preview if and only if it is displayed, and always stop it when hidden. */
if (show_preview && !priv->avatar_manipulation) {
priv->avatar_manipulation = avatar_manipulation_new_from_wizard();
gtk_box_pack_start(GTK_BOX(priv->box_avatarselection), priv->avatar_manipulation, true, true, 0);
gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->account_creation);
} else if (priv->avatar_manipulation) {
/* make sure the AvatarManipulation widget is destroyed so the VideoWidget inside of it is too;
* NOTE: destorying its parent (box_avatarselection) first will cause a mystery 'BadDrawable'
* crash due to X error */
gtk_container_remove(GTK_CONTAINER(priv->box_avatarselection), priv->avatar_manipulation);
priv->avatar_manipulation = nullptr;
}
}
void
account_creation_wizard_cancel(AccountCreationWizard *win)
{
// make sure to stop preview before doing something else
account_creation_wizard_show_preview(win, FALSE);
g_signal_emit(G_OBJECT(win), account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED], 0);
}
......@@ -35,4 +35,7 @@ typedef struct _AccountCreationWizardClass AccountCreationWizardClass;
GType account_creation_wizard_get_type (void) G_GNUC_CONST;
GtkWidget *account_creation_wizard_new (bool cancel_button);
void account_creation_wizard_show_preview (AccountCreationWizard *win, gboolean show_preview = TRUE);
void account_creation_wizard_cancel (AccountCreationWizard *win);
G_END_DECLS
......@@ -126,18 +126,27 @@ account_selection_changed(GtkTreeSelection *selection, AccountView *self)
auto old_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_account));
if(IS_ACCOUNT_CREATION_WIZARD(old_view))
{
/* When using the account creation wizard, The user might create
* accounts that will be deleted by the daemon. The fact that the
* selection has changed should be ignored. The account creation wizard
* should be responsible to remove itself of the stack and then call
* account_selection_changed.
*/
// cancel account creation, this will call hide_account_creation_wizard via callback
account_creation_wizard_cancel(ACCOUNT_CREATION_WIZARD(old_view));
return;
}
QModelIndex account_idx = get_index_from_selection(selection);
if (!account_idx.isValid()) {
/* it nothing is slected, simply display something empty */
g_debug("accountview: invalid account selection");
/* If no account is selected, check for account list size. If not 0, select
the first account. */
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(priv->treeview_account_list));
if (gtk_tree_model_iter_n_children(model, NULL)) {
g_debug("accountview: other accounts are available, selecting first one");
GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
gtk_tree_selection_select_path(gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->treeview_account_list)), path);
gtk_tree_path_free(path);
return;
}
/* there is no account to select, display empty */
GtkWidget *empty_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_show(empty_box);
gtk_stack_add_named(GTK_STACK(priv->stack_account), empty_box, "placeholder");
......@@ -323,6 +332,7 @@ hide_account_creation_wizard(AccountView *view)
auto old_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_account));
if (IS_ACCOUNT_CREATION_WIZARD(old_view))
{
account_creation_wizard_show_preview(ACCOUNT_CREATION_WIZARD(old_view), FALSE);
gtk_container_remove(GTK_CONTAINER(priv->stack_account), old_view);
}
......@@ -369,7 +379,13 @@ add_account(G_GNUC_UNUSED GtkWidget *entry, AccountView *view)
Account::Protocol protocol = qvariant_cast<Account::Protocol>(idx.data((int)ProtocolModel::Role::Protocol));
if (protocol == Account::Protocol::RING)
{
show_account_creation_wizard(view);
auto old_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_account));
if (IS_ACCOUNT_CREATION_WIZARD(old_view))
{
account_creation_wizard_cancel(ACCOUNT_CREATION_WIZARD(old_view));
} else {
show_account_creation_wizard(view);
}
}
else
{
......@@ -556,3 +572,23 @@ account_view_new(AccountInfoPointer const & accountInfo)
priv->accountInfo_ = &accountInfo;
return (GtkWidget *)view;
}
void
account_settings_view_show(AccountView *view, gboolean show) {
AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
/* If displayed stack element is still the placeholder element, thats is it hasn't
been initialized yet, change account selection. */
if (show && strcmp(gtk_stack_get_visible_child_name (GTK_STACK(priv->stack_account)), "placeholder") == 0) {
auto selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_account_list));
account_selection_changed(selection, view);
return;
}
/* If account creation wizard is currently open and settings get closed, cancel so
the preview is stopped properly. */
auto old_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_account));
if (!show && IS_ACCOUNT_CREATION_WIZARD(old_view)) {
account_creation_wizard_cancel(ACCOUNT_CREATION_WIZARD(old_view));
}
}
......@@ -40,6 +40,8 @@ typedef struct _AccountViewClass AccountViewClass;
GType account_view_get_type (void) G_GNUC_CONST;
GtkWidget *account_view_new (AccountInfoPointer const & accountInfo);
void account_settings_view_show (AccountView *view, gboolean show);
G_END_DECLS
#endif /* _ACCOUNTVIEW_H */
......@@ -348,6 +348,7 @@ on_show_account_settings(GtkToggleButton* navbutton, RingMainWindow* self)
auto* priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(self));
if (gtk_toggle_button_get_active(navbutton)) {
account_settings_view_show(ACCOUNT_VIEW(priv->account_settings_view), TRUE);
gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_main_view), ACCOUNT_SETTINGS_VIEW_NAME);
priv->last_settings_view = priv->account_settings_view;
}
......@@ -1175,6 +1176,7 @@ CppImpl::leaveSettingsView()
gtk_widget_hide(widgets->hbox_settings);
/* make sure video preview is stopped, in case it was started */
account_settings_view_show(ACCOUNT_VIEW(widgets->account_settings_view), FALSE);
media_settings_view_show_preview(MEDIA_SETTINGS_VIEW(widgets->media_settings_view), FALSE);
general_settings_view_show_profile(GENERAL_SETTINGS_VIEW(widgets->general_settings_view),
FALSE);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment