blob: 95474d7079953f3cc22aa5739e18b454e8b31415 [file] [log] [blame]
Stepan Salenikovich434b88f2015-02-19 17:49:08 -05001/*
Stepan Salenikovichbe87d2c2016-01-25 14:14:34 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Stepan Salenikovich434b88f2015-02-19 17:49:08 -05003 * Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Stepan Salenikovich434b88f2015-02-19 17:49:08 -050018 */
19
20#include "ringmainwindow.h"
21
Stepan Salenikovich5fd97bc2016-08-30 09:40:38 -040022// system
23#include <string.h>
24#include <memory>
25
26// GTK+ related
Stepan Salenikovicha1b8cb32015-09-11 14:58:35 -040027#include <glib/gi18n.h>
Stepan Salenikovich5fd97bc2016-08-30 09:40:38 -040028
29// Qt
30#include <QtCore/QItemSelectionModel>
31#include <QtCore/QSortFilterProxyModel>
Stepan Salenikoviche9933242016-06-21 18:08:48 -040032#include <QtCore/QDateTime>
Stepan Salenikovich5fd97bc2016-08-30 09:40:38 -040033
34// LRC
Stepan Salenikovicha3557452015-02-20 14:14:12 -050035#include <callmodel.h>
Stepan Salenikovich69771842015-02-24 18:11:45 -050036#include <call.h>
Stepan Salenikovich15142182015-03-11 17:15:26 -040037#include <contactmethod.h>
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -040038#include <accountmodel.h>
Edric Milaret58e71072016-03-21 12:16:37 -040039#include <codecmodel.h>
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040040#include <video/previewmanager.h>
Stepan Salenikovich6f687072015-03-26 10:43:37 -040041#include <personmodel.h>
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -040042#include <globalinstances.h>
Stepan Salenikovich5fd97bc2016-08-30 09:40:38 -040043#include <categorizedcontactmodel.h>
44#include <recentmodel.h>
45#include <profilemodel.h>
46#include <profile.h>
Stepan Salenikovichf53128f2016-10-07 10:32:16 -040047#include <phonedirectorymodel.h>
Stepan Salenikovich5fd97bc2016-08-30 09:40:38 -040048
49// Ring client
50#include "models/gtkqtreemodel.h"
51#include "incomingcallview.h"
52#include "currentcallview.h"
Stepan Salenikovichf6078222016-10-03 17:31:16 -040053#include "models/gtkqtreemodel.h"
Stepan Salenikovich5fd97bc2016-08-30 09:40:38 -040054#include "accountview.h"
55#include "dialogs.h"
56#include "mediasettingsview.h"
57#include "utils/drawing.h"
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -040058#include "native/pixbufmanipulator.h"
Stepan Salenikovich6f687072015-03-26 10:43:37 -040059#include "models/activeitemproxymodel.h"
Stepan Salenikovich9816a942015-04-22 17:49:16 -040060#include "utils/calling.h"
61#include "contactsview.h"
62#include "historyview.h"
63#include "utils/models.h"
Stepan Salenikovichde896112015-05-11 16:46:33 -040064#include "generalsettingsview.h"
Stepan Salenikovich75a39172015-07-10 13:21:08 -040065#include "utils/accounts.h"
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040066#include "ringwelcomeview.h"
aviau6aeb4852016-08-18 16:01:09 -040067#include "accountmigrationview.h"
68#include "accountcreationwizard.h"
Stepan Salenikovich2f8b4492015-09-21 17:10:36 -040069#include "recentcontactsview.h"
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -050070#include "chatview.h"
Nicolas Jagerb413b302016-05-06 11:41:32 -040071#include "avatarmanipulation.h"
Stepan Salenikovichba87ae22016-09-13 14:27:20 -040072#include "utils/files.h"
Nicolas Jagerb413b302016-05-06 11:41:32 -040073
Stepan Salenikovich9ffad5e2015-09-25 13:16:50 -040074static constexpr const char* CALL_VIEW_NAME = "calls";
aviau6aeb4852016-08-18 16:01:09 -040075static constexpr const char* ACCOUNT_CREATION_WIZARD_VIEW_NAME = "account-creation-wizard";
76static constexpr const char* ACCOUNT_MIGRATION_VIEW_NAME = "account-migration-view";
Stepan Salenikovich9ffad5e2015-09-25 13:16:50 -040077static constexpr const char* GENERAL_SETTINGS_VIEW_NAME = "general";
78static constexpr const char* AUDIO_SETTINGS_VIEW_NAME = "audio";
79static constexpr const char* MEDIA_SETTINGS_VIEW_NAME = "media";
80static constexpr const char* ACCOUNT_SETTINGS_VIEW_NAME = "accounts";
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040081static constexpr const char* DEFAULT_VIEW_NAME = "welcome";
Stepan Salenikovich9ffad5e2015-09-25 13:16:50 -040082static constexpr const char* VIEW_CONTACTS = "contacts";
83static constexpr const char* VIEW_HISTORY = "history";
84static constexpr const char* VIEW_PRESENCE = "presence";
Stepan Salenikovich434b88f2015-02-19 17:49:08 -050085
86struct _RingMainWindow
87{
88 GtkApplicationWindow parent;
89};
90
91struct _RingMainWindowClass
92{
93 GtkApplicationWindowClass parent_class;
94};
95
96typedef struct _RingMainWindowPrivate RingMainWindowPrivate;
97
98struct _RingMainWindowPrivate
99{
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400100 GtkWidget *ring_menu;
101 GtkWidget *image_ring;
102 GtkWidget *ring_settings;
103 GtkWidget *image_settings;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400104 GtkWidget *hbox_settings;
Stepan Salenikovich2f8b4492015-09-21 17:10:36 -0400105 GtkWidget *scrolled_window_smartview;
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400106 GtkWidget *treeview_conversations;
Stepan Salenikovicha7a19bc2015-09-24 16:16:28 -0400107 GtkWidget *scrolled_window_contacts;
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400108 GtkWidget *treeview_contacts;
Stepan Salenikovicha7a19bc2015-09-24 16:16:28 -0400109 GtkWidget *scrolled_window_history;
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400110 GtkWidget *treeview_history;
Stepan Salenikovichbbb10d82015-05-13 12:26:44 -0400111 GtkWidget *vbox_left_pane;
Stepan Salenikovich45d25aa2015-02-20 17:39:09 -0500112 GtkWidget *search_entry;
Stepan Salenikovich69771842015-02-24 18:11:45 -0500113 GtkWidget *stack_main_view;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400114 GtkWidget *vbox_call_view;
Stepan Salenikovich3034d922015-10-09 10:11:42 -0400115 GtkWidget *frame_call;
116 GtkWidget *welcome_view;
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400117 GtkWidget *button_new_conversation ;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400118 GtkWidget *account_settings_view;
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400119 GtkWidget *media_settings_view;
Stepan Salenikovichde896112015-05-11 16:46:33 -0400120 GtkWidget *general_settings_view;
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400121 GtkWidget *last_settings_view;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400122 GtkWidget *radiobutton_general_settings;
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -0400123 GtkWidget *radiobutton_media_settings;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400124 GtkWidget *radiobutton_account_settings;
aviau69081842016-10-14 14:51:54 -0400125 GtkWidget *account_creation_wizard;
126 GtkWidget *account_migration_view;
Stepan Salenikovich5eab3032015-03-28 10:50:51 -0400127
aviau039001d2016-09-29 16:39:05 -0400128 /* The webkit_chat_container is created once, then reused for all chat views */
129 GtkWidget *webkit_chat_container;
130
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400131 QMetaObject::Connection selected_item_changed;
132 QMetaObject::Connection selected_call_over;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400133
134 gboolean show_settings;
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400135
Stepan Salenikoviche1b54892015-12-13 22:18:44 -0500136 /* fullscreen */
137 gboolean is_fullscreen;
Stepan Salenikovichba87ae22016-09-13 14:27:20 -0400138
139 GSettings *settings;
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500140};
141
142G_DEFINE_TYPE_WITH_PRIVATE(RingMainWindow, ring_main_window, GTK_TYPE_APPLICATION_WINDOW);
143
144#define RING_MAIN_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), RING_MAIN_WINDOW_TYPE, RingMainWindowPrivate))
145
aviau039001d2016-09-29 16:39:05 -0400146static gboolean selection_changed(RingMainWindow *win);
147
148static WebKitChatContainer*
149get_webkit_chat_container(RingMainWindow *win)
150{
151 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
152 if (!priv->webkit_chat_container)
153 {
154 priv->webkit_chat_container = webkit_chat_container_new();
155
156 //We don't want it to be deleted, ever.
157 g_object_ref(priv->webkit_chat_container);
158 }
159 return WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container);
160}
161
Stepan Salenikovich69771842015-02-24 18:11:45 -0500162static void
Stepan Salenikoviche1b54892015-12-13 22:18:44 -0500163enter_full_screen(RingMainWindow *self)
164{
165 g_return_if_fail(IS_RING_MAIN_WINDOW(self));
166 auto priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(self));
167
168 if (!priv->is_fullscreen) {
169 gtk_widget_hide(priv->vbox_left_pane);
170 gtk_window_fullscreen(GTK_WINDOW(self));
171 priv->is_fullscreen = TRUE;
172 }
173}
174
175static void
176leave_full_screen(RingMainWindow *self)
177{
178 g_return_if_fail(IS_RING_MAIN_WINDOW(self));
179 auto priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(self));
180
181 if (priv->is_fullscreen) {
182 gtk_widget_show(priv->vbox_left_pane);
183 gtk_window_unfullscreen(GTK_WINDOW(self));
184 priv->is_fullscreen = FALSE;
185 }
186}
187
188static void
Stepan Salenikovich5e431cf2015-12-24 14:09:01 -0500189video_double_clicked(G_GNUC_UNUSED CurrentCallView *view, RingMainWindow *self)
Stepan Salenikoviche1b54892015-12-13 22:18:44 -0500190{
191 g_return_if_fail(IS_RING_MAIN_WINDOW(self));
192 auto priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(self));
193
194 if (priv->is_fullscreen) {
195 leave_full_screen(self);
196 } else {
197 enter_full_screen(self);
198 }
199}
200
Stepan Salenikovich8043a562016-03-18 13:56:40 -0400201static void
202hide_view_clicked(G_GNUC_UNUSED GtkWidget *view, RingMainWindow *self)
203{
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400204 auto priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(self));
Stepan Salenikovich8043a562016-03-18 13:56:40 -0400205
206 /* clear selection */
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400207 auto selection_conversations = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_conversations));
208 gtk_tree_selection_unselect_all(GTK_TREE_SELECTION(selection_conversations));
209 auto selection_contacts = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_contacts));
210 gtk_tree_selection_unselect_all(GTK_TREE_SELECTION(selection_contacts));
211 auto selection_history = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_history));
212 gtk_tree_selection_unselect_all(GTK_TREE_SELECTION(selection_history));
Stepan Salenikovich8043a562016-03-18 13:56:40 -0400213}
214
aviau039001d2016-09-29 16:39:05 -0400215static void
216change_view(RingMainWindow *self, GtkWidget* old, QObject *object, GType type)
217{
218 auto priv = RING_MAIN_WINDOW_GET_PRIVATE(self);
219 leave_full_screen(self);
220 gtk_container_remove(GTK_CONTAINER(priv->frame_call), old);
221
222 GtkWidget *new_view = nullptr;
223
224 QObject::disconnect(priv->selected_item_changed);
225 QObject::disconnect(priv->selected_call_over);
226
227 if (g_type_is_a(INCOMING_CALL_VIEW_TYPE, type)) {
228 if (auto call = qobject_cast<Call *>(object)) {
229 new_view = incoming_call_view_new(call, get_webkit_chat_container(self));
230 priv->selected_item_changed = QObject::connect(
231 call,
232 &Call::lifeCycleStateChanged,
233 [self] (Call::LifeCycleState, Call::LifeCycleState)
234 {g_idle_add((GSourceFunc)selection_changed, self);}
235 );
236 priv->selected_call_over = QObject::connect(
237 call,
238 &Call::isOver,
239 [self] ()
240 {g_idle_add((GSourceFunc)selection_changed, self);}
241 );
242 } else
243 g_warning("Trying to display a view of type IncomingCallView, but the object is not of type Call");
244 } else if (g_type_is_a(CURRENT_CALL_VIEW_TYPE, type)) {
245 if (auto call = qobject_cast<Call *>(object)) {
246 new_view = current_call_view_new(call, get_webkit_chat_container(self));
247 g_signal_connect(new_view, "video-double-clicked", G_CALLBACK(video_double_clicked), self);
248 priv->selected_item_changed = QObject::connect(
249 call,
250 &Call::lifeCycleStateChanged,
251 [self] (Call::LifeCycleState, Call::LifeCycleState)
252 {g_idle_add((GSourceFunc)selection_changed, self);}
253 );
254 priv->selected_call_over = QObject::connect(
255 call,
256 &Call::isOver,
257 [self] ()
258 {g_idle_add((GSourceFunc)selection_changed, self);}
259 );
260 } else
261 g_warning("Trying to display a view of type CurrentCallView, but the object is not of type Call");
262 } else if (g_type_is_a(CHAT_VIEW_TYPE, type)) {
263 if (auto person = qobject_cast<Person *>(object)) {
264 new_view = chat_view_new_person(get_webkit_chat_container(self), person);
265 g_signal_connect(new_view, "hide-view-clicked", G_CALLBACK(hide_view_clicked), self);
266
267 /* connect to the Person's callAdded signal, because we want to switch to the call view
268 * in this case */
269 priv->selected_item_changed = QObject::connect(
270 person,
271 &Person::callAdded,
272 [self] (Call*)
273 {g_idle_add((GSourceFunc)selection_changed, self);}
274 );
275 } else if (auto cm = qobject_cast<ContactMethod *>(object)) {
276 new_view = chat_view_new_cm(get_webkit_chat_container(self), cm);
277 g_signal_connect(new_view, "hide-view-clicked", G_CALLBACK(hide_view_clicked), self);
278
279 /* connect to the ContactMethod's callAdded signal, because we want to switch to the
280 * call view in this case */
281 priv->selected_item_changed = QObject::connect(
282 cm,
283 &ContactMethod::callAdded,
284 [self] (Call*)
285 {g_idle_add((GSourceFunc)selection_changed, self);}
286 );
287 } else {
288 g_warning("Trying to display a veiw of type ChatView, but the object is neither a Person nor a ContactMethod");
289 }
290 } else {
291 // display the welcome view
292 new_view = priv->welcome_view;
293 }
294
295 gtk_container_add(GTK_CONTAINER(priv->frame_call), new_view);
296 gtk_widget_show(new_view);
297}
298
Stepan Salenikovichc1323422016-01-06 10:54:44 -0500299/**
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400300 * This function determines which view to display in the right panel of the main window based on
301 * which item is selected in one of the 3 contact list views (Conversations, Contacts, History). The
302 * possible views ares:
Stepan Salenikovichc1323422016-01-06 10:54:44 -0500303 * - incoming call view
304 * - current call view
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500305 * - chat view
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400306 * - welcome view (if no valid item is selected)
307 *
308 * There should never be a conflict of which item should be displayed (ie: which item is selected),
309 * as there should only ever be one selection at a time in the 3 views except in the case that the
310 * same item is selected in more than one view (see the compare_treeview_selection() function).
311 *
312 * This function could be called from a g_idle source, so it returns a boolean to remove itself from
313 * being called again. The boolean doesn't reflect success nor failure.
Stepan Salenikovichc1323422016-01-06 10:54:44 -0500314 */
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400315static gboolean
316selection_changed(RingMainWindow *win)
Stepan Salenikovich69771842015-02-24 18:11:45 -0500317{
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500318 // g_debug("selection changed");
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400319
320 g_return_val_if_fail(IS_RING_MAIN_WINDOW(win), G_SOURCE_REMOVE);
Stepan Salenikovich69771842015-02-24 18:11:45 -0500321 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(win));
322
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400323 auto old_view = gtk_bin_get_child(GTK_BIN(priv->frame_call));
Stepan Salenikovichbd4b3772015-12-13 23:28:06 -0500324
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400325 /* if we're showing the settings, then we need to make sure to remove any possible ongoing call
326 * view so that we don't have more than one VideoWidget at a time */
327 if (priv->show_settings) {
328 if (old_view != priv->welcome_view) {
329 leave_full_screen(win);
330 gtk_container_remove(GTK_CONTAINER(priv->frame_call), old_view);
331 gtk_container_add(GTK_CONTAINER(priv->frame_call), priv->welcome_view);
332 gtk_widget_show(priv->welcome_view);
333 }
334 return G_SOURCE_REMOVE;
335 }
Stepan Salenikovich69771842015-02-24 18:11:45 -0500336
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400337 /* there should only be one item selected at a time, get which one is selected */
338 auto selection_conversations = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_conversations));
339 auto selection_contacts = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_contacts));
340 auto selection_history = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_history));
341
342 GtkTreeModel *model = nullptr;
343 GtkTreeIter iter;
344 QModelIndex idx;
345
346 if (gtk_tree_selection_get_selected(selection_conversations, &model, &iter)) {
Stepan Salenikovichf6078222016-10-03 17:31:16 -0400347 idx = gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter);
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400348 } else if (gtk_tree_selection_get_selected(selection_contacts, &model, &iter)) {
Stepan Salenikovichf6078222016-10-03 17:31:16 -0400349 idx = gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter);
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400350 } else if (gtk_tree_selection_get_selected(selection_history, &model, &iter)) {
Stepan Salenikovichf6078222016-10-03 17:31:16 -0400351 idx = gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter);
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400352 }
Stepan Salenikoviche1b54892015-12-13 22:18:44 -0500353
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500354 /* check which object type is selected */
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400355 auto type = idx.data(static_cast<int>(Ring::Role::ObjectType));
356 auto object = idx.data(static_cast<int>(Ring::Role::Object));
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500357
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400358 if (idx.isValid() && type.isValid() && object.isValid()) {
Stepan Salenikovich69771842015-02-24 18:11:45 -0500359
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400360 /* we prioritize the views in the following order:
361 * - call view (if there is an ongoing call associated with the item)
362 * - chat view built from Person
363 * - chat view built from ContactMethod
364 */
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500365
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400366 Person *person = nullptr;
367 ContactMethod *cm = nullptr;
368 Call *call = nullptr;
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500369
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400370 /* use the RecentModel to see if there are any ongoing calls associated with the selected item */
371 switch(type.value<Ring::ObjectType>()) {
372 case Ring::ObjectType::Person:
373 {
374 person = object.value<Person *>();
375 auto recent_idx = RecentModel::instance().getIndex(person);
376 if (recent_idx.isValid()) {
377 call = RecentModel::instance().getActiveCall(recent_idx);
378 }
379 }
380 break;
381 case Ring::ObjectType::ContactMethod:
382 {
383 cm = object.value<ContactMethod *>();
384 auto recent_idx = RecentModel::instance().getIndex(cm);
385 if (recent_idx.isValid()) {
386 call = RecentModel::instance().getActiveCall(recent_idx);
387 }
388 }
389 break;
390 case Ring::ObjectType::Call:
391 {
392 /* if the call is over (eg: if it comes from the history model) then we first check
393 * if there is an ongoing call with the same ContactMethod, otherwise we need to get
394 * the associated Person or ContactMethod */
395 call = object.value<Call *>();
396 if (call->isHistory()) {
397 cm = call->peerContactMethod();
398 call = nullptr;
399 if (cm) {
400 auto recent_idx = RecentModel::instance().getIndex(cm);
401 if (recent_idx.isValid()) {
402 call = RecentModel::instance().getActiveCall(recent_idx);
403 }
404 person = cm->contact();
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500405 }
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500406 }
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400407 }
408 break;
409 case Ring::ObjectType::Media:
410 case Ring::ObjectType::Certificate:
411 case Ring::ObjectType::COUNT__:
412 // nothing to do
413 break;
414 }
415
416 /* we prioritize showing the call view */
417 if (call) {
418 auto state = call->lifeCycleState();
419
420 Call *current_call = nullptr;
421
422 switch(state) {
423 case Call::LifeCycleState::CREATION:
424 case Call::LifeCycleState::INITIALIZATION:
425 case Call::LifeCycleState::FINISHED:
426 // check if we're already displaying this call
427 if (IS_INCOMING_CALL_VIEW(old_view))
428 current_call = incoming_call_view_get_call(INCOMING_CALL_VIEW(old_view));
429 if (current_call != call)
aviau039001d2016-09-29 16:39:05 -0400430 change_view(win, old_view, call, INCOMING_CALL_VIEW_TYPE);
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400431 break;
432 case Call::LifeCycleState::PROGRESS:
433 // check if we're already displaying this call
434 if (IS_CURRENT_CALL_VIEW(old_view))
435 current_call = current_call_view_get_call(CURRENT_CALL_VIEW(old_view));
aviau039001d2016-09-29 16:39:05 -0400436 if (current_call != call)
437 change_view(win, old_view, call, CURRENT_CALL_VIEW_TYPE);
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400438 break;
439 case Call::LifeCycleState::COUNT__:
440 g_warning("LifeCycleState should never be COUNT");
441 break;
442 }
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500443
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400444 } else if (person) {
445 /* show chat view constructed from Person object */
446
447 // check if we're already displaying the chat view for this person
448 Person *current_person = nullptr;
449 if (IS_CHAT_VIEW(old_view))
450 current_person = chat_view_get_person(CHAT_VIEW(old_view));
451
aviau039001d2016-09-29 16:39:05 -0400452 if (current_person != person)
453 change_view(win, old_view, person, CHAT_VIEW_TYPE);
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400454 } else if (cm) {
455 /* show chat view constructed from CM */
456
457 // check if we're already displaying the chat view for this cm
458 ContactMethod *current_cm = nullptr;
459 if (IS_CHAT_VIEW(old_view))
460 current_cm = chat_view_get_cm(CHAT_VIEW(old_view));
461
aviau039001d2016-09-29 16:39:05 -0400462 if (current_cm != cm)
463 change_view(win, old_view, cm, CHAT_VIEW_TYPE);
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400464 } else {
465 /* not a supported object type, display the welcome view */
aviau039001d2016-09-29 16:39:05 -0400466 if (old_view != priv->welcome_view)
467 change_view(win, old_view, nullptr, RING_WELCOME_VIEW_TYPE);
Stepan Salenikovichc6a3b982016-01-11 18:11:39 -0500468 }
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400469 } else {
470 /* selection isn't valid, display the welcome view */
aviau039001d2016-09-29 16:39:05 -0400471 if (old_view != priv->welcome_view)
472 change_view(win, old_view, nullptr, RING_WELCOME_VIEW_TYPE);
Stepan Salenikovich69771842015-02-24 18:11:45 -0500473 }
Stepan Salenikovich504f7722016-01-20 17:10:45 -0500474
475 return G_SOURCE_REMOVE;
Stepan Salenikovich69771842015-02-24 18:11:45 -0500476}
477
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500478static void
Stepan Salenikovichb0ffc342016-10-13 13:10:55 -0400479search_entry_activated(RingMainWindow *self)
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500480{
Stepan Salenikovichb0ffc342016-10-13 13:10:55 -0400481 auto priv = RING_MAIN_WINDOW_GET_PRIVATE(self);
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500482
Stepan Salenikovichb0ffc342016-10-13 13:10:55 -0400483 const auto *number_entered = gtk_entry_get_text(GTK_ENTRY(priv->search_entry));
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500484
Stepan Salenikovich895a70b2015-03-27 16:02:27 -0400485 if (number_entered && strlen(number_entered) > 0) {
Stepan Salenikovich5fd97bc2016-08-30 09:40:38 -0400486 auto cm = PhoneDirectoryModel::instance().getNumber(number_entered);
Stepan Salenikovich895a70b2015-03-27 16:02:27 -0400487
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400488 if (g_settings_get_boolean(priv->settings, "search-entry-places-call")) {
489 place_new_call(cm);
Stepan Salenikovich895a70b2015-03-27 16:02:27 -0400490
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400491 /* move focus away from entry so that DTMF tones can be entered via the keyboard */
492 gtk_widget_child_focus(GTK_WIDGET(self), GTK_DIR_TAB_FORWARD);
493 } else {
494 // if its a new CM, bring it to the top
495 if (cm->lastUsed() == 0)
496 cm->setLastUsed(QDateTime::currentDateTime().toTime_t());
Stepan Salenikovich1564bba2015-04-29 11:28:43 -0400497
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400498 // select cm
499 RecentModel::instance().selectionModel()->setCurrentIndex(RecentModel::instance().getIndex(cm), QItemSelectionModel::ClearAndSelect);
500 }
Stepan Salenikovichb0ffc342016-10-13 13:10:55 -0400501 gtk_entry_set_text(GTK_ENTRY(priv->search_entry), "");
Stepan Salenikovich2e6ab562015-05-07 12:33:07 -0400502 }
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500503}
504
Stepan Salenikovich7c71bfe2015-05-13 18:08:09 -0400505static gboolean
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400506save_accounts(GtkWidget *working_dialog)
507{
508 /* save changes to accounts */
Guillaume Roguez5d1514b2015-10-22 15:55:31 -0400509 AccountModel::instance().save();
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400510
511 if (working_dialog)
512 gtk_widget_destroy(working_dialog);
513
514 return G_SOURCE_REMOVE;
515}
516
Stepan Salenikovich15142182015-03-11 17:15:26 -0400517static void
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400518settings_clicked(G_GNUC_UNUSED GtkButton *button, RingMainWindow *win)
519{
520 g_return_if_fail(IS_RING_MAIN_WINDOW(win));
521 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
522
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400523 /* check which view to show */
Stepan Salenikovichbd4b3772015-12-13 23:28:06 -0500524 if (!priv->show_settings) {
525 /* show the settings */
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400526 priv->show_settings = TRUE;
Stepan Salenikovichbd4b3772015-12-13 23:28:06 -0500527
Stepan Salenikovichc1323422016-01-06 10:54:44 -0500528 /* make sure we are not showing a call view so we don't have more than one clutter stage at a time */
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400529 selection_changed(win);
Stepan Salenikovichbd4b3772015-12-13 23:28:06 -0500530
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400531 /* show settings */
Stepan Salenikovichd61974b2016-03-18 16:36:27 -0400532 gtk_image_set_from_icon_name(GTK_IMAGE(priv->image_settings), "emblem-ok-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400533
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400534 gtk_widget_show(priv->hbox_settings);
535
Stepan Salenikovich41118912015-05-01 11:25:46 -0400536 /* make sure to start preview if we're showing the video settings */
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400537 if (priv->last_settings_view == priv->media_settings_view)
538 media_settings_view_show_preview(MEDIA_SETTINGS_VIEW(priv->media_settings_view), TRUE);
Stepan Salenikovich41118912015-05-01 11:25:46 -0400539
Nicolas Jager6f5e04a2016-05-18 15:04:59 -0400540 /* make sure to show the profile if we're showing the general settings */
541 if (priv->last_settings_view == priv->general_settings_view)
542 general_settings_view_show_profile(GENERAL_SETTINGS_VIEW(priv->general_settings_view), TRUE);
543
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400544 gtk_stack_set_transition_type(GTK_STACK(priv->stack_main_view), GTK_STACK_TRANSITION_TYPE_SLIDE_UP);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400545 gtk_stack_set_visible_child(GTK_STACK(priv->stack_main_view), priv->last_settings_view);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400546 } else {
Stepan Salenikovichbd4b3772015-12-13 23:28:06 -0500547 /* hide the settings */
548 priv->show_settings = FALSE;
549
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400550 /* show working dialog in case save operation takes time */
551 GtkWidget *working = ring_dialog_working(GTK_WIDGET(win), NULL);
552 gtk_window_present(GTK_WINDOW(working));
553
554 /* now save after the time it takes to transition back to the call view (400ms)
555 * the save doesn't happen before the "working" dialog is presented
556 * the timeout function should destroy the "working" dialog when done saving
557 */
Stepan Salenikovich12fee942015-03-25 18:38:47 -0400558 g_timeout_add_full(G_PRIORITY_DEFAULT, 400, (GSourceFunc)save_accounts, working, NULL);
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400559
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400560 /* show calls */
Stepan Salenikovichd61974b2016-03-18 16:36:27 -0400561 gtk_image_set_from_icon_name(GTK_IMAGE(priv->image_settings), "emblem-system-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400562
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400563 gtk_widget_hide(priv->hbox_settings);
564
Stepan Salenikovichbd4b3772015-12-13 23:28:06 -0500565 /* make sure video preview is stopped, in case it was started */
566 media_settings_view_show_preview(MEDIA_SETTINGS_VIEW(priv->media_settings_view), FALSE);
Nicolas Jager6f5e04a2016-05-18 15:04:59 -0400567 general_settings_view_show_profile(GENERAL_SETTINGS_VIEW(priv->general_settings_view), FALSE);
Stepan Salenikovichbd4b3772015-12-13 23:28:06 -0500568
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400569 gtk_stack_set_transition_type(GTK_STACK(priv->stack_main_view), GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN);
570 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_main_view), CALL_VIEW_NAME);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400571
Stepan Salenikovichc1323422016-01-06 10:54:44 -0500572 /* show the view which was selected previously */
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400573 selection_changed(win);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400574 }
575}
576
577static void
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -0400578show_media_settings(GtkToggleButton *navbutton, RingMainWindow *win)
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400579{
580 g_return_if_fail(IS_RING_MAIN_WINDOW(win));
581 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
582
583 if (gtk_toggle_button_get_active(navbutton)) {
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400584 media_settings_view_show_preview(MEDIA_SETTINGS_VIEW(priv->media_settings_view), TRUE);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400585 gtk_stack_set_transition_type(GTK_STACK(priv->stack_main_view), GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -0400586 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_main_view), MEDIA_SETTINGS_VIEW_NAME);
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400587 priv->last_settings_view = priv->media_settings_view;
Stepan Salenikovich41118912015-05-01 11:25:46 -0400588 } else {
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400589 media_settings_view_show_preview(MEDIA_SETTINGS_VIEW(priv->media_settings_view), FALSE);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400590 }
591}
592
593static void
594show_account_settings(GtkToggleButton *navbutton, RingMainWindow *win)
595{
596 g_return_if_fail(IS_RING_MAIN_WINDOW(win));
597 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
598
599 if (gtk_toggle_button_get_active(navbutton)) {
600 gtk_stack_set_transition_type(GTK_STACK(priv->stack_main_view), GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
601 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_main_view), ACCOUNT_SETTINGS_VIEW_NAME);
602 priv->last_settings_view = priv->account_settings_view;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400603 }
604}
605
Stepan Salenikovichde896112015-05-11 16:46:33 -0400606static void
607show_general_settings(GtkToggleButton *navbutton, RingMainWindow *win)
608{
609 g_return_if_fail(IS_RING_MAIN_WINDOW(win));
610 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
611
612 if (gtk_toggle_button_get_active(navbutton)) {
Nicolas Jager6f5e04a2016-05-18 15:04:59 -0400613 general_settings_view_show_profile(GENERAL_SETTINGS_VIEW(priv->general_settings_view), TRUE);
Stepan Salenikovichde896112015-05-11 16:46:33 -0400614 gtk_stack_set_transition_type(GTK_STACK(priv->stack_main_view), GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
615 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_main_view), GENERAL_SETTINGS_VIEW_NAME);
616 priv->last_settings_view = priv->general_settings_view;
Nicolas Jager6f5e04a2016-05-18 15:04:59 -0400617 } else {
618 general_settings_view_show_profile(GENERAL_SETTINGS_VIEW(priv->general_settings_view), FALSE);
Stepan Salenikovichde896112015-05-11 16:46:33 -0400619 }
620}
621
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400622static void
aviau6aeb4852016-08-18 16:01:09 -0400623on_account_creation_completed(RingMainWindow *win)
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400624{
Stepan Salenikovichbabe26f2016-02-12 16:47:07 -0500625 g_return_if_fail(IS_RING_MAIN_WINDOW(win));
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400626 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
627
aviau6aeb4852016-08-18 16:01:09 -0400628 gtk_stack_set_transition_type(GTK_STACK(priv->stack_main_view), GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT);
629 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_main_view), CALL_VIEW_NAME);
630
631 /* destroy the wizard */
aviau69081842016-10-14 14:51:54 -0400632 if (priv->account_creation_wizard)
aviau6aeb4852016-08-18 16:01:09 -0400633 {
aviau69081842016-10-14 14:51:54 -0400634 gtk_container_remove(GTK_CONTAINER(priv->stack_main_view), priv->account_creation_wizard);
635 gtk_widget_destroy(priv->account_creation_wizard);
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400636 }
aviau6aeb4852016-08-18 16:01:09 -0400637
638 /* show the settings button*/
639 gtk_widget_show(priv->ring_settings);
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400640}
641
642static void
aviau6aeb4852016-08-18 16:01:09 -0400643show_account_creation_wizard(RingMainWindow *win)
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400644{
645 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
646
aviau61d05b32016-10-18 16:47:53 -0400647 if (!priv->account_creation_wizard)
aviau6aeb4852016-08-18 16:01:09 -0400648 {
aviau69081842016-10-14 14:51:54 -0400649 priv->account_creation_wizard = account_creation_wizard_new(false);
650 g_object_add_weak_pointer(G_OBJECT(priv->account_creation_wizard), (gpointer *)&priv->account_creation_wizard);
651 g_signal_connect_swapped(priv->account_creation_wizard, "account-creation-completed", G_CALLBACK(on_account_creation_completed), win);
Stepan Salenikovich419414c2016-06-07 10:35:07 -0400652
aviau6aeb4852016-08-18 16:01:09 -0400653 gtk_stack_add_named(GTK_STACK(priv->stack_main_view),
aviau69081842016-10-14 14:51:54 -0400654 priv->account_creation_wizard,
aviau6aeb4852016-08-18 16:01:09 -0400655 ACCOUNT_CREATION_WIZARD_VIEW_NAME);
656 }
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400657
Stepan Salenikovich64505672015-09-24 10:46:07 -0400658 /* hide settings button until account creation is complete */
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400659 gtk_widget_hide(priv->ring_settings);
660
aviau69081842016-10-14 14:51:54 -0400661 gtk_widget_show(priv->account_creation_wizard);
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400662
aviau69081842016-10-14 14:51:54 -0400663 gtk_stack_set_visible_child(GTK_STACK(priv->stack_main_view), priv->account_creation_wizard);
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400664}
665
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400666static void
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -0400667search_entry_text_changed(GtkEditable *search_entry, RingMainWindow *self)
Stepan Salenikovicheafc3dd2015-04-16 18:38:01 -0400668{
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -0400669 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(self);
670
Stepan Salenikovicheafc3dd2015-04-16 18:38:01 -0400671 /* get the text from the entry */
672 const gchar *text = gtk_entry_get_text(GTK_ENTRY(search_entry));
673
Stepan Salenikovichf53128f2016-10-07 10:32:16 -0400674 RecentModel::instance().peopleProxy()->setFilterRegExp(QRegExp(text, Qt::CaseInsensitive, QRegExp::FixedString));
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -0400675 contacts_view_set_filter_string(CONTACTS_VIEW(priv->treeview_contacts), text);
676 history_view_set_filter_string(HISTORY_VIEW(priv->treeview_history), text);
Stepan Salenikovicheafc3dd2015-04-16 18:38:01 -0400677}
678
Stepan Salenikovichb01d7362015-04-27 23:02:00 -0400679static gboolean
680dtmf_pressed(RingMainWindow *win,
681 GdkEventKey *event,
682 G_GNUC_UNUSED gpointer user_data)
683{
684 g_return_val_if_fail(event->type == GDK_KEY_PRESS, GDK_EVENT_PROPAGATE);
685
686 /* we want to react to digit key presses, as long as a GtkEntry is not the
687 * input focus
688 */
689 GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(win));
690 if (GTK_IS_ENTRY(focus))
691 return GDK_EVENT_PROPAGATE;
692
693 /* make sure that a call is selected*/
Guillaume Roguez5d1514b2015-10-22 15:55:31 -0400694 QItemSelectionModel *selection = CallModel::instance().selectionModel();
Stepan Salenikovichb01d7362015-04-27 23:02:00 -0400695 QModelIndex idx = selection->currentIndex();
696 if (!idx.isValid())
697 return GDK_EVENT_PROPAGATE;
698
699 /* make sure that the selected call is in progress */
Guillaume Roguez5d1514b2015-10-22 15:55:31 -0400700 Call *call = CallModel::instance().getCall(idx);
Stepan Salenikovichb01d7362015-04-27 23:02:00 -0400701 Call::LifeCycleState state = call->lifeCycleState();
702 if (state != Call::LifeCycleState::PROGRESS)
703 return GDK_EVENT_PROPAGATE;
704
Stepan Salenikovich447f4a72015-04-29 11:09:28 -0400705 /* filter out cretain MOD masked key presses so that, for example, 'Ctrl+c'
706 * does not result in a 'c' being played.
707 * we filter Ctrl, Alt, and SUPER/HYPER/META keys */
708 if ( event->state
709 & ( GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK ))
710 return GDK_EVENT_PROPAGATE;
711
Stepan Salenikovichb01d7362015-04-27 23:02:00 -0400712 /* pass the character that was entered to be played by the daemon;
713 * the daemon will filter out invalid DTMF characters */
714 guint32 unicode_val = gdk_keyval_to_unicode(event->keyval);
715 QString val = QString::fromUcs4(&unicode_val, 1);
716 call->playDTMF(val);
717 g_debug("attemptingto play DTMF tone during ongoing call: %s", val.toUtf8().constData());
Stepan Salenikovich447f4a72015-04-29 11:09:28 -0400718
719 /* always propogate the key, so we don't steal accelerators/shortcuts */
720 return GDK_EVENT_PROPAGATE;
Stepan Salenikovichb01d7362015-04-27 23:02:00 -0400721}
722
Stepan Salenikovich09e0b782016-09-07 16:28:50 -0400723/**
724 * This function determines if two different contact list views (Conversations, Contacts, History)
725 * have the same item selected. Note that the same item does not necessarily mean the same object.
726 * For example, if the history view has a Call selected and the Conversations view has a Person
727 * selected which is associated with the ContactMethod to which that Call was made, then this will
728 * evaluate to TRUE.
729 */
730static gboolean
731compare_treeview_selection(GtkTreeSelection *selection1, GtkTreeSelection *selection2)
732{
733 g_return_val_if_fail(selection1 && selection2, FALSE);
734
735 if (selection1 == selection2) return TRUE;
736
737 auto idx1 = get_index_from_selection(selection1);
738 auto type1 = idx1.data(static_cast<int>(Ring::Role::ObjectType));
739 auto object1 = idx1.data(static_cast<int>(Ring::Role::Object));
740
741 auto idx2 = get_index_from_selection(selection2);
742 auto type2 = idx2.data(static_cast<int>(Ring::Role::ObjectType));
743 auto object2 = idx2.data(static_cast<int>(Ring::Role::Object));
744
745 if (idx1.isValid() && type1.isValid() && object1.isValid() && idx2.isValid() && type2.isValid() && object2.isValid()) {
746 Call *call1 = nullptr;
747 ContactMethod *cm1 = nullptr;
748 Person *person1 = nullptr;
749
750 Call *call2 = nullptr;
751 ContactMethod *cm2 = nullptr;
752 Person *person2 = nullptr;
753
754 switch(type1.value<Ring::ObjectType>()) {
755 case Ring::ObjectType::Person:
756 person1 = object1.value<Person *>();
757 break;
758 case Ring::ObjectType::ContactMethod:
759 cm1 = object1.value<ContactMethod *>();
760 person1 = cm1->contact();
761 break;
762 case Ring::ObjectType::Call:
763 call1 = object1.value<Call *>();
764 cm1 = call1->peerContactMethod();
765 person1 = cm1->contact();
766 break;
767 case Ring::ObjectType::Media:
768 case Ring::ObjectType::Certificate:
769 case Ring::ObjectType::COUNT__:
770 // nothing to do
771 break;
772 }
773
774 switch(type2.value<Ring::ObjectType>()) {
775 case Ring::ObjectType::Person:
776 person2 = object2.value<Person *>();
777 break;
778 case Ring::ObjectType::ContactMethod:
779 cm2 = object2.value<ContactMethod *>();
780 person2 = cm2->contact();
781 break;
782 case Ring::ObjectType::Call:
783 call2 = object2.value<Call *>();
784 cm2 = call2->peerContactMethod();
785 person2 = cm2->contact();
786 break;
787 case Ring::ObjectType::Media:
788 case Ring::ObjectType::Certificate:
789 case Ring::ObjectType::COUNT__:
790 // nothing to do
791 break;
792 }
793
794 if (person1 != nullptr && person1 == person2)
795 return TRUE;
796 if (cm1 != nullptr && cm1 == cm2)
797 return TRUE;
798 if (call1 != nullptr && call1 == call2)
799 return TRUE;
800 }
801
802 return FALSE;
803}
804
805static void
806conversation_selection_changed(GtkTreeSelection *selection, RingMainWindow *self)
807{
808 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(self);
809 GtkTreeIter iter;
810 GtkTreeModel *model = nullptr;
811 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
812 /* something is selected in the conversations view, clear the selection in the other views;
813 * unless the current selection is of the same item; we don't try to match the selection in
814 * all views since not all items exist in all 3 contact list views
815 */
816
817 auto selection_contacts = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_contacts));
818 if (!compare_treeview_selection(selection, selection_contacts))
819 gtk_tree_selection_unselect_all(GTK_TREE_SELECTION(selection_contacts));
820
821 auto selection_history = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_history));
822 if (!compare_treeview_selection(selection, selection_history))
823 gtk_tree_selection_unselect_all(GTK_TREE_SELECTION(selection_history));
824 }
825
826 selection_changed(self);
827}
828
829static void
830contact_selection_changed(GtkTreeSelection *selection, RingMainWindow *self)
831{
832 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(self);
833 GtkTreeIter iter;
834 if (gtk_tree_selection_get_selected(selection, nullptr, &iter)) {
835 /* something is selected in the contacts view, clear the selection in the other views;
836 * unless the current selection is of the same item; we don't try to match the selection in
837 * all views since not all items exist in all 3 contact list views
838 */
839 auto selection_conversations = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_conversations));
840 if (!compare_treeview_selection(selection, selection_conversations))
841 gtk_tree_selection_unselect_all(GTK_TREE_SELECTION(selection_conversations));
842
843 auto selection_history = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_history));
844 if (!compare_treeview_selection(selection, selection_history))
845 gtk_tree_selection_unselect_all(GTK_TREE_SELECTION(selection_history));
846 }
847
848 selection_changed(self);
849}
850
851static void
852history_selection_changed(GtkTreeSelection *selection, RingMainWindow *self)
853{
854 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(self);
855 GtkTreeIter iter;
856 if (gtk_tree_selection_get_selected(selection, nullptr, &iter)) {
857 /* something is selected in the history view, clear the selection in the other views;
858 * unless the current selection is of the same item; we don't try to match the selection in
859 * all views since not all items exist in all 3 contact list views
860 */
861
862 auto selection_conversations = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_conversations));
863 if (!compare_treeview_selection(selection, selection_conversations))
864 gtk_tree_selection_unselect_all(GTK_TREE_SELECTION(selection_conversations));
865
866 auto selection_contacts = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_contacts));
867 if (!compare_treeview_selection(selection, selection_contacts))
868 gtk_tree_selection_unselect_all(GTK_TREE_SELECTION(selection_contacts));
869 }
870
871 selection_changed(self);
872}
873
Stepan Salenikovichba87ae22016-09-13 14:27:20 -0400874static gboolean
875window_size_changed(GtkWidget *win, GdkEventConfigure *event, gpointer)
876{
877 auto *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
878
879 g_settings_set_int(priv->settings, "window-width", event->width);
880 g_settings_set_int(priv->settings, "window-height", event->height);
881
882 return GDK_EVENT_PROPAGATE;
883}
884
Stepan Salenikovicheafc3dd2015-04-16 18:38:01 -0400885static void
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400886search_entry_places_call_changed(GSettings *settings, const gchar *key, RingMainWindow *self)
887{
888 auto priv = RING_MAIN_WINDOW_GET_PRIVATE(self);
889
890 if (g_settings_get_boolean(settings, key)) {
891 gtk_widget_set_tooltip_text(priv->button_new_conversation, C_("button next to search entry will place a new call", "place call"));
892 } else {
893 gtk_widget_set_tooltip_text(priv->button_new_conversation, C_("button next to search entry will open chat", "open chat"));
894 }
895}
896
897static void
aviau6aeb4852016-08-18 16:01:09 -0400898handle_account_migrations(RingMainWindow *win)
899{
900 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
901
902 /* If there is an existing migration view, remove it */
aviau69081842016-10-14 14:51:54 -0400903 if (priv->account_migration_view)
aviau6aeb4852016-08-18 16:01:09 -0400904 {
Stepan Salenikovich56530b12016-10-20 17:51:34 -0400905 gtk_widget_destroy(priv->account_migration_view);
906 priv->account_migration_view = nullptr;
aviau6aeb4852016-08-18 16:01:09 -0400907 }
908
909 QList<Account*> accounts = AccountModel::instance().accountsToMigrate();
910 if (!accounts.isEmpty())
911 {
912 Account* account = accounts.first();
aviau6aeb4852016-08-18 16:01:09 -0400913
aviau69081842016-10-14 14:51:54 -0400914 priv->account_migration_view = account_migration_view_new(account);
aviau69081842016-10-14 14:51:54 -0400915 g_signal_connect_swapped(priv->account_migration_view, "account-migration-completed", G_CALLBACK(handle_account_migrations), win);
916 g_signal_connect_swapped(priv->account_migration_view, "account-migration-failed", G_CALLBACK(handle_account_migrations), win);
aviau6aeb4852016-08-18 16:01:09 -0400917
918 gtk_widget_hide(priv->ring_settings);
aviau69081842016-10-14 14:51:54 -0400919 gtk_widget_show(priv->account_migration_view);
aviau6aeb4852016-08-18 16:01:09 -0400920 gtk_stack_add_named(
921 GTK_STACK(priv->stack_main_view),
aviau69081842016-10-14 14:51:54 -0400922 priv->account_migration_view,
aviau6aeb4852016-08-18 16:01:09 -0400923 ACCOUNT_MIGRATION_VIEW_NAME
924 );
925 gtk_stack_set_visible_child_name(
926 GTK_STACK(priv->stack_main_view),
927 ACCOUNT_MIGRATION_VIEW_NAME
928 );
929 }
930 else
931 {
932 gtk_widget_show(priv->ring_settings);
933 }
934}
935
936static void
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500937ring_main_window_init(RingMainWindow *win)
938{
939 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
940 gtk_widget_init_template(GTK_WIDGET(win));
941
Stepan Salenikovichba87ae22016-09-13 14:27:20 -0400942 /* bind to window size settings */
943 priv->settings = g_settings_new_full(get_ring_schema(), nullptr, nullptr);
944 auto width = g_settings_get_int(priv->settings, "window-width");
945 auto height = g_settings_get_int(priv->settings, "window-height");
946 gtk_window_set_default_size(GTK_WINDOW(win), width, height);
947 g_signal_connect(win, "configure-event", G_CALLBACK(window_size_changed), nullptr);
948
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400949 /* search-entry-places-call setting */
950 search_entry_places_call_changed(priv->settings, "search-entry-places-call", win);
951 g_signal_connect(priv->settings, "changed::search-entry-places-call", G_CALLBACK(search_entry_places_call_changed), win);
952
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500953 /* set window icon */
954 GError *error = NULL;
955 GdkPixbuf* icon = gdk_pixbuf_new_from_resource("/cx/ring/RingGnome/ring-symbol-blue", &error);
956 if (icon == NULL) {
957 g_debug("Could not load icon: %s", error->message);
Stepan Salenikovich8a287fc2015-05-01 16:53:20 -0400958 g_clear_error(&error);
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500959 } else
960 gtk_window_set_icon(GTK_WINDOW(win), icon);
961
962 /* set menu icon */
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400963 GdkPixbuf* image_ring = gdk_pixbuf_new_from_resource_at_scale("/cx/ring/RingGnome/ring-symbol-blue",
Stepan Salenikovichd61974b2016-03-18 16:36:27 -0400964 -1, 16, TRUE, &error);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400965 if (image_ring == NULL) {
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500966 g_debug("Could not load icon: %s", error->message);
Stepan Salenikovich8a287fc2015-05-01 16:53:20 -0400967 g_clear_error(&error);
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500968 } else
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400969 gtk_image_set_from_pixbuf(GTK_IMAGE(priv->image_ring), image_ring);
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500970
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400971 /* ring menu */
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500972 GtkBuilder *builder = gtk_builder_new_from_resource("/cx/ring/RingGnome/ringgearsmenu.ui");
973 GMenuModel *menu = G_MENU_MODEL(gtk_builder_get_object(builder, "menu"));
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400974 gtk_menu_button_set_menu_model(GTK_MENU_BUTTON(priv->ring_menu), menu);
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500975 g_object_unref(builder);
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500976
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400977 /* settings icon */
Stepan Salenikovichd61974b2016-03-18 16:36:27 -0400978 gtk_image_set_from_icon_name(GTK_IMAGE(priv->image_settings), "emblem-system-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400979
980 /* connect settings button signal */
981 g_signal_connect(priv->ring_settings, "clicked", G_CALLBACK(settings_clicked), win);
982
983 /* add the call view to the main stack */
984 gtk_stack_add_named(GTK_STACK(priv->stack_main_view),
985 priv->vbox_call_view,
986 CALL_VIEW_NAME);
987
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400988 if (has_ring_account()) {
989 /* user has ring account, so show the call view right away */
990 gtk_stack_set_visible_child(GTK_STACK(priv->stack_main_view), priv->vbox_call_view);
991 } else {
992 /* user has to create the ring account */
aviau6aeb4852016-08-18 16:01:09 -0400993 show_account_creation_wizard(win);
Stepan Salenikovichb8e41272015-03-27 14:31:54 -0400994 }
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400995
996 /* init the settings views */
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400997 priv->account_settings_view = account_view_new();
998 gtk_stack_add_named(GTK_STACK(priv->stack_main_view), priv->account_settings_view, ACCOUNT_SETTINGS_VIEW_NAME);
999
Stepan Salenikovich0bd53492015-05-11 14:28:52 -04001000 priv->media_settings_view = media_settings_view_new();
1001 gtk_stack_add_named(GTK_STACK(priv->stack_main_view), priv->media_settings_view, MEDIA_SETTINGS_VIEW_NAME);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -04001002
Stepan Salenikovichde896112015-05-11 16:46:33 -04001003 priv->general_settings_view = general_settings_view_new();
1004 gtk_stack_add_named(GTK_STACK(priv->stack_main_view), priv->general_settings_view, GENERAL_SETTINGS_VIEW_NAME);
1005
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -04001006 /* make the setting we will show first the active one */
Stepan Salenikovichde896112015-05-11 16:46:33 -04001007 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->radiobutton_general_settings), TRUE);
1008 priv->last_settings_view = priv->general_settings_view;
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -04001009
1010 /* connect the settings button signals to switch settings views */
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -04001011 g_signal_connect(priv->radiobutton_media_settings, "toggled", G_CALLBACK(show_media_settings), win);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -04001012 g_signal_connect(priv->radiobutton_account_settings, "toggled", G_CALLBACK(show_account_settings), win);
Stepan Salenikovichde896112015-05-11 16:46:33 -04001013 g_signal_connect(priv->radiobutton_general_settings, "toggled", G_CALLBACK(show_general_settings), win);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -04001014
Stepan Salenikovicha7a19bc2015-09-24 16:16:28 -04001015 /* populate the notebook */
Stepan Salenikovich09e0b782016-09-07 16:28:50 -04001016 priv->treeview_conversations = recent_contacts_view_new();
1017 gtk_container_add(GTK_CONTAINER(priv->scrolled_window_smartview), priv->treeview_conversations);
Stepan Salenikovich7c71bfe2015-05-13 18:08:09 -04001018
Stepan Salenikovich09e0b782016-09-07 16:28:50 -04001019 priv->treeview_contacts = contacts_view_new();
1020 gtk_container_add(GTK_CONTAINER(priv->scrolled_window_contacts), priv->treeview_contacts);
Stepan Salenikovich15142182015-03-11 17:15:26 -04001021
Stepan Salenikovich09e0b782016-09-07 16:28:50 -04001022 priv->treeview_history = history_view_new();
1023 gtk_container_add(GTK_CONTAINER(priv->scrolled_window_history), priv->treeview_history);
Stepan Salenikovich6f687072015-03-26 10:43:37 -04001024
Stepan Salenikovich2cde7612015-09-25 10:44:01 -04001025 /* welcome/default view */
Stepan Salenikovich3034d922015-10-09 10:11:42 -04001026 priv->welcome_view = ring_welcome_view_new();
Stepan Salenikovich09e0b782016-09-07 16:28:50 -04001027 g_object_ref(priv->welcome_view); // increase ref because don't want it to be destroyed when not displayed
Stepan Salenikovich3034d922015-10-09 10:11:42 -04001028 gtk_container_add(GTK_CONTAINER(priv->frame_call), priv->welcome_view);
1029 gtk_widget_show(priv->welcome_view);
Stepan Salenikovich69771842015-02-24 18:11:45 -05001030
Stepan Salenikovich09e0b782016-09-07 16:28:50 -04001031 auto selection_conversations = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_conversations));
1032 g_signal_connect(selection_conversations, "changed", G_CALLBACK(conversation_selection_changed), win);
Stepan Salenikovich2f8b4492015-09-21 17:10:36 -04001033
Stepan Salenikovich09e0b782016-09-07 16:28:50 -04001034 auto selection_contacts = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_contacts));
1035 g_signal_connect(selection_contacts, "changed", G_CALLBACK(contact_selection_changed), win);
1036
1037 auto selection_history = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_history));
1038 g_signal_connect(selection_history, "changed", G_CALLBACK(history_selection_changed), win);
Stepan Salenikovich2f8b4492015-09-21 17:10:36 -04001039
Stepan Salenikovichb0ffc342016-10-13 13:10:55 -04001040 g_signal_connect_swapped(priv->button_new_conversation, "clicked", G_CALLBACK(search_entry_activated), win);
1041 g_signal_connect_swapped(priv->search_entry, "activate", G_CALLBACK(search_entry_activated), win);
Stepan Salenikovich297b5d12015-02-26 17:51:13 -05001042
Stepan Salenikovicheafc3dd2015-04-16 18:38:01 -04001043 /* connect signal to when text is entered in the entry */
1044 g_signal_connect(priv->search_entry, "changed", G_CALLBACK(search_entry_text_changed), win);
Stepan Salenikovichf53128f2016-10-07 10:32:16 -04001045 // g_signal_connect(entry_completion, "match-selected", G_CALLBACK(select_autocompletion), win);
Stepan Salenikovich36c025c2015-03-03 19:06:44 -05001046
Stepan Salenikovich09e0b782016-09-07 16:28:50 -04001047 /* make sure the incoming call is the selected call in the CallModel */
Stepan Salenikovich36c025c2015-03-03 19:06:44 -05001048 QObject::connect(
Guillaume Roguez5d1514b2015-10-22 15:55:31 -04001049 &CallModel::instance(),
Stepan Salenikovich36c025c2015-03-03 19:06:44 -05001050 &CallModel::incomingCall,
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -04001051 [priv](Call* call) {
Stepan Salenikovichf53128f2016-10-07 10:32:16 -04001052 // clear the regex to make sure the call is shown
1053 RecentModel::instance().peopleProxy()->setFilterRegExp(QRegExp());
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -04001054 contacts_view_set_filter_string(CONTACTS_VIEW(priv->treeview_contacts),"");
1055 history_view_set_filter_string(HISTORY_VIEW(priv->treeview_history), "");
Stepan Salenikovichf53128f2016-10-07 10:32:16 -04001056
1057 // now make sure its selected
1058 RecentModel::instance().selectionModel()->clearCurrentIndex();
Stepan Salenikovich09e0b782016-09-07 16:28:50 -04001059 CallModel::instance().selectCall(call);
Stepan Salenikovich36c025c2015-03-03 19:06:44 -05001060 }
1061 );
Stepan Salenikovich5eab3032015-03-28 10:50:51 -04001062
Stepan Salenikovichb01d7362015-04-27 23:02:00 -04001063 /* react to digit key press events */
1064 g_signal_connect(win, "key-press-event", G_CALLBACK(dtmf_pressed), NULL);
Stepan Salenikovich48b45c12015-09-25 15:49:51 -04001065
1066 /* set the search entry placeholder text */
1067 gtk_entry_set_placeholder_text(GTK_ENTRY(priv->search_entry),
1068 C_("Please try to make the translation 50 chars or less so that it fits into the layout", "Search contacts or enter number"));
aviau6aeb4852016-08-18 16:01:09 -04001069
aviau039001d2016-09-29 16:39:05 -04001070 /* init chat webkit container so that it starts loading before the first time we need it*/
1071 get_webkit_chat_container(win);
1072
aviau6aeb4852016-08-18 16:01:09 -04001073 handle_account_migrations(win);
Stepan Salenikovich36c025c2015-03-03 19:06:44 -05001074}
1075
1076static void
Stepan Salenikovich6f687072015-03-26 10:43:37 -04001077ring_main_window_dispose(GObject *object)
1078{
Stepan Salenikovichbbb10d82015-05-13 12:26:44 -04001079 RingMainWindow *self = RING_MAIN_WINDOW(object);
1080 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(self);
1081
Stepan Salenikovich09e0b782016-09-07 16:28:50 -04001082 QObject::disconnect(priv->selected_item_changed);
1083 QObject::disconnect(priv->selected_call_over);
aviau039001d2016-09-29 16:39:05 -04001084
1085 g_clear_object(&priv->welcome_view);
1086 g_clear_object(&priv->webkit_chat_container);
Stepan Salenikovichbbb10d82015-05-13 12:26:44 -04001087
Stepan Salenikovich6f687072015-03-26 10:43:37 -04001088 G_OBJECT_CLASS(ring_main_window_parent_class)->dispose(object);
1089}
1090
1091static void
Stepan Salenikovich36c025c2015-03-03 19:06:44 -05001092ring_main_window_finalize(GObject *object)
1093{
Stepan Salenikovichba87ae22016-09-13 14:27:20 -04001094 RingMainWindow *self = RING_MAIN_WINDOW(object);
1095 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(self);
1096
1097 g_clear_object(&priv->settings);
1098
Stepan Salenikovich36c025c2015-03-03 19:06:44 -05001099 G_OBJECT_CLASS(ring_main_window_parent_class)->finalize(object);
Stepan Salenikovich434b88f2015-02-19 17:49:08 -05001100}
1101
1102static void
1103ring_main_window_class_init(RingMainWindowClass *klass)
1104{
Stepan Salenikovich36c025c2015-03-03 19:06:44 -05001105 G_OBJECT_CLASS(klass)->finalize = ring_main_window_finalize;
Stepan Salenikovich6f687072015-03-26 10:43:37 -04001106 G_OBJECT_CLASS(klass)->dispose = ring_main_window_dispose;
Stepan Salenikovich36c025c2015-03-03 19:06:44 -05001107
Stepan Salenikovich434b88f2015-02-19 17:49:08 -05001108 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
1109 "/cx/ring/RingGnome/ringmainwindow.ui");
1110
Stepan Salenikovichbbb10d82015-05-13 12:26:44 -04001111 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, vbox_left_pane);
Stepan Salenikovich2f8b4492015-09-21 17:10:36 -04001112 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, scrolled_window_smartview);
Stepan Salenikovicha7a19bc2015-09-24 16:16:28 -04001113 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, scrolled_window_contacts);
1114 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, scrolled_window_history);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -04001115 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, ring_menu);
1116 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, image_ring);
1117 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, ring_settings);
1118 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, image_settings);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -04001119 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, hbox_settings);
Stepan Salenikovich45d25aa2015-02-20 17:39:09 -05001120 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, search_entry);
Stepan Salenikovich69771842015-02-24 18:11:45 -05001121 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, stack_main_view);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -04001122 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, vbox_call_view);
Stepan Salenikovich3034d922015-10-09 10:11:42 -04001123 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, frame_call);
Stepan Salenikoviche9933242016-06-21 18:08:48 -04001124 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, button_new_conversation );
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -04001125 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, radiobutton_general_settings);
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -04001126 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, radiobutton_media_settings);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -04001127 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, radiobutton_account_settings);
Stepan Salenikovich434b88f2015-02-19 17:49:08 -05001128}
1129
1130GtkWidget *
1131ring_main_window_new (GtkApplication *app)
1132{
Stepan Salenikovich61cbab02015-03-16 18:35:10 -04001133 gpointer win = g_object_new(RING_MAIN_WINDOW_TYPE, "application", app, NULL);
1134
Stepan Salenikovich61cbab02015-03-16 18:35:10 -04001135 return (GtkWidget *)win;
Stepan Salenikovich434b88f2015-02-19 17:49:08 -05001136}