| 68 |
68 |
| 69 /****************************************************************************** |
69 /****************************************************************************** |
| 70 * Helpers |
70 * Helpers |
| 71 *****************************************************************************/ |
71 *****************************************************************************/ |
| 72 static void |
72 static void |
| 73 populate_vv_device_menuitems(PurpleMediaElementType type, GtkListStore *store) |
73 populate_vv_device_menuitems(AdwComboRow *row, PurpleMediaElementType type, |
| |
74 const char *active) |
| 74 { |
75 { |
| 75 PurpleMediaManager *manager = NULL; |
76 PurpleMediaManager *manager = NULL; |
| |
77 GListStore *store = NULL; |
| 76 GList *devices; |
78 GList *devices; |
| 77 |
79 guint selected = 0; /* Default to auto{audio,video}{src,sink} elements. */ |
| 78 gtk_list_store_clear(store); |
80 |
| |
81 store = G_LIST_STORE(adw_combo_row_get_model(row)); |
| |
82 |
| |
83 g_list_store_remove_all(store); |
| 79 |
84 |
| 80 manager = purple_media_manager_get(); |
85 manager = purple_media_manager_get(); |
| 81 devices = purple_media_manager_enumerate_elements(manager, type); |
86 devices = purple_media_manager_enumerate_elements(manager, type); |
| 82 for (; devices; devices = g_list_delete_link(devices, devices)) { |
87 for (; devices; devices = g_list_delete_link(devices, devices)) { |
| 83 PurpleMediaElementInfo *info = devices->data; |
88 PurpleMediaElementInfo *info = devices->data; |
| 84 GtkTreeIter iter; |
89 char *id; |
| 85 char *name, *id; |
90 |
| 86 |
|
| 87 name = purple_media_element_info_get_name(info); |
|
| 88 id = purple_media_element_info_get_id(info); |
91 id = purple_media_element_info_get_id(info); |
| 89 |
92 if(purple_strequal(id, active)) { |
| 90 gtk_list_store_append(store, &iter); |
93 /* The index will be for the *next* appended item. */ |
| 91 gtk_list_store_set(store, &iter, PIDGIN_PREF_COMBO_TEXT, name, |
94 selected = g_list_model_get_n_items(G_LIST_MODEL(store)); |
| 92 PIDGIN_PREF_COMBO_VALUE, id, -1); |
95 } |
| 93 |
|
| 94 g_free(name); |
|
| 95 g_free(id); |
96 g_free(id); |
| |
97 |
| |
98 g_list_store_append(store, info); |
| |
99 |
| 96 g_object_unref(info); |
100 g_object_unref(info); |
| 97 } |
101 } |
| |
102 |
| |
103 adw_combo_row_set_selected(row, selected); |
| 98 } |
104 } |
| 99 |
105 |
| 100 static GstElement * |
106 static GstElement * |
| 101 create_test_element(PurpleMediaElementType type) |
107 create_test_element(PurpleMediaElementType type) |
| 102 { |
108 { |
| 433 |
439 |
| 434 return NULL; |
440 return NULL; |
| 435 } |
441 } |
| 436 |
442 |
| 437 static void |
443 static void |
| 438 bind_vv_dropdown(PidginPrefCombo *combo, PurpleMediaElementType element_type) |
444 vv_combo_row_set(GObject *obj, G_GNUC_UNUSED GParamSpec *pspec, gpointer data) |
| 439 { |
445 { |
| 440 const gchar *preference_key; |
446 const char *key = data; |
| 441 GtkTreeModel *model; |
447 PurpleMediaElementInfo *item = NULL; |
| 442 |
448 char *id = NULL; |
| 443 preference_key = purple_media_type_to_preference_key(element_type); |
449 |
| 444 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo->combo)); |
450 item = adw_combo_row_get_selected_item(ADW_COMBO_ROW(obj)); |
| 445 populate_vv_device_menuitems(element_type, GTK_LIST_STORE(model)); |
451 id = purple_media_element_info_get_id(item); |
| 446 |
452 purple_prefs_set_string(key, id); |
| 447 combo->type = PURPLE_PREF_STRING; |
453 g_free(id); |
| 448 combo->key = preference_key; |
454 } |
| 449 pidgin_prefs_bind_dropdown(combo); |
455 |
| 450 } |
456 static void |
| 451 |
457 bind_vv_combo(PidginVVPrefs *prefs, AdwComboRow *row, |
| 452 static void |
|
| 453 bind_vv_frame(PidginVVPrefs *prefs, PidginPrefCombo *combo, |
|
| 454 PurpleMediaElementType type) |
458 PurpleMediaElementType type) |
| 455 { |
459 { |
| 456 bind_vv_dropdown(combo, type); |
460 const char *pref_key = NULL; |
| 457 |
461 const char *pref_value = NULL; |
| 458 purple_prefs_connect_callback(combo->combo, |
462 |
| 459 purple_media_type_to_preference_key(type), |
463 pref_key = purple_media_type_to_preference_key(type); |
| 460 vv_device_changed_cb, prefs); |
464 pref_value = purple_prefs_get_string(pref_key); |
| 461 g_signal_connect_swapped(combo->combo, "destroy", |
465 |
| |
466 populate_vv_device_menuitems(row, type, pref_value); |
| |
467 |
| |
468 g_signal_connect(row, "notify::selected", G_CALLBACK(vv_combo_row_set), |
| |
469 (gpointer)pref_key); |
| |
470 |
| |
471 purple_prefs_connect_callback(row, pref_key, vv_device_changed_cb, prefs); |
| |
472 g_signal_connect_swapped(row, "destroy", |
| 462 G_CALLBACK(purple_prefs_disconnect_by_handle), |
473 G_CALLBACK(purple_prefs_disconnect_by_handle), |
| 463 combo->combo); |
474 row); |
| 464 |
475 |
| 465 g_object_set_data(G_OBJECT(combo->combo), "vv_media_type", |
476 g_object_set_data(G_OBJECT(row), "vv_media_type", GINT_TO_POINTER(type)); |
| 466 (gpointer)type); |
|
| 467 g_object_set_data(G_OBJECT(combo->combo), "vv_combo", combo); |
|
| 468 } |
477 } |
| 469 |
478 |
| 470 static void |
479 static void |
| 471 device_list_changed_cb(G_GNUC_UNUSED PurpleMediaManager *manager, |
480 device_list_changed_cb(G_GNUC_UNUSED PurpleMediaManager *manager, |
| 472 GtkWidget *widget) |
481 gpointer data) |
| 473 { |
482 { |
| 474 PidginPrefCombo *combo; |
483 AdwComboRow *row = data; |
| |
484 PurpleMediaElementInfo *original = NULL; |
| |
485 PurpleMediaElementInfo *selected = NULL; |
| 475 PurpleMediaElementType media_type; |
486 PurpleMediaElementType media_type; |
| 476 const gchar *preference_key; |
487 const char *pref_key = NULL; |
| 477 guint signal_id; |
488 const char *pref_value = NULL; |
| 478 GtkTreeModel *model; |
489 |
| 479 |
490 original = g_object_ref(adw_combo_row_get_selected_item(row)); |
| 480 combo = g_object_get_data(G_OBJECT(widget), "vv_combo"); |
491 |
| 481 media_type = (PurpleMediaElementType)GPOINTER_TO_INT(g_object_get_data( |
492 media_type = (PurpleMediaElementType)GPOINTER_TO_INT( |
| 482 G_OBJECT(widget), |
493 g_object_get_data( |
| 483 "vv_media_type")); |
494 G_OBJECT(row), |
| 484 preference_key = purple_media_type_to_preference_key(media_type); |
495 "vv_media_type")); |
| |
496 pref_key = purple_media_type_to_preference_key(media_type); |
| |
497 pref_value = purple_prefs_get_string(pref_key); |
| 485 |
498 |
| 486 /* Block signals so pref doesn't get re-saved while changing UI. */ |
499 /* Block signals so pref doesn't get re-saved while changing UI. */ |
| 487 signal_id = g_signal_lookup("changed", GTK_TYPE_COMBO_BOX); |
500 g_signal_handlers_block_by_func(row, vv_combo_row_set, (gpointer)pref_key); |
| 488 g_signal_handlers_block_matched(combo->combo, G_SIGNAL_MATCH_ID, signal_id, |
501 |
| 489 0, NULL, NULL, NULL); |
502 populate_vv_device_menuitems(row, media_type, pref_value); |
| 490 |
503 |
| 491 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo->combo)); |
504 g_signal_handlers_unblock_by_func(row, vv_combo_row_set, |
| 492 populate_vv_device_menuitems(media_type, GTK_LIST_STORE(model)); |
505 (gpointer)pref_key); |
| 493 gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo->combo), |
506 |
| 494 purple_prefs_get_string(preference_key)); |
507 selected = adw_combo_row_get_selected_item(row); |
| 495 |
508 if(original != selected) { |
| 496 g_signal_handlers_unblock_matched(combo->combo, G_SIGNAL_MATCH_ID, |
509 /* We blocked signals to prevent accidentally changing the selected |
| 497 signal_id, 0, NULL, NULL, NULL); |
510 * element while the combo row repopulates, but now the original |
| |
511 * element is gone, so we need to push this change back to the pref. */ |
| |
512 char *id = purple_media_element_info_get_id(selected); |
| |
513 purple_prefs_set_string(pref_key, id); |
| |
514 g_free(id); |
| |
515 } |
| |
516 |
| |
517 g_clear_object(&original); |
| 498 } |
518 } |
| 499 |
519 |
| 500 /****************************************************************************** |
520 /****************************************************************************** |
| 501 * GObject Implementation |
521 * GObject Implementation |
| 502 *****************************************************************************/ |
522 *****************************************************************************/ |
| 509 widget_class, |
529 widget_class, |
| 510 "/im/pidgin/Pidgin3/Prefs/vv.ui" |
530 "/im/pidgin/Pidgin3/Prefs/vv.ui" |
| 511 ); |
531 ); |
| 512 |
532 |
| 513 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
533 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
| 514 voice.input.combo); |
534 voice.input); |
| 515 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
535 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
| 516 voice.output.combo); |
536 voice.output); |
| 517 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
537 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
| 518 voice.volume); |
538 voice.volume); |
| 519 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
539 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
| 520 voice.threshold_row); |
540 voice.threshold_row); |
| 521 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
541 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
| 531 threshold_value_changed_cb); |
551 threshold_value_changed_cb); |
| 532 gtk_widget_class_bind_template_callback(widget_class, |
552 gtk_widget_class_bind_template_callback(widget_class, |
| 533 toggle_voice_test_cb); |
553 toggle_voice_test_cb); |
| 534 |
554 |
| 535 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
555 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
| 536 video.input.combo); |
556 video.input); |
| 537 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
557 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
| 538 video.output.combo); |
558 video.output); |
| 539 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
559 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
| 540 video.frame); |
560 video.frame); |
| 541 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
561 gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs, |
| 542 video.test); |
562 video.test); |
| 543 gtk_widget_class_bind_template_callback(widget_class, |
563 gtk_widget_class_bind_template_callback(widget_class, |
| 551 |
571 |
| 552 gtk_widget_init_template(GTK_WIDGET(prefs)); |
572 gtk_widget_init_template(GTK_WIDGET(prefs)); |
| 553 |
573 |
| 554 manager = purple_media_manager_get(); |
574 manager = purple_media_manager_get(); |
| 555 |
575 |
| 556 bind_vv_frame(prefs, &prefs->voice.input, |
576 bind_vv_combo(prefs, prefs->voice.input, |
| 557 PURPLE_MEDIA_ELEMENT_AUDIO | PURPLE_MEDIA_ELEMENT_SRC); |
577 PURPLE_MEDIA_ELEMENT_AUDIO | PURPLE_MEDIA_ELEMENT_SRC); |
| 558 g_signal_connect_object(manager, "elements-changed::audiosrc", |
578 g_signal_connect_object(manager, "elements-changed::audiosrc", |
| 559 G_CALLBACK(device_list_changed_cb), |
579 G_CALLBACK(device_list_changed_cb), |
| 560 prefs->voice.input.combo, 0); |
580 prefs->voice.input, 0); |
| 561 |
581 |
| 562 bind_vv_frame(prefs, &prefs->voice.output, |
582 bind_vv_combo(prefs, prefs->voice.output, |
| 563 PURPLE_MEDIA_ELEMENT_AUDIO | PURPLE_MEDIA_ELEMENT_SINK); |
583 PURPLE_MEDIA_ELEMENT_AUDIO | PURPLE_MEDIA_ELEMENT_SINK); |
| 564 g_signal_connect_object(manager, "elements-changed::audiosink", |
584 g_signal_connect_object(manager, "elements-changed::audiosink", |
| 565 G_CALLBACK(device_list_changed_cb), |
585 G_CALLBACK(device_list_changed_cb), |
| 566 prefs->voice.output.combo, 0); |
586 prefs->voice.output, 0); |
| 567 |
587 |
| 568 bind_voice_test(prefs); |
588 bind_voice_test(prefs); |
| 569 |
589 |
| 570 bind_vv_frame(prefs, &prefs->video.input, |
590 bind_vv_combo(prefs, prefs->video.input, |
| 571 PURPLE_MEDIA_ELEMENT_VIDEO | PURPLE_MEDIA_ELEMENT_SRC); |
591 PURPLE_MEDIA_ELEMENT_VIDEO | PURPLE_MEDIA_ELEMENT_SRC); |
| 572 g_signal_connect_object(manager, "elements-changed::videosrc", |
592 g_signal_connect_object(manager, "elements-changed::videosrc", |
| 573 G_CALLBACK(device_list_changed_cb), |
593 G_CALLBACK(device_list_changed_cb), |
| 574 prefs->video.input.combo, 0); |
594 prefs->video.input, 0); |
| 575 |
595 |
| 576 bind_vv_frame(prefs, &prefs->video.output, |
596 bind_vv_combo(prefs, prefs->video.output, |
| 577 PURPLE_MEDIA_ELEMENT_VIDEO | PURPLE_MEDIA_ELEMENT_SINK); |
597 PURPLE_MEDIA_ELEMENT_VIDEO | PURPLE_MEDIA_ELEMENT_SINK); |
| 578 g_signal_connect_object(manager, "elements-changed::videosink", |
598 g_signal_connect_object(manager, "elements-changed::videosink", |
| 579 G_CALLBACK(device_list_changed_cb), |
599 G_CALLBACK(device_list_changed_cb), |
| 580 prefs->video.output.combo, 0); |
600 prefs->video.output, 0); |
| 581 } |
601 } |
| 582 |
602 |
| 583 /****************************************************************************** |
603 /****************************************************************************** |
| 584 * API |
604 * API |
| 585 *****************************************************************************/ |
605 *****************************************************************************/ |