summaryrefslogtreecommitdiff
path: root/src/control-center.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/control-center.c')
-rw-r--r--src/control-center.c821
1 files changed, 0 insertions, 821 deletions
diff --git a/src/control-center.c b/src/control-center.c
deleted file mode 100644
index bb22830..0000000
--- a/src/control-center.c
+++ /dev/null
@@ -1,821 +0,0 @@
-#include "control-center.h"
-#include "widgets/control-center/control-button.h"
-#include "widgets/control-center/control-slider.h"
-#include "widgets/control-center/control-details.h"
-#include "widgets/control-center/control-details-item.h"
-#include "widgets/inset-container.h"
-#include "widgets/notification-widget.h"
-#include <gtk4-layer-shell.h>
-
-#define STACK_ITEM_LIST "list"
-#define STACK_ITEM_PLACEHOLDER "placeholder"
-
-//
-// FoobarControlCenter:
-//
-// The control center is made up of two sections:
-// - The "controls" section for configuring wi-fi, volume, brightness, etc.
-// - The "notifications" section showing all notifications (including dismissed ones) and allowing the user to close
-// them.
-//
-
-struct _FoobarControlCenter
-{
- GtkWindow parent_instance;
- GtkWidget* control_container;
- GtkWidget* notification_list;
- GtkWidget* notification_container;
- GtkWidget* notification_placeholder;
- GtkWidget* notification_stack;
- GtkWidget* layout;
- FoobarBrightnessService* brightness_service;
- FoobarAudioService* audio_service;
- FoobarNetworkService* network_service;
- FoobarBluetoothService* bluetooth_service;
- FoobarNotificationService* notification_service;
- FoobarConfigurationService* configuration_service;
- gchar* notification_time_format;
- gint notification_min_height;
- gint notification_close_button_inset;
- gint padding;
- gint spacing;
- gulong config_handler_id;
-};
-
-static void foobar_control_center_class_init ( FoobarControlCenterClass* klass );
-static void foobar_control_center_init ( FoobarControlCenter* self );
-static void foobar_control_center_finalize ( GObject* object );
-static void foobar_control_center_handle_notification_setup ( GtkListItemFactory* factory,
- GtkListItem* list_item,
- gpointer userdata );
-static void foobar_control_center_handle_network_setup ( GtkListItemFactory* factory,
- GtkListItem* list_item,
- gpointer userdata );
-static void foobar_control_center_handle_bluetooth_device_setup ( GtkListItemFactory* factory,
- GtkListItem* list_item,
- gpointer userdata );
-static void foobar_control_center_handle_bluetooth_device_activate ( GtkListView* view,
- guint position,
- gpointer userdata );
-static void foobar_control_center_handle_audio_device_setup ( GtkListItemFactory* factory,
- GtkListItem* list_item,
- gpointer userdata );
-static void foobar_control_center_handle_audio_device_activate ( GtkListView* view,
- guint position,
- gpointer userdata );
-static void foobar_control_center_handle_config_change ( GObject* object,
- GParamSpec* pspec,
- gpointer userdata );
-static FoobarControlDetailsAccessory foobar_control_center_compute_bluetooth_device_accessory ( GtkExpression* expression,
- FoobarBluetoothDeviceState state,
- gpointer userdata );
-static gchar* foobar_control_center_compute_visible_notification_child_name( GtkExpression* expression,
- guint count,
- gpointer userdata );
-
-G_DEFINE_FINAL_TYPE( FoobarControlCenter, foobar_control_center, GTK_TYPE_WINDOW )
-
-// ---------------------------------------------------------------------------------------------------------------------
-// Window Implementation
-// ---------------------------------------------------------------------------------------------------------------------
-
-//
-// Static initialization for the control center.
-//
-void foobar_control_center_class_init( FoobarControlCenterClass* klass )
-{
- GObjectClass* object_klass = G_OBJECT_CLASS( klass );
- object_klass->finalize = foobar_control_center_finalize;
-}
-
-//
-// Instance initialization for the control center.
-//
-void foobar_control_center_init( FoobarControlCenter* self )
-{
- self->control_container = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 );
- gtk_widget_add_css_class( self->control_container, "controls" );
- gtk_widget_set_hexpand( self->control_container, TRUE );
-
- GtkListItemFactory* notification_factory = gtk_signal_list_item_factory_new( );
- g_signal_connect(
- notification_factory,
- "setup",
- G_CALLBACK( foobar_control_center_handle_notification_setup ),
- self );
- self->notification_list = gtk_list_view_new( NULL, notification_factory );
- gtk_widget_add_css_class( self->notification_list, "notifications" );
-
- // XXX: Get rid of this container to enable virtualization; currently needed because I haven't figured out how to
- // set padding without using css (setting margin on list view causes glitches when scrolling).
- self->notification_container = foobar_inset_container_new( );
- foobar_inset_container_set_child( FOOBAR_INSET_CONTAINER( self->notification_container ), self->notification_list );
-
- GtkWidget* scrolled_window = gtk_scrolled_window_new( );
- gtk_scrolled_window_set_child( GTK_SCROLLED_WINDOW( scrolled_window ), self->notification_container );
- gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolled_window ), GTK_POLICY_NEVER, GTK_POLICY_EXTERNAL );
-
- self->notification_placeholder = gtk_label_new( "No Notifications" );
- gtk_widget_add_css_class( self->notification_placeholder, "placeholder" );
- gtk_label_set_ellipsize( GTK_LABEL( self->notification_placeholder ), PANGO_ELLIPSIZE_END );
- gtk_label_set_wrap( GTK_LABEL( self->notification_placeholder ), FALSE );
-
- self->notification_stack = gtk_stack_new( );
- gtk_stack_add_named( GTK_STACK( self->notification_stack ), scrolled_window, STACK_ITEM_LIST );
- gtk_stack_add_named( GTK_STACK( self->notification_stack ), self->notification_placeholder, STACK_ITEM_PLACEHOLDER );
- gtk_widget_set_vexpand( self->notification_stack, TRUE );
- gtk_widget_set_hexpand( self->notification_stack, TRUE );
-
- self->layout = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 );
- gtk_box_append( GTK_BOX( self->layout ), self->control_container );
- gtk_box_append( GTK_BOX( self->layout ), gtk_separator_new( GTK_ORIENTATION_HORIZONTAL ) );
- gtk_box_append( GTK_BOX( self->layout ), self->notification_stack );
-
- g_autoptr( GtkSizeGroup ) size_group = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL );
- gtk_size_group_add_widget( size_group, self->control_container );
- gtk_size_group_add_widget( size_group, self->notification_stack );
-
- gtk_window_set_child( GTK_WINDOW( self ), self->layout );
- gtk_window_set_title( GTK_WINDOW( self ), "Foobar Control Center" );
- gtk_widget_add_css_class( GTK_WIDGET( self ), "control-center" );
- gtk_layer_init_for_window( GTK_WINDOW( self ) );
- gtk_layer_set_namespace( GTK_WINDOW( self ), "foobar-control-center" );
-}
-
-//
-// Instance cleanup for the control center.
-//
-void foobar_control_center_finalize( GObject* object )
-{
- FoobarControlCenter* self = (FoobarControlCenter*)object;
-
- g_clear_signal_handler( &self->config_handler_id, self->configuration_service );
- g_clear_object( &self->brightness_service );
- g_clear_object( &self->audio_service );
- g_clear_object( &self->network_service );
- g_clear_object( &self->bluetooth_service );
- g_clear_object( &self->configuration_service );
- g_clear_object( &self->notification_service );
- g_clear_pointer( &self->notification_time_format, g_free );
-
- G_OBJECT_CLASS( foobar_control_center_parent_class )->finalize( object );
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-// Public API
-// ---------------------------------------------------------------------------------------------------------------------
-
-//
-// Create a new control center instance.
-//
-FoobarControlCenter* foobar_control_center_new(
- FoobarBrightnessService* brightness_service,
- FoobarAudioService* audio_service,
- FoobarNetworkService* network_service,
- FoobarBluetoothService* bluetooth_service,
- FoobarNotificationService* notification_service,
- FoobarConfigurationService* configuration_service )
-{
- g_return_val_if_fail( FOOBAR_IS_BRIGHTNESS_SERVICE( brightness_service ), NULL );
- g_return_val_if_fail( FOOBAR_IS_AUDIO_SERVICE( audio_service ), NULL );
- g_return_val_if_fail( FOOBAR_IS_NETWORK_SERVICE( network_service ), NULL );
- g_return_val_if_fail( FOOBAR_IS_BLUETOOTH_SERVICE( bluetooth_service ), NULL );
- g_return_val_if_fail( FOOBAR_IS_NOTIFICATION_SERVICE( notification_service ), NULL );
- g_return_val_if_fail( FOOBAR_IS_CONFIGURATION_SERVICE( configuration_service ), NULL );
-
- FoobarControlCenter* self = g_object_new( FOOBAR_TYPE_CONTROL_CENTER, NULL );
- self->brightness_service = g_object_ref( brightness_service );
- self->audio_service = g_object_ref( audio_service );
- self->network_service = g_object_ref( network_service );
- self->bluetooth_service = g_object_ref( bluetooth_service );
- self->notification_service = g_object_ref( notification_service );
- self->configuration_service = g_object_ref( configuration_service );
-
- // Apply the configuration and subscribe to changes.
-
- FoobarConfiguration const* config = foobar_configuration_service_get_current( self->configuration_service );
- foobar_control_center_apply_configuration(
- self,
- foobar_configuration_get_control_center( config ),
- foobar_configuration_get_notifications( config ) );
- self->config_handler_id = g_signal_connect(
- self->configuration_service,
- "notify::current",
- G_CALLBACK( foobar_control_center_handle_config_change ),
- self );
-
- // Set up the notifications list view.
-
- GListModel* source_model = foobar_notification_service_get_notifications( self->notification_service );
- GtkNoSelection* selection_model = gtk_no_selection_new( g_object_ref( source_model ) );
- gtk_list_view_set_model( GTK_LIST_VIEW( self->notification_list ), GTK_SELECTION_MODEL( selection_model ) );
-
- // Set up bindings.
-
- {
- GtkExpression* count_expr = gtk_property_expression_new( GTK_TYPE_SORT_LIST_MODEL, NULL, "n-items" );
- GtkExpression* child_params[] = { count_expr };
- GtkExpression* child_expr = gtk_cclosure_expression_new(
- G_TYPE_STRING,
- NULL,
- G_N_ELEMENTS( child_params ),
- child_params,
- G_CALLBACK( foobar_control_center_compute_visible_notification_child_name ),
- NULL,
- NULL );
- gtk_expression_bind( child_expr, self->notification_stack, "visible-child-name", source_model );
- }
-
- return self;
-}
-
-//
-// Apply the control center configuration provided by the configuration service, additionally using the provided
-// notification configuration for some settings.
-//
-void foobar_control_center_apply_configuration(
- FoobarControlCenter* self,
- FoobarControlCenterConfiguration const* config,
- FoobarNotificationConfiguration const* notification_config )
-{
- g_return_if_fail( FOOBAR_IS_CONTROL_CENTER( self ) );
- g_return_if_fail( config != NULL );
- g_return_if_fail( notification_config != NULL );
-
- // Copy configuration into member variables.
-
- g_clear_pointer( &self->notification_time_format, g_free );
- self->notification_time_format = g_strdup( foobar_notification_configuration_get_time_format( notification_config ) );
- self->notification_min_height = foobar_notification_configuration_get_min_height( notification_config );
- self->notification_close_button_inset = foobar_notification_configuration_get_close_button_inset( notification_config );
- self->padding = foobar_control_center_configuration_get_padding( config );
- self->spacing = foobar_control_center_configuration_get_spacing( config );
-
- // Configure the window.
-
- gtk_window_set_default_size(
- GTK_WINDOW( self ),
- foobar_control_center_configuration_get_width( config ),
- foobar_control_center_configuration_get_height( config ) );
-
- FoobarScreenEdge position = foobar_control_center_configuration_get_position( config );
- FoobarControlCenterAlignment alignment = foobar_control_center_configuration_get_alignment( config );
- gboolean attach_left = ( position == FOOBAR_SCREEN_EDGE_LEFT );
- gboolean attach_right = ( position == FOOBAR_SCREEN_EDGE_RIGHT );
- gboolean attach_top = ( position == FOOBAR_SCREEN_EDGE_TOP );
- gboolean attach_bottom = ( position == FOOBAR_SCREEN_EDGE_BOTTOM );
- switch ( position )
- {
- case FOOBAR_SCREEN_EDGE_LEFT:
- case FOOBAR_SCREEN_EDGE_RIGHT:
- attach_top =
- ( alignment == FOOBAR_CONTROL_CENTER_ALIGNMENT_START ) ||
- ( alignment == FOOBAR_CONTROL_CENTER_ALIGNMENT_FILL );
- attach_bottom =
- ( alignment == FOOBAR_CONTROL_CENTER_ALIGNMENT_END ) ||
- ( alignment == FOOBAR_CONTROL_CENTER_ALIGNMENT_FILL );
- break;
- case FOOBAR_SCREEN_EDGE_TOP:
- case FOOBAR_SCREEN_EDGE_BOTTOM:
- attach_left =
- ( alignment == FOOBAR_CONTROL_CENTER_ALIGNMENT_START ) ||
- ( alignment == FOOBAR_CONTROL_CENTER_ALIGNMENT_FILL );
- attach_right =
- ( alignment == FOOBAR_CONTROL_CENTER_ALIGNMENT_END ) ||
- ( alignment == FOOBAR_CONTROL_CENTER_ALIGNMENT_FILL );
- break;
- default:
- g_warn_if_reached( );
- break;
- }
-
- gtk_layer_set_anchor( GTK_WINDOW( self ), GTK_LAYER_SHELL_EDGE_LEFT, attach_left );
- gtk_layer_set_anchor( GTK_WINDOW( self ), GTK_LAYER_SHELL_EDGE_RIGHT, attach_right );
- gtk_layer_set_anchor( GTK_WINDOW( self ), GTK_LAYER_SHELL_EDGE_TOP, attach_top );
- gtk_layer_set_anchor( GTK_WINDOW( self ), GTK_LAYER_SHELL_EDGE_BOTTOM, attach_bottom );
-
- gint offset = foobar_control_center_configuration_get_offset( config );
- gtk_layer_set_margin( GTK_WINDOW( self ), GTK_LAYER_SHELL_EDGE_LEFT, attach_left ? offset : 0 );
- gtk_layer_set_margin( GTK_WINDOW( self ), GTK_LAYER_SHELL_EDGE_RIGHT, attach_right ? offset : 0 );
- gtk_layer_set_margin( GTK_WINDOW( self ), GTK_LAYER_SHELL_EDGE_TOP, attach_top ? offset : 0 );
- gtk_layer_set_margin( GTK_WINDOW( self ), GTK_LAYER_SHELL_EDGE_BOTTOM, attach_bottom ? offset : 0 );
-
- // Configure the orientation.
-
- FoobarOrientation orientation = foobar_control_center_configuration_get_orientation( config );
- switch ( orientation )
- {
- case FOOBAR_ORIENTATION_HORIZONTAL:
- gtk_orientable_set_orientation( GTK_ORIENTABLE( self->layout ), GTK_ORIENTATION_HORIZONTAL );
- break;
- case FOOBAR_ORIENTATION_VERTICAL:
- gtk_orientable_set_orientation( GTK_ORIENTABLE( self->layout ), GTK_ORIENTATION_VERTICAL );
- break;
- default:
- g_warn_if_reached( );
- break;
- }
-
- // Adjust spacing for the containers.
-
- foobar_inset_container_set_inset_vertical( FOOBAR_INSET_CONTAINER( self->notification_container ), -self->spacing / 2 );
- gtk_widget_set_margin_top( self->notification_container, self->padding );
- gtk_widget_set_margin_bottom( self->notification_container, self->padding );
-
- gtk_widget_set_margin_start( self->notification_placeholder, self->padding );
- gtk_widget_set_margin_end( self->notification_placeholder, self->padding );
- gtk_widget_set_margin_top( self->notification_placeholder, self->padding );
- gtk_widget_set_margin_bottom( self->notification_placeholder, self->padding );
-
- gtk_box_set_spacing( GTK_BOX( self->control_container ), self->spacing );
- gtk_widget_set_margin_top( self->control_container, self->padding );
- gtk_widget_set_margin_bottom( self->control_container, self->padding );
-
- // Re-create list items by resetting the factory.
-
- GtkListItemFactory* factory = gtk_list_view_get_factory( GTK_LIST_VIEW( self->notification_list ) );
- g_object_ref( factory );
- gtk_list_view_set_factory( GTK_LIST_VIEW( self->notification_list ), NULL );
- gtk_list_view_set_factory( GTK_LIST_VIEW( self->notification_list ), factory );
- g_object_unref( factory );
-
- // Re-create control rows.
-
- GtkWidget* row_widget;
- while ( ( row_widget = gtk_widget_get_first_child( self->control_container ) ) )
- {
- gtk_widget_unparent( row_widget );
- }
-
- gsize rows_count;
- FoobarControlCenterRow const* rows = foobar_control_center_configuration_get_rows( config, &rows_count );
- for ( gsize i = 0; i < rows_count; ++i )
- {
- // Add rows. If there are details for a row, add them into another box that is then added to the
- // control_container to circumvent the spacing of the box.
-
- switch ( rows[i] )
- {
- case FOOBAR_CONTROL_CENTER_ROW_CONNECTIVITY:
- {
- // Create the buttons for network and bluetooth.
-
- GtkWidget* network_button = foobar_control_button_new( );
-
- GtkWidget* bluetooth_button = foobar_control_button_new( );
- foobar_control_button_set_icon_name( FOOBAR_CONTROL_BUTTON( bluetooth_button ), "fluent-bluetooth-symbolic" );
- foobar_control_button_set_label( FOOBAR_CONTROL_BUTTON( bluetooth_button ), "Bluetooth" );
-
- GtkWidget* button_container = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, self->spacing );
- gtk_box_set_homogeneous( GTK_BOX( button_container ), TRUE );
- gtk_widget_set_margin_start( button_container, self->padding );
- gtk_widget_set_margin_end( button_container, self->padding );
- gtk_box_append( GTK_BOX( button_container ), network_button );
- gtk_box_append( GTK_BOX( button_container ), bluetooth_button );
-
- GtkWidget* row = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 );
- gtk_box_append( GTK_BOX( row ), button_container );
-
- // Show either a button for managing Wi-Fi or a static element for ethernet.
-
- FoobarNetworkAdapterWifi* wifi_adapter = foobar_network_service_get_wifi( self->network_service );
- if ( wifi_adapter )
- {
- foobar_control_button_set_icon_name( FOOBAR_CONTROL_BUTTON( network_button ), "fluent-wifi-1-symbolic" );
- foobar_control_button_set_label( FOOBAR_CONTROL_BUTTON( network_button ), "Wi-Fi" );
- foobar_control_button_set_can_expand( FOOBAR_CONTROL_BUTTON( network_button ), TRUE );
- foobar_control_button_set_can_toggle( FOOBAR_CONTROL_BUTTON( network_button ), TRUE );
- g_object_bind_property(
- wifi_adapter,
- "is-enabled",
- network_button,
- "is-toggled",
- G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL );
- g_object_bind_property(
- network_button,
- "is-toggled",
- network_button,
- "can-expand",
- G_BINDING_SYNC_CREATE );
- g_object_bind_property(
- network_button,
- "is-expanded",
- wifi_adapter,
- "is-scanning",
- G_BINDING_SYNC_CREATE );
-
- GtkListItemFactory* wifi_item_factory = gtk_signal_list_item_factory_new( );
- g_signal_connect(
- wifi_item_factory,
- "setup",
- G_CALLBACK( foobar_control_center_handle_network_setup ),
- self );
-
- GListModel* wifi_source_model = g_object_ref( foobar_network_adapter_wifi_get_networks( wifi_adapter ) );
- GtkNoSelection* wifi_selection_model = gtk_no_selection_new( wifi_source_model );
-
- GtkWidget* wifi_list_view = gtk_list_view_new( GTK_SELECTION_MODEL( wifi_selection_model ), wifi_item_factory );
-
- GtkWidget* wifi_details = foobar_control_details_new( );
- foobar_control_details_set_inset_top( FOOBAR_CONTROL_DETAILS( wifi_details ), self->spacing );
- foobar_control_details_set_child( FOOBAR_CONTROL_DETAILS( wifi_details ), wifi_list_view );
- g_object_bind_property(
- network_button,
- "is-expanded",
- wifi_details,
- "is-expanded",
- G_BINDING_SYNC_CREATE );
-
- gtk_box_append( GTK_BOX( row ), wifi_details );
- }
- else
- {
- foobar_control_button_set_icon_name( FOOBAR_CONTROL_BUTTON( network_button ), "fluent-virtual-network-symbolic" );
- foobar_control_button_set_label( FOOBAR_CONTROL_BUTTON( network_button ), "Ethernet" );
- foobar_control_button_set_can_expand( FOOBAR_CONTROL_BUTTON( network_button ), FALSE );
- foobar_control_button_set_can_toggle( FOOBAR_CONTROL_BUTTON( network_button ), FALSE );
- }
-
- // Enable interactions for the bluetooth button if available.
-
- g_object_bind_property(
- self->bluetooth_service,
- "is-available",
- bluetooth_button,
- "can-toggle",
- G_BINDING_SYNC_CREATE );
- g_object_bind_property(
- self->bluetooth_service,
- "is-enabled",
- bluetooth_button,
- "is-toggled",
- G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL );
- g_object_bind_property(
- bluetooth_button,
- "is-toggled",
- bluetooth_button,
- "can-expand",
- G_BINDING_SYNC_CREATE );
- g_object_bind_property(
- bluetooth_button,
- "is-expanded",
- self->bluetooth_service,
- "is-scanning",
- G_BINDING_SYNC_CREATE );
-
- GtkListItemFactory* bluetooth_item_factory = gtk_signal_list_item_factory_new( );
- g_signal_connect(
- bluetooth_item_factory,
- "setup",
- G_CALLBACK( foobar_control_center_handle_bluetooth_device_setup ),
- self );
-
- GListModel* bluetooth_source_model = g_object_ref( foobar_bluetooth_service_get_devices( self->bluetooth_service ) );
- GtkNoSelection* bluetooth_selection_model = gtk_no_selection_new( bluetooth_source_model );
-
- GtkWidget* bluetooth_list_view = gtk_list_view_new(
- GTK_SELECTION_MODEL( bluetooth_selection_model ),
- bluetooth_item_factory );
- gtk_list_view_set_single_click_activate( GTK_LIST_VIEW( bluetooth_list_view ), TRUE );
- g_signal_connect(
- bluetooth_list_view,
- "activate",
- G_CALLBACK( foobar_control_center_handle_bluetooth_device_activate ),
- NULL );
-
- GtkWidget* bluetooth_details = foobar_control_details_new( );
- foobar_control_details_set_inset_top( FOOBAR_CONTROL_DETAILS( bluetooth_details ), self->spacing );
- foobar_control_details_set_child( FOOBAR_CONTROL_DETAILS( bluetooth_details ), bluetooth_list_view );
- g_object_bind_property(
- bluetooth_button,
- "is-expanded",
- bluetooth_details,
- "is-expanded",
- G_BINDING_SYNC_CREATE );
-
- gtk_box_append( GTK_BOX( row ), bluetooth_details );
-
- gtk_box_append( GTK_BOX( self->control_container ), row );
- break;
- }
- case FOOBAR_CONTROL_CENTER_ROW_AUDIO_OUTPUT:
- case FOOBAR_CONTROL_CENTER_ROW_AUDIO_INPUT:
- {
- FoobarAudioDevice* default_device;
- GListModel* device_list;
- gchar const* icon_name;
- gchar const* label;
- if ( rows[i] == FOOBAR_CONTROL_CENTER_ROW_AUDIO_OUTPUT )
- {
- default_device = foobar_audio_service_get_default_output( self->audio_service );
- device_list = foobar_audio_service_get_outputs( self->audio_service );
- icon_name = "fluent-speaker-2-symbolic";
- label = "Audio Output";
- }
- else
- {
- default_device = foobar_audio_service_get_default_input( self->audio_service );
- device_list = foobar_audio_service_get_inputs( self->audio_service );
- icon_name = "fluent-microphone-symbolic";
- label = "Audio Input";
- }
-
- // Create the slider for controlling the volume.
-
- GtkWidget* slider = foobar_control_slider_new( );
- gtk_widget_set_margin_start( slider, self->padding );
- gtk_widget_set_margin_end( slider, self->padding );
- foobar_control_slider_set_icon_name( FOOBAR_CONTROL_SLIDER( slider ), icon_name );
- foobar_control_slider_set_label( FOOBAR_CONTROL_SLIDER( slider ), label );
- foobar_control_slider_set_can_expand( FOOBAR_CONTROL_SLIDER( slider ), TRUE );
- g_object_bind_property(
- default_device,
- "volume",
- slider,
- "percentage",
- G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL );
-
- // Create the details view for selecting the audio device.
-
- GtkListItemFactory* item_factory = gtk_signal_list_item_factory_new( );
- g_signal_connect( item_factory, "setup", G_CALLBACK( foobar_control_center_handle_audio_device_setup ), self );
-
- GListModel* source_model = g_object_ref( device_list );
- GtkNoSelection* selection_model = gtk_no_selection_new( source_model );
-
- GtkWidget* list_view = gtk_list_view_new( GTK_SELECTION_MODEL( selection_model ), item_factory );
- gtk_list_view_set_single_click_activate( GTK_LIST_VIEW( list_view ), TRUE );
- g_signal_connect(
- list_view,
- "activate",
- G_CALLBACK( foobar_control_center_handle_audio_device_activate ),
- NULL );
-
- GtkWidget* details = foobar_control_details_new( );
- foobar_control_details_set_inset_top( FOOBAR_CONTROL_DETAILS( details ), self->spacing );
- foobar_control_details_set_child( FOOBAR_CONTROL_DETAILS( details ), list_view );
- g_object_bind_property(
- slider,
- "is-expanded",
- details,
- "is-expanded",
- G_BINDING_SYNC_CREATE );
-
- GtkWidget* row = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 );
- gtk_box_append( GTK_BOX( row ), slider );
- gtk_box_append( GTK_BOX( row ), details );
-
- gtk_box_append( GTK_BOX( self->control_container ), row );
- break;
- }
- case FOOBAR_CONTROL_CENTER_ROW_BRIGHTNESS:
- {
- // Create the slider for adjusting the brightness.
-
- GtkWidget* slider = foobar_control_slider_new( );
- gtk_widget_set_margin_start( slider, self->padding );
- gtk_widget_set_margin_end( slider, self->padding );
- foobar_control_slider_set_icon_name( FOOBAR_CONTROL_SLIDER( slider ), "fluent-brightness-high-symbolic" );
- foobar_control_slider_set_label( FOOBAR_CONTROL_SLIDER( slider ), "Brightness" );
- g_object_bind_property(
- self->brightness_service,
- "percentage",
- slider,
- "percentage",
- G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL );
-
- gtk_box_append( GTK_BOX( self->control_container ), slider );
- break;
- }
- default:
- {
- g_warn_if_reached( );
- break;
- }
- }
- }
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-// Signal Handlers
-// ---------------------------------------------------------------------------------------------------------------------
-
-//
-// Called by the notification list view to create a widget for displaying a notification.
-//
-void foobar_control_center_handle_notification_setup(
- GtkListItemFactory* factory,
- GtkListItem* list_item,
- gpointer userdata )
-{
- (void)factory;
- FoobarControlCenter* self = (FoobarControlCenter*)userdata;
-
- GtkWidget* widget = foobar_notification_widget_new( );
- foobar_notification_widget_set_close_action( FOOBAR_NOTIFICATION_WIDGET( widget ), FOOBAR_TYPE_NOTIFICATION_CLOSE_ACTION_REMOVE );
- foobar_notification_widget_set_time_format( FOOBAR_NOTIFICATION_WIDGET( widget ), self->notification_time_format );
- foobar_notification_widget_set_min_height( FOOBAR_NOTIFICATION_WIDGET( widget ), self->notification_min_height );
- foobar_notification_widget_set_close_button_inset( FOOBAR_NOTIFICATION_WIDGET( widget ), self->notification_close_button_inset );
- foobar_notification_widget_set_inset_start( FOOBAR_NOTIFICATION_WIDGET( widget ), self->padding );
- foobar_notification_widget_set_inset_end( FOOBAR_NOTIFICATION_WIDGET( widget ), self->padding );
- foobar_notification_widget_set_inset_top( FOOBAR_NOTIFICATION_WIDGET( widget ), self->spacing / 2 );
- foobar_notification_widget_set_inset_bottom( FOOBAR_NOTIFICATION_WIDGET( widget ), self->spacing / 2 );
- gtk_list_item_set_child( list_item, widget );
-
- {
- GtkExpression* item_expr = gtk_property_expression_new( GTK_TYPE_LIST_ITEM, NULL, "item" );
- gtk_expression_bind( item_expr, widget, "notification", list_item );
- }
-}
-
-//
-// Called by the wi-fi details list view to create a widget for displaying a network.
-//
-void foobar_control_center_handle_network_setup(
- GtkListItemFactory* factory,
- GtkListItem* list_item,
- gpointer userdata )
-{
- (void)factory;
- FoobarControlCenter* self = (FoobarControlCenter*)userdata;
-
- GtkWidget* item = foobar_control_details_item_new( );
- gtk_widget_set_margin_start( item, self->padding );
- gtk_widget_set_margin_end( item, self->padding );
- gtk_list_item_set_child( list_item, item );
-
- {
- GtkExpression* item_expr = gtk_property_expression_new( GTK_TYPE_LIST_ITEM, NULL, "item" );
- GtkExpression* label_expr = gtk_property_expression_new( FOOBAR_TYPE_NETWORK, item_expr, "name" );
- gtk_expression_bind( label_expr, item, "label", list_item );
- }
-
- {
- GtkExpression* item_expr = gtk_property_expression_new( GTK_TYPE_LIST_ITEM, NULL, "item" );
- GtkExpression* checked_expr = gtk_property_expression_new( FOOBAR_TYPE_NETWORK, item_expr, "is-active" );
- gtk_expression_bind( checked_expr, item, "is-checked", list_item );
- }
-}
-
-//
-// Called by the bluetooth details list view to create a widget for displaying a device.
-//
-void foobar_control_center_handle_bluetooth_device_setup(
- GtkListItemFactory* factory,
- GtkListItem* list_item,
- gpointer userdata )
-{
- (void)factory;
- FoobarControlCenter* self = (FoobarControlCenter*)userdata;
-
- GtkWidget* item = foobar_control_details_item_new( );
- gtk_widget_set_margin_start( item, self->padding );
- gtk_widget_set_margin_end( item, self->padding );
- gtk_list_item_set_child( list_item, item );
-
- {
- GtkExpression* item_expr = gtk_property_expression_new( GTK_TYPE_LIST_ITEM, NULL, "item" );
- GtkExpression* label_expr = gtk_property_expression_new( FOOBAR_TYPE_BLUETOOTH_DEVICE, item_expr, "name" );
- gtk_expression_bind( label_expr, item, "label", list_item );
- }
-
- {
- GtkExpression* item_expr = gtk_property_expression_new( GTK_TYPE_LIST_ITEM, NULL, "item" );
- GtkExpression* state_expr = gtk_property_expression_new( FOOBAR_TYPE_BLUETOOTH_DEVICE, item_expr, "state" );
- GtkExpression* accessory_params[] = { state_expr };
- GtkExpression* accessory_expr = gtk_cclosure_expression_new(
- FOOBAR_TYPE_CONTROL_DETAILS_ACCESSORY,
- NULL,
- G_N_ELEMENTS( accessory_params ),
- accessory_params,
- G_CALLBACK( foobar_control_center_compute_bluetooth_device_accessory ),
- NULL,
- NULL );
- gtk_expression_bind( accessory_expr, item, "accessory", list_item );
- }
-}
-
-//
-// Called by the bluetooth details list view when a device was selected.
-//
-void foobar_control_center_handle_bluetooth_device_activate(
- GtkListView* view,
- guint position,
- gpointer userdata )
-{
- (void)view;
- (void)userdata;
-
- GListModel* device_list = G_LIST_MODEL( gtk_list_view_get_model( view ) );
- FoobarBluetoothDevice* device = g_list_model_get_item( device_list, position );
- foobar_bluetooth_device_toggle_connection( device );
-}
-
-//
-// Called by the audio details list view to create a widget for displaying a device.
-//
-void foobar_control_center_handle_audio_device_setup(
- GtkListItemFactory* factory,
- GtkListItem* list_item,
- gpointer userdata )
-{
- (void)factory;
- FoobarControlCenter* self = (FoobarControlCenter*)userdata;
-
- GtkWidget* item = foobar_control_details_item_new( );
- gtk_widget_set_margin_start( item, self->padding );
- gtk_widget_set_margin_end( item, self->padding );
- gtk_list_item_set_child( list_item, item );
-
- {
- GtkExpression* item_expr = gtk_property_expression_new( GTK_TYPE_LIST_ITEM, NULL, "item" );
- GtkExpression* label_expr = gtk_property_expression_new( FOOBAR_TYPE_AUDIO_DEVICE, item_expr, "description" );
- gtk_expression_bind( label_expr, item, "label", list_item );
- }
-
- {
- GtkExpression* item_expr = gtk_property_expression_new( GTK_TYPE_LIST_ITEM, NULL, "item" );
- GtkExpression* checked_expr = gtk_property_expression_new( FOOBAR_TYPE_AUDIO_DEVICE, item_expr, "is-default" );
- gtk_expression_bind( checked_expr, item, "is-checked", list_item );
- }
-}
-
-//
-// Called by the audio details list view when a device was selected.
-//
-void foobar_control_center_handle_audio_device_activate(
- GtkListView* view,
- guint position,
- gpointer userdata )
-{
- (void)view;
- (void)userdata;
-
- GListModel* device_list = G_LIST_MODEL( gtk_list_view_get_model( view ) );
- FoobarAudioDevice* device = g_list_model_get_item( device_list, position );
- foobar_audio_device_make_default( device );
-}
-
-//
-// Signal handler called when the global configuration file has changed.
-//
-void foobar_control_center_handle_config_change(
- GObject* object,
- GParamSpec* pspec,
- gpointer userdata )
-{
- (void)object;
- (void)pspec;
- FoobarControlCenter* self = (FoobarControlCenter*)userdata;
-
- FoobarConfiguration const* config = foobar_configuration_service_get_current( self->configuration_service );
- foobar_control_center_apply_configuration(
- self,
- foobar_configuration_get_control_center( config ),
- foobar_configuration_get_notifications( config ) );
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-// Value Converters
-// ---------------------------------------------------------------------------------------------------------------------
-
-//
-// Derive the item accessory from a bluetooth device's connection state.
-//
-FoobarControlDetailsAccessory foobar_control_center_compute_bluetooth_device_accessory(
- GtkExpression* expression,
- FoobarBluetoothDeviceState state,
- gpointer userdata )
-{
- (void)expression;
- (void)userdata;
-
- switch ( state )
- {
- case FOOBAR_BLUETOOTH_DEVICE_STATE_DISCONNECTED:
- return FOOBAR_CONTROL_DETAILS_ACCESSORY_NONE;
- case FOOBAR_BLUETOOTH_DEVICE_STATE_CONNECTING:
- return FOOBAR_CONTROL_DETAILS_ACCESSORY_PROGRESS;
- case FOOBAR_BLUETOOTH_DEVICE_STATE_CONNECTED:
- return FOOBAR_CONTROL_DETAILS_ACCESSORY_CHECKED;
- default:
- g_warn_if_reached( );
- return FOOBAR_CONTROL_DETAILS_ACCESSORY_NONE;
- }
-}
-
-//
-// Derive the visible child in the "notifications" stack from the number of notifications.
-//
-// If there are no notifications, a placeholder is shown.
-//
-gchar* foobar_control_center_compute_visible_notification_child_name(
- GtkExpression* expression,
- guint count,
- gpointer userdata )
-{
- (void)expression;
- (void)userdata;
-
- return count > 0 ? g_strdup( STACK_ITEM_LIST ) : g_strdup( STACK_ITEM_PLACEHOLDER );
-}