blob: c216462522eee1349f7eba3216047f34db761824 [file] [log] [blame]
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -04001/*
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
Stepan Salenikovich0bd53492015-05-11 14:28:52 -040031#include "mediasettingsview.h"
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040032
33#include <gtk/gtk.h>
34#include "models/gtkqtreemodel.h"
35#include "video/video_widget.h"
36#include <video/previewmanager.h>
37#include <video/configurationproxy.h>
38#include <QtCore/QItemSelectionModel>
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -040039#include <audio/settings.h>
40#include <audio/managermodel.h>
41#include <audio/alsapluginmodel.h>
42#include <audio/outputdevicemodel.h>
43#include <audio/inputdevicemodel.h>
44#include <audio/ringtonedevicemodel.h>
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040045
Stepan Salenikovich0bd53492015-05-11 14:28:52 -040046struct _MediaSettingsView
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040047{
48 GtkBox parent;
49};
50
Stepan Salenikovich0bd53492015-05-11 14:28:52 -040051struct _MediaSettingsViewClass
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040052{
53 GtkBoxClass parent_class;
54};
55
Stepan Salenikovich0bd53492015-05-11 14:28:52 -040056typedef struct _MediaSettingsViewPrivate MediaSettingsViewPrivate;
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040057
Stepan Salenikovich0bd53492015-05-11 14:28:52 -040058struct _MediaSettingsViewPrivate
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040059{
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -040060 /* audio settings */
61 GtkWidget *combobox_manager;
62 GtkWidget *combobox_ringtone;
63 GtkWidget *combobox_output;
64 GtkWidget *combobox_input;
65
66 QMetaObject::Connection manager_selection;
67 QMetaObject::Connection ringtone_selection;
68 QMetaObject::Connection output_selection;
69 QMetaObject::Connection input_selection;
70
71 /* camera settings */
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040072 GtkWidget *combobox_device;
73 GtkWidget *combobox_channel;
74 GtkWidget *combobox_resolution;
75 GtkWidget *combobox_framerate;
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -040076 GtkWidget *hbox_camera;
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040077 GtkWidget *video_widget;
78
Stepan Salenikovich41118912015-05-01 11:25:46 -040079 /* this is used to keep track of the state of the preview when the settings
80 * are opened; if a call is in progress, then the preview should already be
81 * started and we don't want to stop it when the settings are closed, in this
82 * case */
83 gboolean video_started_by_settings;
84
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040085 QMetaObject::Connection local_renderer_connection;
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040086 QMetaObject::Connection device_selection;
87 QMetaObject::Connection channel_selection;
88 QMetaObject::Connection resolution_selection;
89 QMetaObject::Connection rate_selection;
90};
91
Stepan Salenikovich0bd53492015-05-11 14:28:52 -040092G_DEFINE_TYPE_WITH_PRIVATE(MediaSettingsView, media_settings_view, GTK_TYPE_BOX);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040093
Stepan Salenikovich0bd53492015-05-11 14:28:52 -040094#define MEDIA_SETTINGS_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MEDIA_SETTINGS_VIEW_TYPE, MediaSettingsViewPrivate))
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040095
96static void
Stepan Salenikovich0bd53492015-05-11 14:28:52 -040097media_settings_view_dispose(GObject *object)
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -040098{
Stepan Salenikovich0bd53492015-05-11 14:28:52 -040099 MediaSettingsView *view = MEDIA_SETTINGS_VIEW(object);
100 MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(view);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400101
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -0400102 /* make sure to stop the preview if this view is getting destroyed */
103 if (priv->video_started_by_settings) {
104 Video::PreviewManager::instance()->stopPreview();
105 priv->video_started_by_settings = FALSE;
106 }
107
108 QObject::disconnect(priv->manager_selection);
109 QObject::disconnect(priv->ringtone_selection);
110 QObject::disconnect(priv->output_selection);
111 QObject::disconnect(priv->input_selection);
112
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400113 QObject::disconnect(priv->local_renderer_connection);
114 QObject::disconnect(priv->device_selection);
115 QObject::disconnect(priv->channel_selection);
116 QObject::disconnect(priv->resolution_selection);
117 QObject::disconnect(priv->rate_selection);
118
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400119 G_OBJECT_CLASS(media_settings_view_parent_class)->dispose(object);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400120}
121
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400122static QModelIndex
123get_index_from_combobox(GtkComboBox *box)
124{
125 GtkTreeIter iter;
126 GtkTreeModel *model = gtk_combo_box_get_model(box);
127 if (gtk_combo_box_get_active_iter(box, &iter)) {
128 return gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter);
129 } else {
130 return QModelIndex();
131 }
132}
133
134static void
135update_selection(GtkComboBox *box, QItemSelectionModel *selection_model)
136{
137 QModelIndex idx = get_index_from_combobox(box);
138 if (idx.isValid())
139 selection_model->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
140}
141
142static QMetaObject::Connection
143connect_combo_box_qmodel(GtkComboBox *box, QAbstractItemModel *qmodel, QItemSelectionModel *selection_model)
144{
145 QMetaObject::Connection connection;
146 GtkCellRenderer *renderer;
147 GtkQTreeModel *model = gtk_q_tree_model_new(qmodel,
148 1,
149 Qt::DisplayRole, G_TYPE_STRING);
150
151 gtk_combo_box_set_model(box, GTK_TREE_MODEL(model));
152 renderer = gtk_cell_renderer_text_new();
153 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box), renderer, FALSE);
154 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(box), renderer,
155 "text", 0, NULL);
156
157 /* connect signals to and from the selection model */
158 connection = QObject::connect(
159 selection_model,
160 &QItemSelectionModel::currentChanged,
161 [=](const QModelIndex & current, G_GNUC_UNUSED const QModelIndex & previous) {
162 /* select the current */
163 if (current.isValid()) {
164 GtkTreeIter new_iter;
165 GtkTreeModel *model = gtk_combo_box_get_model(box);
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -0400166 g_return_if_fail(model);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400167 if (gtk_q_tree_model_source_index_to_iter(GTK_Q_TREE_MODEL(model), current, &new_iter)) {
168 gtk_combo_box_set_active_iter(box, &new_iter);
169 } else {
170 g_warning("SelectionModel changed to invalid QModelIndex?");
171 }
172 }
173 }
174 );
175 g_signal_connect(box,
176 "changed",
177 G_CALLBACK(update_selection),
178 selection_model);
179
180 /* sync the initial selection */
181 QModelIndex idx = selection_model->currentIndex();
182 if (idx.isValid()) {
183 GtkTreeIter iter;
184 if (gtk_q_tree_model_source_index_to_iter(model, idx, &iter))
185 gtk_combo_box_set_active_iter(box, &iter);
186 }
187
188 return connection;
189}
190
191static void
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400192media_settings_view_init(MediaSettingsView *view)
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400193{
194 gtk_widget_init_template(GTK_WIDGET(view));
195
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400196 MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(view);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400197
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400198 priv->device_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_device),
199 Video::ConfigurationProxy::deviceModel(),
200 Video::ConfigurationProxy::deviceSelectionModel());
201 priv->channel_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_channel),
202 Video::ConfigurationProxy::channelModel(),
203 Video::ConfigurationProxy::channelSelectionModel());
204 priv->resolution_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_resolution),
205 Video::ConfigurationProxy::resolutionModel(),
206 Video::ConfigurationProxy::resolutionSelectionModel());
207 priv->rate_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_framerate),
208 Video::ConfigurationProxy::rateModel(),
209 Video::ConfigurationProxy::rateSelectionModel());
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -0400210
211 /* audio settings */
212 /* instantiate all the models before the manager model first */
213 Audio::Settings::instance()->alsaPluginModel();
214 Audio::Settings::instance()->ringtoneDeviceModel();
215 Audio::Settings::instance()->inputDeviceModel();
216 Audio::Settings::instance()->outputDeviceModel();
217 priv->manager_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_manager),
218 Audio::Settings::instance()->managerModel(),
219 Audio::Settings::instance()->managerModel()->selectionModel());
220 priv->ringtone_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_ringtone),
221 Audio::Settings::instance()->ringtoneDeviceModel(),
222 Audio::Settings::instance()->ringtoneDeviceModel()->selectionModel());
223 priv->input_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_input),
224 Audio::Settings::instance()->inputDeviceModel(),
225 Audio::Settings::instance()->inputDeviceModel()->selectionModel());
226 priv->output_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_output),
227 Audio::Settings::instance()->outputDeviceModel(),
228 Audio::Settings::instance()->outputDeviceModel()->selectionModel());
229
230
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400231}
232
233static void
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400234media_settings_view_class_init(MediaSettingsViewClass *klass)
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400235{
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400236 G_OBJECT_CLASS(klass)->dispose = media_settings_view_dispose;
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400237
238 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400239 "/cx/ring/RingGnome/mediasettingsview.ui");
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400240
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400241 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_manager);
242 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_ringtone);
243 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_output);
244 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_input);
245 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_device);
246 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_channel);
247 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_resolution);
248 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_framerate);
249 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, hbox_camera);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400250}
251
252GtkWidget *
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400253media_settings_view_new()
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400254{
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400255 gpointer view = g_object_new(MEDIA_SETTINGS_VIEW_TYPE, NULL);
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400256
257 return (GtkWidget *)view;
258}
Stepan Salenikovich41118912015-05-01 11:25:46 -0400259
260void
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400261media_settings_view_show_preview(MediaSettingsView *self, gboolean show_preview)
Stepan Salenikovich41118912015-05-01 11:25:46 -0400262{
Stepan Salenikovich0bd53492015-05-11 14:28:52 -0400263 g_return_if_fail(IS_MEDIA_SETTINGS_VIEW(self));
264 MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self);
Stepan Salenikovich41118912015-05-01 11:25:46 -0400265
266 /* if TRUE, create a VideoWidget, then check if the preview has already been
267 * started (because a call was in progress); if not, then start it.
268 * if FALSE, check if the preview was started by this function, if so
269 * then stop the preview; then destroy the VideoWidget to make sure we don't
270 * get useless frame updates */
271
272 if (show_preview) {
273 /* put video widget in */
274 priv->video_widget = video_widget_new();
275 gtk_widget_show_all(priv->video_widget);
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -0400276 gtk_box_pack_start(GTK_BOX(priv->hbox_camera), priv->video_widget, TRUE, TRUE, 0);
Stepan Salenikovich41118912015-05-01 11:25:46 -0400277
278 if (Video::PreviewManager::instance()->isPreviewing()) {
279 priv->video_started_by_settings = FALSE;
280
281 /* local renderer, but set as "remote" so that it takes up the whole screen */
282 video_widget_push_new_renderer(VIDEO_WIDGET(priv->video_widget),
283 Video::PreviewManager::instance()->previewRenderer(),
284 VIDEO_RENDERER_REMOTE);
285 } else {
286 priv->video_started_by_settings = TRUE;
287 priv->local_renderer_connection = QObject::connect(
288 Video::PreviewManager::instance(),
289 &Video::PreviewManager::previewStarted,
290 [=](Video::Renderer *renderer) {
291 video_widget_push_new_renderer(VIDEO_WIDGET(priv->video_widget),
292 renderer,
293 VIDEO_RENDERER_REMOTE);
294 }
295 );
296 Video::PreviewManager::instance()->startPreview();
297 }
298 } else {
299 if (priv->video_started_by_settings) {
300 Video::PreviewManager::instance()->stopPreview();
301 QObject::disconnect(priv->local_renderer_connection);
302 priv->video_started_by_settings = FALSE;
303 }
304
305 if (priv->video_widget && IS_VIDEO_WIDGET(priv->video_widget))
Stepan Salenikovich5d3506e2015-03-30 11:01:29 -0400306 gtk_container_remove(GTK_CONTAINER(priv->hbox_camera), priv->video_widget);
Stepan Salenikovich41118912015-05-01 11:25:46 -0400307 priv->video_widget = NULL;
308 }
309
310}