blob: 66c4208d8b3a287f5153d6a8e19d9c666adb6bbf [file] [log] [blame]
Stepan Salenikovich434b88f2015-02-19 17:49:08 -05001/*
2 * Copyright (C) 2015 Savoir-Faire Linux Inc.
3 * 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.
18 *
19 * Additional permission under GNU GPL version 3 section 7:
20 *
21 * If you modify this program, or any covered work, by linking or
22 * combining it with the OpenSSL project's OpenSSL library (or a
23 * modified version of that library), containing parts covered by the
24 * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
25 * grants you additional permission to convey the resulting work.
26 * Corresponding Source for a non-source form of such a combination
27 * shall include the source code for the parts of OpenSSL used as well
28 * as that of the covered work.
29 */
30
31#include "ringmainwindow.h"
32
33#include <gtk/gtk.h>
Stepan Salenikovicha3557452015-02-20 14:14:12 -050034#include "models/gtkqtreemodel.h"
35#include <callmodel.h>
Stepan Salenikovich69771842015-02-24 18:11:45 -050036#include <call.h>
Stepan Salenikovichd2dbcee2015-02-27 16:52:28 -050037#include <QtCore/QItemSelectionModel>
Stepan Salenikovich69771842015-02-24 18:11:45 -050038#include "incomingcallview.h"
Stepan Salenikovichc64523b2015-02-27 16:31:00 -050039#include "currentcallview.h"
Stepan Salenikovich297b5d12015-02-26 17:51:13 -050040#include <string.h>
Stepan Salenikovichdd84cf92015-03-19 21:38:19 -040041#include <categorizedhistorymodel.h>
Stepan Salenikovich15142182015-03-11 17:15:26 -040042#include <contactmethod.h>
Stepan Salenikovich7ff47962015-03-16 15:10:14 -040043#include <QtCore/QSortFilterProxyModel>
44#include "models/gtkqsortfiltertreemodel.h"
Stepan Salenikovich61cbab02015-03-16 18:35:10 -040045#include "accountview.h"
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -040046#include <accountmodel.h>
47#include <audio/codecmodel.h>
Stepan Salenikovichbd029582015-03-24 11:00:56 -040048#include "dialogs.h"
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040049#include "videosettingsview.h"
50#include <video/previewmanager.h>
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -040051#define CALL_VIEW_NAME "calls"
52#define GENERAL_SETTINGS_VIEW_NAME "general"
53#define AUDIO_SETTINGS_VIEW_NAME "audio"
54#define VIDEO_SETTINGS_VIEW_NAME "video"
55#define ACCOUNT_SETTINGS_VIEW_NAME "accounts"
Stepan Salenikovich69771842015-02-24 18:11:45 -050056#define DEFAULT_VIEW_NAME "placeholder"
Stepan Salenikovich15142182015-03-11 17:15:26 -040057#define VIEW_CONTACTS "contacts"
58#define VIEW_HISTORY "history"
59#define VIEW_PRESENCE "presence"
Stepan Salenikovich434b88f2015-02-19 17:49:08 -050060
61struct _RingMainWindow
62{
63 GtkApplicationWindow parent;
64};
65
66struct _RingMainWindowClass
67{
68 GtkApplicationWindowClass parent_class;
69};
70
71typedef struct _RingMainWindowPrivate RingMainWindowPrivate;
72
73struct _RingMainWindowPrivate
74{
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -040075 GtkWidget *ring_menu;
76 GtkWidget *image_ring;
77 GtkWidget *ring_settings;
78 GtkWidget *image_settings;
79 GtkWidget *hbox_search;
80 GtkWidget *hbox_settings;
Stepan Salenikovich15142182015-03-11 17:15:26 -040081 GtkWidget *stack_contacts_history_presence;
82 GtkWidget *radiobutton_contacts;
83 GtkWidget *radiobutton_history;
84 GtkWidget *radiobutton_presence;
Stepan Salenikovicha3557452015-02-20 14:14:12 -050085 GtkWidget *treeview_call;
Stepan Salenikovich45d25aa2015-02-20 17:39:09 -050086 GtkWidget *search_entry;
Stepan Salenikovich69771842015-02-24 18:11:45 -050087 GtkWidget *stack_main_view;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -040088 GtkWidget *vbox_call_view;
89 GtkWidget *stack_call_view;
Stepan Salenikovich297b5d12015-02-26 17:51:13 -050090 GtkWidget *button_placecall;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -040091 GtkWidget *account_settings_view;
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040092 GtkWidget *video_settings_view;
93 GtkWidget *last_settings_view;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -040094 GtkWidget *radiobutton_audio_settings;
95 GtkWidget *radiobutton_general_settings;
96 GtkWidget *radiobutton_video_settings;
97 GtkWidget *radiobutton_account_settings;
98
99 gboolean show_settings;
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500100};
101
102G_DEFINE_TYPE_WITH_PRIVATE(RingMainWindow, ring_main_window, GTK_TYPE_APPLICATION_WINDOW);
103
104#define RING_MAIN_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), RING_MAIN_WINDOW_TYPE, RingMainWindowPrivate))
105
Stepan Salenikovich69771842015-02-24 18:11:45 -0500106static QModelIndex
107get_index_from_selection(GtkTreeSelection *selection)
108{
109 GtkTreeIter iter;
110 GtkTreeModel *model = NULL;
111
112 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
113 return gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter);
114 } else {
115 return QModelIndex();
116 }
117}
118
119static void
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500120update_call_model_selection(GtkTreeSelection *selection, G_GNUC_UNUSED gpointer user_data)
Stepan Salenikovich69771842015-02-24 18:11:45 -0500121{
Stepan Salenikovich69771842015-02-24 18:11:45 -0500122 QModelIndex current = get_index_from_selection(selection);
123 if (current.isValid())
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500124 CallModel::instance()->selectionModel()->setCurrentIndex(current, QItemSelectionModel::ClearAndSelect);
Stepan Salenikovich69771842015-02-24 18:11:45 -0500125 else
Stepan Salenikovich36c025c2015-03-03 19:06:44 -0500126 CallModel::instance()->selectionModel()->clearCurrentIndex();
Stepan Salenikovich69771842015-02-24 18:11:45 -0500127}
128
129static void
130call_selection_changed(GtkTreeSelection *selection, gpointer win)
131{
132 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(win));
133
134 /* get the current visible stack child */
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400135 GtkWidget *old_call_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_call_view));
Stepan Salenikovich69771842015-02-24 18:11:45 -0500136
137 QModelIndex idx = get_index_from_selection(selection);
138 if (idx.isValid()) {
Stepan Salenikovich9c1f6682015-03-09 16:21:28 -0400139 QVariant state = CallModel::instance()->data(idx, static_cast<int>(Call::Role::LifeCycleState));
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500140 GtkWidget *new_call_view = NULL;
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500141 char* new_call_view_name = NULL;
Stepan Salenikovich69771842015-02-24 18:11:45 -0500142
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500143 /* FIXME: change when fixed
144 * switch(state.value<Call::LifeCycleState>()) { */
145 Call::LifeCycleState lifecyclestate = (Call::LifeCycleState)state.toUInt();
146 switch(lifecyclestate) {
147 case Call::LifeCycleState::INITIALIZATION:
148 case Call::LifeCycleState::FINISHED:
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500149 new_call_view = incoming_call_view_new();
Stepan Salenikovich69771842015-02-24 18:11:45 -0500150 incoming_call_view_set_call_info(INCOMING_CALL_VIEW(new_call_view), idx);
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500151 /* use the pointer of the call as a unique name */
152 new_call_view_name = g_strdup_printf("%p_incoming", (void *)CallModel::instance()->getCall(idx));
153 break;
154 case Call::LifeCycleState::PROGRESS:
155 new_call_view = current_call_view_new();
156 current_call_view_set_call_info(CURRENT_CALL_VIEW(new_call_view), idx);
157 /* use the pointer of the call as a unique name */
158 new_call_view_name = g_strdup_printf("%p_current", (void *)CallModel::instance()->getCall(idx));
159 break;
160 case Call::LifeCycleState::COUNT__:
161 g_warning("LifeCycleState should never be COUNT");
162 break;
Stepan Salenikovich69771842015-02-24 18:11:45 -0500163 }
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500164
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400165 gtk_stack_add_named(GTK_STACK(priv->stack_call_view), new_call_view, new_call_view_name);
166 gtk_stack_set_visible_child(GTK_STACK(priv->stack_call_view), new_call_view);
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500167 g_free(new_call_view_name);
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500168
Stepan Salenikovich69771842015-02-24 18:11:45 -0500169 } else {
170 /* nothing selected in the call model, so show the default screen */
171
172 /* TODO: replace stack paceholder view */
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400173 gtk_stack_set_transition_type(GTK_STACK(priv->stack_call_view), GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT);
174 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_call_view), DEFAULT_VIEW_NAME);
175 gtk_stack_set_transition_type(GTK_STACK(priv->stack_call_view), GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
Stepan Salenikovich69771842015-02-24 18:11:45 -0500176
177 }
178
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500179 /* check if we changed the visible child */
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400180 GtkWidget *current_call_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_call_view));
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500181 if (current_call_view != old_call_view && old_call_view != NULL) {
182 /* if the previous child was a call view, then remove it from
Stepan Salenikovich69771842015-02-24 18:11:45 -0500183 * the stack; removing it should destory it since there should not
184 * be any other references to it */
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500185 if (IS_INCOMING_CALL_VIEW(old_call_view) || IS_CURRENT_CALL_VIEW(old_call_view)) {
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400186 gtk_container_remove(GTK_CONTAINER(priv->stack_call_view), old_call_view);
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500187 }
188 }
189}
190
191static void
192call_state_changed(Call *call, gpointer win)
193{
194 g_debug("call state changed");
195 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(win));
196
197 /* check if the call that changed state is the same as the selected call */
198 QModelIndex idx_selected = CallModel::instance()->selectionModel()->currentIndex();
199
200 if( idx_selected.isValid() && call == CallModel::instance()->getCall(idx_selected)) {
201 g_debug("selected call state changed");
202 /* check if we need to change the view */
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400203 GtkWidget *old_call_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_call_view));
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500204 GtkWidget *new_call_view = NULL;
Stepan Salenikovich9c1f6682015-03-09 16:21:28 -0400205 QVariant state = CallModel::instance()->data(idx_selected, static_cast<int>(Call::Role::LifeCycleState));
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500206
207 /* check what the current state is vs what is displayed */
208
209 /* FIXME: change when fixed
210 * switch(state.value<Call::LifeCycleState>()) { */
211 Call::LifeCycleState lifecyclestate = (Call::LifeCycleState)state.toUInt();
212 switch(lifecyclestate) {
213 case Call::LifeCycleState::INITIALIZATION:
214 /* LifeCycleState cannot go backwards, so it should not be possible
215 * that the call is displayed as current (meaning that its in progress)
216 * but have the state 'initialization' */
217 if (IS_CURRENT_CALL_VIEW(old_call_view))
218 g_warning("call displayed as current, but is in state of initialization");
219 break;
220 case Call::LifeCycleState::PROGRESS:
221 if (IS_INCOMING_CALL_VIEW(old_call_view)) {
222 /* change from incoming to current */
223 new_call_view = current_call_view_new();
224 current_call_view_set_call_info(CURRENT_CALL_VIEW(new_call_view), idx_selected);
225 /* use the pointer of the call as a unique name */
226 char* new_call_view_name = NULL;
227 new_call_view_name = g_strdup_printf("%p_current", (void *)CallModel::instance()->getCall(idx_selected));
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400228 gtk_stack_add_named(GTK_STACK(priv->stack_call_view), new_call_view, new_call_view_name);
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500229 g_free(new_call_view_name);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400230 gtk_stack_set_transition_type(GTK_STACK(priv->stack_call_view), GTK_STACK_TRANSITION_TYPE_SLIDE_UP);
231 gtk_stack_set_visible_child(GTK_STACK(priv->stack_call_view), new_call_view);
232 gtk_stack_set_transition_type(GTK_STACK(priv->stack_call_view), GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500233 }
234 break;
235 case Call::LifeCycleState::FINISHED:
236 /* do nothing, either call view is valid for this state */
237 break;
238 case Call::LifeCycleState::COUNT__:
239 g_warning("LifeCycleState should never be COUNT");
240 break;
241 }
242
243 /* check if we changed the visible child */
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400244 GtkWidget *current_call_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_call_view));
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500245 if (current_call_view != old_call_view && old_call_view != NULL) {
246 /* if the previous child was a call view, then remove it from
247 * the stack; removing it should destory it since there should not
248 * be any other references to it */
249 if (IS_INCOMING_CALL_VIEW(old_call_view) || IS_CURRENT_CALL_VIEW(old_call_view)) {
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400250 gtk_container_remove(GTK_CONTAINER(priv->stack_call_view), old_call_view);
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500251 }
Stepan Salenikovich69771842015-02-24 18:11:45 -0500252 }
253 }
254}
255
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500256static void
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500257search_entry_placecall(G_GNUC_UNUSED GtkWidget *entry, gpointer win)
258{
259 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(win));
260
261 const gchar *number = gtk_entry_get_text(GTK_ENTRY(priv->search_entry));
262
263 if (number && strlen(number) > 0) {
264 g_debug("dialing to number: %s", number);
265 Call *call = CallModel::instance()->dialingCall();
266 call->setDialNumber(number);
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500267 call->performAction(Call::Action::ACCEPT);
268
269 /* make this the currently selected call */
270 QModelIndex idx = CallModel::instance()->getIndex(call);
271 CallModel::instance()->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
272 }
273}
274
275static void
Stepan Salenikovich15142182015-03-11 17:15:26 -0400276call_history_item(GtkTreeView *tree_view,
277 GtkTreePath *path,
278 G_GNUC_UNUSED GtkTreeViewColumn *column,
279 G_GNUC_UNUSED gpointer user_data)
280{
281 GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
282
283 /* get iter */
284 GtkTreeIter iter;
285 if (gtk_tree_model_get_iter(model, &iter, path)) {
Stepan Salenikovich7ff47962015-03-16 15:10:14 -0400286 QModelIndex idx = gtk_q_sort_filter_tree_model_get_source_idx(GTK_Q_SORT_FILTER_TREE_MODEL(model), &iter);
Stepan Salenikovich15142182015-03-11 17:15:26 -0400287
288 QVariant contact_method = idx.data(static_cast<int>(Call::Role::ContactMethod));
289 /* create new call */
290 if (contact_method.value<ContactMethod*>()) {
291 Call *call = CallModel::instance()->dialingCall();
292 call->setDialNumber(contact_method.value<ContactMethod*>());
293 call->performAction(Call::Action::ACCEPT);
294
295 /* make this the currently selected call */
296 QModelIndex call_idx = CallModel::instance()->getIndex(call);
297 CallModel::instance()->selectionModel()->setCurrentIndex(call_idx, QItemSelectionModel::ClearAndSelect);
298 } else
299 g_warning("contact method is empty");
300 }
301}
302
303static void
304navbutton_contacts_toggled(GtkToggleButton *navbutton, RingMainWindow *win)
305{
306 g_return_if_fail(IS_RING_MAIN_WINDOW(win));
307 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
308
309 if (gtk_toggle_button_get_active(navbutton)) {
310
311 const gchar *visible = gtk_stack_get_visible_child_name(GTK_STACK(priv->stack_contacts_history_presence));
312
313 if (visible) {
314 /* contacts is left of both history and presence, so always slide right to show it */
315 gtk_stack_set_transition_type(GTK_STACK(priv->stack_contacts_history_presence), GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
316 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_contacts_history_presence), VIEW_CONTACTS);
317 } else {
318 g_warning("should always have a visible child in the nav stack");
319 gtk_stack_set_transition_type(GTK_STACK(priv->stack_contacts_history_presence), GTK_STACK_TRANSITION_TYPE_NONE);
320 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_contacts_history_presence), VIEW_CONTACTS);
321 }
322 }
323}
324
325static void
326navbutton_presence_toggled(GtkToggleButton *navbutton, RingMainWindow *win)
327{
328 g_return_if_fail(IS_RING_MAIN_WINDOW(win));
329 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
330
331 if (gtk_toggle_button_get_active(navbutton)) {
332
333 const gchar *visible = gtk_stack_get_visible_child_name(GTK_STACK(priv->stack_contacts_history_presence));
334 if (visible) {
335 /* presence is right of both history and contacts, so always slide left to show it */
336 gtk_stack_set_transition_type(GTK_STACK(priv->stack_contacts_history_presence), GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT);
337 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_contacts_history_presence), VIEW_PRESENCE);
338 } else {
339 g_warning("should always have a visible child in the nav stack");
340 gtk_stack_set_transition_type(GTK_STACK(priv->stack_contacts_history_presence), GTK_STACK_TRANSITION_TYPE_NONE);
341 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_contacts_history_presence), VIEW_PRESENCE);
342 }
343 }
344}
345
346static void
347navbutton_history_toggled(GtkToggleButton *navbutton, RingMainWindow *win)
348{
349 g_return_if_fail(IS_RING_MAIN_WINDOW(win));
350 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
351
352 if (gtk_toggle_button_get_active(navbutton)) {
353
354 const gchar *visible = gtk_stack_get_visible_child_name(GTK_STACK(priv->stack_contacts_history_presence));
355 if (visible) {
356 if (strcmp(visible, VIEW_CONTACTS) == 0) {
357 /* history is right of contacts, so slide left to show it */
358 gtk_stack_set_transition_type(GTK_STACK(priv->stack_contacts_history_presence), GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT);
359 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_contacts_history_presence), VIEW_HISTORY);
360 } else if (strcmp(visible, VIEW_PRESENCE) == 0) {
361 /* history is left of presence, so slide right to show it */
362 gtk_stack_set_transition_type(GTK_STACK(priv->stack_contacts_history_presence), GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
363 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_contacts_history_presence), VIEW_HISTORY);
364 }
365 } else {
366 g_warning("should always have a visible child in the nav stack");
367 gtk_stack_set_transition_type(GTK_STACK(priv->stack_contacts_history_presence), GTK_STACK_TRANSITION_TYPE_NONE);
368 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_contacts_history_presence), VIEW_HISTORY);
369 }
370 }
371}
372
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400373static gboolean
374save_accounts(GtkWidget *working_dialog)
375{
376 /* save changes to accounts */
377 AccountModel::instance()->save();
378 /* save changes to codecs */
379 for (int i = 0; i < AccountModel::instance()->rowCount(); i++) {
380 QModelIndex idx = AccountModel::instance()->index(i, 0);
381 AccountModel::instance()->getAccountByModelIndex(idx)->codecModel()->save();
382 }
383
384 if (working_dialog)
385 gtk_widget_destroy(working_dialog);
386
387 return G_SOURCE_REMOVE;
388}
389
Stepan Salenikovich15142182015-03-11 17:15:26 -0400390static void
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400391settings_clicked(G_GNUC_UNUSED GtkButton *button, RingMainWindow *win)
392{
393 g_return_if_fail(IS_RING_MAIN_WINDOW(win));
394 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
395
396 /* toggle show settings */
397 priv->show_settings = !priv->show_settings;
398
399 /* check which view to show */
400 if (priv->show_settings) {
401 /* show settings */
402 gtk_image_set_from_icon_name(GTK_IMAGE(priv->image_settings), "emblem-ok-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR);
403
404 gtk_widget_hide(priv->hbox_search);
405 gtk_widget_show(priv->hbox_settings);
406
407 gtk_stack_set_transition_type(GTK_STACK(priv->stack_main_view), GTK_STACK_TRANSITION_TYPE_SLIDE_UP);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400408 gtk_stack_set_visible_child(GTK_STACK(priv->stack_main_view), priv->last_settings_view);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400409 } else {
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400410 /* show working dialog in case save operation takes time */
411 GtkWidget *working = ring_dialog_working(GTK_WIDGET(win), NULL);
412 gtk_window_present(GTK_WINDOW(working));
413
414 /* now save after the time it takes to transition back to the call view (400ms)
415 * the save doesn't happen before the "working" dialog is presented
416 * the timeout function should destroy the "working" dialog when done saving
417 */
Stepan Salenikovich12fee942015-03-25 18:38:47 -0400418 g_timeout_add_full(G_PRIORITY_DEFAULT, 400, (GSourceFunc)save_accounts, working, NULL);
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400419
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400420 /* show calls */
421 gtk_image_set_from_icon_name(GTK_IMAGE(priv->image_settings), "emblem-system-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR);
422
423 gtk_widget_show(priv->hbox_search);
424 gtk_widget_hide(priv->hbox_settings);
425
426 gtk_stack_set_transition_type(GTK_STACK(priv->stack_main_view), GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN);
427 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_main_view), CALL_VIEW_NAME);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400428
429 /* make sure video preview is stopped, in case it was started */
430 Video::PreviewManager::instance()->stopPreview();
431 }
432}
433
434static void
435show_video_settings(GtkToggleButton *navbutton, RingMainWindow *win)
436{
437 g_return_if_fail(IS_RING_MAIN_WINDOW(win));
438 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
439
440 if (gtk_toggle_button_get_active(navbutton)) {
441 gtk_stack_set_transition_type(GTK_STACK(priv->stack_main_view), GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
442 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_main_view), VIDEO_SETTINGS_VIEW_NAME);
443 priv->last_settings_view = priv->video_settings_view;
444 }
445}
446
447static void
448show_account_settings(GtkToggleButton *navbutton, RingMainWindow *win)
449{
450 g_return_if_fail(IS_RING_MAIN_WINDOW(win));
451 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
452
453 if (gtk_toggle_button_get_active(navbutton)) {
454 gtk_stack_set_transition_type(GTK_STACK(priv->stack_main_view), GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
455 gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_main_view), ACCOUNT_SETTINGS_VIEW_NAME);
456 priv->last_settings_view = priv->account_settings_view;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400457 }
458}
459
460static void
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500461ring_main_window_init(RingMainWindow *win)
462{
463 RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(win);
464 gtk_widget_init_template(GTK_WIDGET(win));
465
466 /* set window icon */
467 GError *error = NULL;
468 GdkPixbuf* icon = gdk_pixbuf_new_from_resource("/cx/ring/RingGnome/ring-symbol-blue", &error);
469 if (icon == NULL) {
470 g_debug("Could not load icon: %s", error->message);
471 g_error_free(error);
472 } else
473 gtk_window_set_icon(GTK_WINDOW(win), icon);
474
475 /* set menu icon */
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400476 GdkPixbuf* image_ring = gdk_pixbuf_new_from_resource_at_scale("/cx/ring/RingGnome/ring-symbol-blue",
477 -1, 24, TRUE, &error);
478 if (image_ring == NULL) {
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500479 g_debug("Could not load icon: %s", error->message);
480 g_error_free(error);
481 } else
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400482 gtk_image_set_from_pixbuf(GTK_IMAGE(priv->image_ring), image_ring);
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500483
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400484 /* ring menu */
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500485 GtkBuilder *builder = gtk_builder_new_from_resource("/cx/ring/RingGnome/ringgearsmenu.ui");
486 GMenuModel *menu = G_MENU_MODEL(gtk_builder_get_object(builder, "menu"));
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400487 gtk_menu_button_set_menu_model(GTK_MENU_BUTTON(priv->ring_menu), menu);
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500488 g_object_unref(builder);
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500489
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400490 /* settings icon */
491 gtk_image_set_from_icon_name(GTK_IMAGE(priv->image_settings), "emblem-system-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR);
492
493 /* connect settings button signal */
494 g_signal_connect(priv->ring_settings, "clicked", G_CALLBACK(settings_clicked), win);
495
496 /* add the call view to the main stack */
497 gtk_stack_add_named(GTK_STACK(priv->stack_main_view),
498 priv->vbox_call_view,
499 CALL_VIEW_NAME);
500
501 gtk_stack_set_visible_child(GTK_STACK(priv->stack_main_view), priv->vbox_call_view);
502
503 /* init the settings views */
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400504 priv->account_settings_view = account_view_new();
505 gtk_stack_add_named(GTK_STACK(priv->stack_main_view), priv->account_settings_view, ACCOUNT_SETTINGS_VIEW_NAME);
506
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400507 priv->video_settings_view = video_settings_view_new();
508 gtk_stack_add_named(GTK_STACK(priv->stack_main_view), priv->video_settings_view, VIDEO_SETTINGS_VIEW_NAME);
509
510 /* make the setting we will show first the active one */
511 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->radiobutton_video_settings), TRUE);
512 priv->last_settings_view = priv->video_settings_view;
513
514 /* connect the settings button signals to switch settings views */
515 g_signal_connect(priv->radiobutton_video_settings, "toggled", G_CALLBACK(show_video_settings), win);
516 g_signal_connect(priv->radiobutton_account_settings, "toggled", G_CALLBACK(show_account_settings), win);
517
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500518 /* call model */
Stepan Salenikovich69771842015-02-24 18:11:45 -0500519 GtkQTreeModel *call_model;
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500520 GtkCellRenderer *renderer;
521 GtkTreeViewColumn *column;
522
Stepan Salenikovich69771842015-02-24 18:11:45 -0500523 call_model = gtk_q_tree_model_new(CallModel::instance(), 4,
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500524 Call::Role::Name, G_TYPE_STRING,
525 Call::Role::Number, G_TYPE_STRING,
526 Call::Role::Length, G_TYPE_STRING,
Stepan Salenikovich9c1f6682015-03-09 16:21:28 -0400527 Call::Role::State, G_TYPE_STRING);
Stepan Salenikovich69771842015-02-24 18:11:45 -0500528 gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview_call), GTK_TREE_MODEL(call_model));
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500529
530 renderer = gtk_cell_renderer_text_new();
Stepan Salenikovich2efd1982015-03-22 12:10:23 -0400531 g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500532 column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", 0, NULL);
Stepan Salenikovich15142182015-03-11 17:15:26 -0400533 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500534 gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_call), column);
535
536 renderer = gtk_cell_renderer_text_new();
537 column = gtk_tree_view_column_new_with_attributes("Duration", renderer, "text", 2, NULL);
Stepan Salenikovich2efd1982015-03-22 12:10:23 -0400538 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500539 gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_call), column);
540
Stepan Salenikovich69771842015-02-24 18:11:45 -0500541 /* connect signals to and from UserActionModel to sync selection betwee
542 * the QModel and the GtkTreeView */
Stepan Salenikovich69771842015-02-24 18:11:45 -0500543 QObject::connect(
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500544 CallModel::instance()->selectionModel(),
Stepan Salenikovich69771842015-02-24 18:11:45 -0500545 &QItemSelectionModel::currentChanged,
546 [=](const QModelIndex & current, const QModelIndex & previous) {
547 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_call));
548
549 /* first unselect the previous */
550 if (previous.isValid()) {
551 GtkTreeIter old_iter;
552 if (gtk_q_tree_model_source_index_to_iter(call_model, previous, &old_iter)) {
553 gtk_tree_selection_unselect_iter(selection, &old_iter);
554 } else {
555 g_warning("Trying to unselect invalid GtkTreeIter");
556 }
557 }
558
559 /* select the current */
560 if (current.isValid()) {
561 GtkTreeIter new_iter;
562 if (gtk_q_tree_model_source_index_to_iter(call_model, current, &new_iter)) {
563 gtk_tree_selection_select_iter(selection, &new_iter);
564 } else {
565 g_warning("SelectionModel of CallModel changed to invalid QModelIndex?");
566 }
567 }
568 }
569 );
570
571 GtkTreeSelection *call_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_call));
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500572 g_signal_connect(call_selection, "changed", G_CALLBACK(update_call_model_selection), NULL);
Stepan Salenikovich69771842015-02-24 18:11:45 -0500573
Stepan Salenikovichc64523b2015-02-27 16:31:00 -0500574 /* connect to call state changes to update relevant view(s) */
575 QObject::connect(
576 CallModel::instance(),
577 &CallModel::callStateChanged,
578 [=](Call* call, G_GNUC_UNUSED Call::State previousState) {
579 call_state_changed(call, win);
580 }
581 );
582
Stepan Salenikovich15142182015-03-11 17:15:26 -0400583 /* contacts view/model */
584 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
585 GtkWidget *treeview_contacts = gtk_tree_view_new();
586 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview_contacts), FALSE);
587 gtk_container_add(GTK_CONTAINER(scrolled_window), treeview_contacts);
588 gtk_widget_show_all(scrolled_window);
589 gtk_stack_add_named(GTK_STACK(priv->stack_contacts_history_presence),
590 scrolled_window,
591 VIEW_CONTACTS);
592
593 /* history view/model */
594 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
595 GtkWidget *treeview_history = gtk_tree_view_new();
Stepan Salenikovich2efd1982015-03-22 12:10:23 -0400596 /* make headers visible to allow column resizing */
597 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview_history), TRUE);
Stepan Salenikovich15142182015-03-11 17:15:26 -0400598 gtk_container_add(GTK_CONTAINER(scrolled_window), treeview_history);
599 gtk_widget_show_all(scrolled_window);
600 gtk_stack_add_named(GTK_STACK(priv->stack_contacts_history_presence),
601 scrolled_window,
602 VIEW_HISTORY);
603 /* TODO: make this linked to the client settings so that the last shown view is the same on startup */
604 gtk_stack_set_visible_child(GTK_STACK(priv->stack_contacts_history_presence),
605 scrolled_window);
606
Stepan Salenikovich15142182015-03-11 17:15:26 -0400607
Stepan Salenikovich7ff47962015-03-16 15:10:14 -0400608 /* sort the history in descending order by date */
Stepan Salenikovichdd84cf92015-03-19 21:38:19 -0400609 QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(CategorizedHistoryModel::instance());
610 proxyModel->setSourceModel(CategorizedHistoryModel::instance());
Stepan Salenikovich7ff47962015-03-16 15:10:14 -0400611 proxyModel->setSortRole(static_cast<int>(Call::Role::Date));
612 proxyModel->sort(0,Qt::DescendingOrder);
613
614 GtkQSortFilterTreeModel *history_model = gtk_q_sort_filter_tree_model_new((QSortFilterProxyModel *)proxyModel, 4,
Stepan Salenikovich15142182015-03-11 17:15:26 -0400615 Qt::DisplayRole, G_TYPE_STRING,
616 Call::Role::Number, G_TYPE_STRING,
617 Call::Role::FormattedDate, G_TYPE_STRING,
618 Call::Role::Direction, G_TYPE_INT);
619 gtk_tree_view_set_model( GTK_TREE_VIEW(treeview_history), GTK_TREE_MODEL(history_model) );
620
Stepan Salenikovich2efd1982015-03-22 12:10:23 -0400621 /* name or time category column */
622 renderer = gtk_cell_renderer_text_new();
623 g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
624 column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", 0, NULL);
Stepan Salenikovich15142182015-03-11 17:15:26 -0400625 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_history), column);
Stepan Salenikovich2efd1982015-03-22 12:10:23 -0400626 gtk_tree_view_column_set_resizable(column, TRUE);
Stepan Salenikovich15142182015-03-11 17:15:26 -0400627
Stepan Salenikovich2efd1982015-03-22 12:10:23 -0400628 /* "number" column */
629 renderer = gtk_cell_renderer_text_new();
630 g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
631 column = gtk_tree_view_column_new_with_attributes("Number", renderer, "text", 1, NULL);
632 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_history), column);
633 gtk_tree_view_column_set_resizable(column, TRUE);
634
635 /* date column */
Stepan Salenikovich15142182015-03-11 17:15:26 -0400636 renderer = gtk_cell_renderer_text_new ();
Stepan Salenikovich2efd1982015-03-22 12:10:23 -0400637 g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
Stepan Salenikovich15142182015-03-11 17:15:26 -0400638 column = gtk_tree_view_column_new_with_attributes ("Date", renderer, "text", 2, NULL);
Stepan Salenikovich2efd1982015-03-22 12:10:23 -0400639 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_history), column);
640 gtk_tree_view_column_set_resizable(column, TRUE);
Stepan Salenikovich15142182015-03-11 17:15:26 -0400641
Stepan Salenikovich2efd1982015-03-22 12:10:23 -0400642 /* expand the first row, which should be the most recent calls */
643 gtk_tree_view_expand_row(GTK_TREE_VIEW(treeview_history),
644 gtk_tree_path_new_from_string("0"),
645 FALSE);
Stepan Salenikovich15142182015-03-11 17:15:26 -0400646
647 g_signal_connect(treeview_history, "row-activated", G_CALLBACK(call_history_item), NULL);
648
649 /* presence view/model */
650 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
651 GtkWidget *treeview_presence = gtk_tree_view_new();
652 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview_presence), FALSE);
653 gtk_container_add(GTK_CONTAINER(scrolled_window), treeview_presence);
654 gtk_widget_show_all(scrolled_window);
655 gtk_stack_add_named(GTK_STACK(priv->stack_contacts_history_presence),
656 scrolled_window,
657 VIEW_PRESENCE);
658
659 /* connect signals to change the contacts/history/presence stack view */
660 g_signal_connect(priv->radiobutton_contacts, "toggled", G_CALLBACK(navbutton_contacts_toggled), win);
661 g_signal_connect(priv->radiobutton_history, "toggled", G_CALLBACK(navbutton_history_toggled), win);
662 g_signal_connect(priv->radiobutton_presence, "toggled", G_CALLBACK(navbutton_presence_toggled), win);
663
Stepan Salenikovich69771842015-02-24 18:11:45 -0500664 /* TODO: replace stack paceholder view */
665 GtkWidget *placeholder_view = gtk_tree_view_new();
666 gtk_widget_show(placeholder_view);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400667 gtk_stack_add_named(GTK_STACK(priv->stack_call_view), placeholder_view, DEFAULT_VIEW_NAME);
Stepan Salenikovich69771842015-02-24 18:11:45 -0500668
669 /* connect signals */
670 g_signal_connect(call_selection, "changed", G_CALLBACK(call_selection_changed), win);
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500671 g_signal_connect(priv->button_placecall, "clicked", G_CALLBACK(search_entry_placecall), win);
672 g_signal_connect(priv->search_entry, "activate", G_CALLBACK(search_entry_placecall), win);
673
674 /* style of search entry */
675 gtk_widget_override_font(priv->search_entry, pango_font_description_from_string("monospace 15"));
Stepan Salenikovich36c025c2015-03-03 19:06:44 -0500676
677 /* connect to incoming call and focus */
678 QObject::connect(
679 CallModel::instance(),
680 &CallModel::incomingCall,
681 [=](Call* call) {
682 CallModel::instance()->selectionModel()->setCurrentIndex(
683 CallModel::instance()->getIndex(call), QItemSelectionModel::ClearAndSelect);
684 }
685 );
686}
687
688static void
689ring_main_window_finalize(GObject *object)
690{
691 G_OBJECT_CLASS(ring_main_window_parent_class)->finalize(object);
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500692}
693
694static void
695ring_main_window_class_init(RingMainWindowClass *klass)
696{
Stepan Salenikovich36c025c2015-03-03 19:06:44 -0500697 G_OBJECT_CLASS(klass)->finalize = ring_main_window_finalize;
698
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500699 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
700 "/cx/ring/RingGnome/ringmainwindow.ui");
701
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500702 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, treeview_call);
Stepan Salenikovich15142182015-03-11 17:15:26 -0400703 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, stack_contacts_history_presence);
704 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, radiobutton_contacts);
705 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, radiobutton_history);
706 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, radiobutton_presence);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400707 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, ring_menu);
708 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, image_ring);
709 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, ring_settings);
710 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, image_settings);
711 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, hbox_search);
712 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, hbox_settings);
Stepan Salenikovich45d25aa2015-02-20 17:39:09 -0500713 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, search_entry);
Stepan Salenikovich69771842015-02-24 18:11:45 -0500714 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, stack_main_view);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400715 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, vbox_call_view);
716 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, stack_call_view);
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500717 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, button_placecall);
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400718 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, radiobutton_audio_settings);
719 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, radiobutton_general_settings);
720 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, radiobutton_video_settings);
721 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, radiobutton_account_settings);
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500722}
723
724GtkWidget *
725ring_main_window_new (GtkApplication *app)
726{
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400727 gpointer win = g_object_new(RING_MAIN_WINDOW_TYPE, "application", app, NULL);
728
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400729 return (GtkWidget *)win;
Stepan Salenikovich434b88f2015-02-19 17:49:08 -0500730}