From 1af3d14f3f995645a0de08a54b244c19840709e9 Mon Sep 17 00:00:00 2001 From: Hannes Schulze Date: Thu, 19 Jun 2025 23:17:58 +0200 Subject: init hs project --- src/widgets/control-center/control-button.c | 496 ----------- src/widgets/control-center/control-button.h | 31 - src/widgets/control-center/control-details-item.c | 307 ------- src/widgets/control-center/control-details-item.h | 32 - src/widgets/control-center/control-details.c | 289 ------- src/widgets/control-center/control-details.h | 22 - src/widgets/control-center/control-slider.c | 428 ---------- src/widgets/control-center/control-slider.h | 28 - src/widgets/control-center/meson.build | 6 - src/widgets/inset-container.c | 363 -------- src/widgets/inset-container.h | 22 - src/widgets/limit-container.c | 341 -------- src/widgets/limit-container.h | 22 - src/widgets/meson.build | 8 - src/widgets/notification-widget.c | 821 ------------------- src/widgets/notification-widget.h | 50 -- src/widgets/panel/meson.build | 7 - src/widgets/panel/panel-item-clock.c | 152 ---- src/widgets/panel/panel-item-clock.h | 15 - src/widgets/panel/panel-item-icon.c | 92 --- src/widgets/panel/panel-item-icon.h | 13 - src/widgets/panel/panel-item-status.c | 955 ---------------------- src/widgets/panel/panel-item-status.h | 25 - src/widgets/panel/panel-item-workspaces.c | 327 -------- src/widgets/panel/panel-item-workspaces.h | 16 - src/widgets/panel/panel-item.c | 195 ----- src/widgets/panel/panel-item.h | 23 - 27 files changed, 5086 deletions(-) delete mode 100644 src/widgets/control-center/control-button.c delete mode 100644 src/widgets/control-center/control-button.h delete mode 100644 src/widgets/control-center/control-details-item.c delete mode 100644 src/widgets/control-center/control-details-item.h delete mode 100644 src/widgets/control-center/control-details.c delete mode 100644 src/widgets/control-center/control-details.h delete mode 100644 src/widgets/control-center/control-slider.c delete mode 100644 src/widgets/control-center/control-slider.h delete mode 100644 src/widgets/control-center/meson.build delete mode 100644 src/widgets/inset-container.c delete mode 100644 src/widgets/inset-container.h delete mode 100644 src/widgets/limit-container.c delete mode 100644 src/widgets/limit-container.h delete mode 100644 src/widgets/meson.build delete mode 100644 src/widgets/notification-widget.c delete mode 100644 src/widgets/notification-widget.h delete mode 100644 src/widgets/panel/meson.build delete mode 100644 src/widgets/panel/panel-item-clock.c delete mode 100644 src/widgets/panel/panel-item-clock.h delete mode 100644 src/widgets/panel/panel-item-icon.c delete mode 100644 src/widgets/panel/panel-item-icon.h delete mode 100644 src/widgets/panel/panel-item-status.c delete mode 100644 src/widgets/panel/panel-item-status.h delete mode 100644 src/widgets/panel/panel-item-workspaces.c delete mode 100644 src/widgets/panel/panel-item-workspaces.h delete mode 100644 src/widgets/panel/panel-item.c delete mode 100644 src/widgets/panel/panel-item.h (limited to 'src/widgets') diff --git a/src/widgets/control-center/control-button.c b/src/widgets/control-center/control-button.c deleted file mode 100644 index 5b6d991..0000000 --- a/src/widgets/control-center/control-button.c +++ /dev/null @@ -1,496 +0,0 @@ -#include "widgets/control-center/control-button.h" - -// -// FoobarControlButton: -// -// A button in the "controls" section of the control center. This can be a regular button or a toggle button with an -// optional secondary button to toggle a details view. -// - -struct _FoobarControlButton -{ - GtkWidget parent_instance; - gchar* icon_name; - gchar* label; - gboolean can_expand; - gboolean can_toggle; - gboolean is_expanded; - gboolean is_toggled; -}; - -enum -{ - PROP_ICON_NAME = 1, - PROP_LABEL, - PROP_CAN_EXPAND, - PROP_CAN_TOGGLE, - PROP_IS_EXPANDED, - PROP_IS_TOGGLED, - N_PROPS, -}; - -static GParamSpec* props[N_PROPS] = { 0 }; - -static void foobar_control_button_class_init ( FoobarControlButtonClass* klass ); -static void foobar_control_button_init ( FoobarControlButton* self ); -static void foobar_control_button_get_property ( GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ); -static void foobar_control_button_set_property ( GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ); -static void foobar_control_button_dispose ( GObject* object ); -static void foobar_control_button_finalize ( GObject* object ); -static void foobar_control_button_handle_primary_clicked( GtkButton* button, - gpointer userdata ); -static void foobar_control_button_handle_expand_clicked ( GtkButton* button, - gpointer userdata ); - -G_DEFINE_FINAL_TYPE( FoobarControlButton, foobar_control_button, GTK_TYPE_WIDGET ) - -// --------------------------------------------------------------------------------------------------------------------- -// Widget Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for control buttons. -// -void foobar_control_button_class_init( FoobarControlButtonClass* klass ) -{ - GtkWidgetClass* widget_klass = GTK_WIDGET_CLASS( klass ); - gtk_widget_class_set_css_name( widget_klass, "control-button" ); - gtk_widget_class_set_layout_manager_type( widget_klass, GTK_TYPE_BOX_LAYOUT ); - - GObjectClass* object_klass = G_OBJECT_CLASS( klass ); - object_klass->get_property = foobar_control_button_get_property; - object_klass->set_property = foobar_control_button_set_property; - object_klass->dispose = foobar_control_button_dispose; - object_klass->finalize = foobar_control_button_finalize; - - props[PROP_ICON_NAME] = g_param_spec_string( - "icon-name", - "Icon Name", - "Name of the icon to be displayed next to the label.", - NULL, - G_PARAM_READWRITE ); - props[PROP_LABEL] = g_param_spec_string( - "label", - "Label", - "The button's main label.", - NULL, - G_PARAM_READWRITE ); - props[PROP_CAN_EXPAND] = g_param_spec_boolean( - "can-expand", - "Can Expand", - "Indicates whether some details are hidden and can be revealed by a toggle button next to the main action.", - FALSE, - G_PARAM_READWRITE ); - props[PROP_CAN_TOGGLE] = g_param_spec_boolean( - "can-toggle", - "Can Toggle", - "Indicates whether the main button can be toggled.", - FALSE, - G_PARAM_READWRITE ); - props[PROP_IS_EXPANDED] = g_param_spec_boolean( - "is-expanded", - "Is Expanded", - "Indicates whether additional details should be shown.", - FALSE, - G_PARAM_READWRITE ); - props[PROP_IS_TOGGLED] = g_param_spec_boolean( - "is-toggled", - "Is Toggled", - "Indicates whether the main button is currently toggled.", - FALSE, - G_PARAM_READWRITE ); - g_object_class_install_properties( object_klass, N_PROPS, props ); -} - -// -// Instance initialization for control buttons. -// -void foobar_control_button_init( FoobarControlButton* self ) -{ - GtkWidget* icon = gtk_image_new( ); - gtk_widget_set_valign( icon, GTK_ALIGN_CENTER ); - g_object_bind_property( - self, - "icon-name", - icon, - "icon-name", - G_BINDING_SYNC_CREATE ); - - GtkWidget* label = gtk_label_new( NULL ); - gtk_widget_set_valign( label, GTK_ALIGN_CENTER ); - gtk_widget_set_hexpand( label, TRUE ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - gtk_label_set_xalign( GTK_LABEL( label ), 0 ); - g_object_bind_property( - self, - "label", - label, - "label", - G_BINDING_SYNC_CREATE ); - - GtkWidget* content = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 ); - gtk_box_append( GTK_BOX( content ), icon ); - gtk_box_append( GTK_BOX( content ), label ); - - GtkWidget* primary_button = gtk_button_new( ); - gtk_widget_add_css_class( primary_button, "primary" ); - gtk_widget_set_hexpand( primary_button, TRUE ); - gtk_button_set_child( GTK_BUTTON( primary_button ), content ); - g_object_bind_property( - self, - "can-toggle", - primary_button, - "sensitive", - G_BINDING_SYNC_CREATE ); - g_signal_connect( primary_button, "clicked", G_CALLBACK( foobar_control_button_handle_primary_clicked ), self ); - - GtkWidget* expand_button = gtk_button_new_from_icon_name( "fluent-chevron-right-symbolic" ); - gtk_widget_add_css_class( expand_button, "expand" ); - g_object_bind_property( - self, - "can-expand", - expand_button, - "visible", - G_BINDING_SYNC_CREATE ); - g_signal_connect( expand_button, "clicked", G_CALLBACK( foobar_control_button_handle_expand_clicked ), self ); - - GtkLayoutManager* layout = gtk_widget_get_layout_manager( GTK_WIDGET( self ) ); - gtk_orientable_set_orientation( GTK_ORIENTABLE( layout ), GTK_ORIENTATION_HORIZONTAL ); - gtk_widget_insert_before( primary_button, GTK_WIDGET( self ), NULL ); - gtk_widget_insert_before( expand_button, GTK_WIDGET( self ), NULL ); -} - -// -// Property getter implementation, mapping a property id to a method. -// -void foobar_control_button_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ) -{ - FoobarControlButton* self = (FoobarControlButton*)object; - - switch ( prop_id ) - { - case PROP_ICON_NAME: - g_value_set_string( value, foobar_control_button_get_icon_name( self ) ); - break; - case PROP_LABEL: - g_value_set_string( value, foobar_control_button_get_label( self ) ); - break; - case PROP_CAN_EXPAND: - g_value_set_boolean( value, foobar_control_button_can_expand( self ) ); - break; - case PROP_CAN_TOGGLE: - g_value_set_boolean( value, foobar_control_button_can_toggle( self ) ); - break; - case PROP_IS_EXPANDED: - g_value_set_boolean( value, foobar_control_button_is_expanded( self ) ); - break; - case PROP_IS_TOGGLED: - g_value_set_boolean( value, foobar_control_button_is_toggled( self ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Property setter implementation, mapping a property id to a method. -// -void foobar_control_button_set_property( - GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ) -{ - FoobarControlButton* self = (FoobarControlButton*)object; - - switch ( prop_id ) - { - case PROP_ICON_NAME: - foobar_control_button_set_icon_name( self, g_value_get_string( value ) ); - break; - case PROP_LABEL: - foobar_control_button_set_label( self, g_value_get_string( value ) ); - break; - case PROP_CAN_EXPAND: - foobar_control_button_set_can_expand( self, g_value_get_boolean( value ) ); - break; - case PROP_CAN_TOGGLE: - foobar_control_button_set_can_toggle( self, g_value_get_boolean( value ) ); - break; - case PROP_IS_EXPANDED: - foobar_control_button_set_expanded( self, g_value_get_boolean( value ) ); - break; - case PROP_IS_TOGGLED: - foobar_control_button_set_toggled( self, g_value_get_boolean( value ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Instance de-initialization for control buttons. -// -void foobar_control_button_dispose( GObject* object ) -{ - FoobarControlButton* self = (FoobarControlButton*)object; - - GtkWidget* child; - while ( ( child = gtk_widget_get_first_child( GTK_WIDGET( self ) ) ) ) - { - gtk_widget_unparent( child ); - } - - G_OBJECT_CLASS( foobar_control_button_parent_class )->dispose( object ); -} - -// -// Instance cleanup for control buttons. -// -void foobar_control_button_finalize( GObject* object ) -{ - FoobarControlButton* self = (FoobarControlButton*)object; - - g_clear_pointer( &self->icon_name, g_free ); - g_clear_pointer( &self->label, g_free ); - - G_OBJECT_CLASS( foobar_control_button_parent_class )->finalize( object ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new control button instance. -// -GtkWidget* foobar_control_button_new( void ) -{ - return g_object_new( FOOBAR_TYPE_CONTROL_BUTTON, NULL ); -} - -// -// Get the name of the icon to be displayed next to the label. -// -gchar const* foobar_control_button_get_icon_name( FoobarControlButton* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ), NULL ); - return self->icon_name; -} - -// -// Get the button's main label. -// -gchar const* foobar_control_button_get_label( FoobarControlButton* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ), NULL ); - return self->label; -} - -// -// Check whether some details are hidden and can be revealed by a toggle button next to the main action. -// -gboolean foobar_control_button_can_expand( FoobarControlButton* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ), FALSE ); - return self->can_expand; -} - -// -// Check whether the main button can be toggled. -// -gboolean foobar_control_button_can_toggle( FoobarControlButton* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ), FALSE ); - return self->can_toggle; -} - -// -// Check whether additional details should currently be shown. -// -gboolean foobar_control_button_is_expanded( FoobarControlButton* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ), FALSE ); - return self->is_expanded; -} - -// -// Check whether the main button is currently toggled. -// -gboolean foobar_control_button_is_toggled( FoobarControlButton* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ), FALSE ); - return self->is_toggled; -} - -// -// Update the name of the icon to be displayed next to the label. -// -void foobar_control_button_set_icon_name( - FoobarControlButton* self, - gchar const* value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ) ); - - if ( g_strcmp0( self->icon_name, value ) ) - { - g_clear_pointer( &self->icon_name, g_free ); - self->icon_name = g_strdup( value ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_ICON_NAME] ); - } -} - -// -// Update the button's main label. -// -void foobar_control_button_set_label( - FoobarControlButton* self, - gchar const* value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ) ); - - if ( g_strcmp0( self->label, value ) ) - { - g_clear_pointer( &self->label, g_free ); - self->label = g_strdup( value ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_LABEL] ); - } -} - -// -// Update whether some details are hidden and can be revealed by a toggle button next to the main action. -// -void foobar_control_button_set_can_expand( - FoobarControlButton* self, - gboolean value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ) ); - - if ( !value ) { foobar_control_button_set_expanded( self, FALSE ); } - - value = !!value; - if ( self->can_expand != value ) - { - self->can_expand = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_CAN_EXPAND] ); - } -} - -// -// Update whether the main button can be toggled. -// -void foobar_control_button_set_can_toggle( - FoobarControlButton* self, - gboolean value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ) ); - - if ( !value ) { foobar_control_button_set_toggled( self, FALSE ); } - - value = !!value; - if ( self->can_toggle != value ) - { - self->can_toggle = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_CAN_TOGGLE] ); - } -} - -// -// Update whether additional details are currently shown. -// -void foobar_control_button_set_expanded( - FoobarControlButton* self, - gboolean value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ) ); - - value = value && self->can_expand; - if ( self->is_expanded != value ) - { - self->is_expanded = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_IS_EXPANDED] ); - - if ( self->is_expanded ) - { - gtk_widget_add_css_class( GTK_WIDGET( self ), "expanded" ); - } - else - { - gtk_widget_remove_css_class( GTK_WIDGET( self ), "expanded" ); - } - } -} - -// -// Update whether the main button is currently toggled. -// -void foobar_control_button_set_toggled( - FoobarControlButton* self, - gboolean value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_BUTTON( self ) ); - - value = value && self->can_toggle; - if ( self->is_toggled != value ) - { - self->is_toggled = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_IS_TOGGLED] ); - - if ( self->is_toggled ) - { - gtk_widget_add_css_class( GTK_WIDGET( self ), "toggled" ); - } - else - { - gtk_widget_remove_css_class( GTK_WIDGET( self ), "toggled" ); - } - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// Signal Handlers -// --------------------------------------------------------------------------------------------------------------------- - -// -// Called when the primary button was clicked. -// -// If allowed, this will toggle the button. -// -void foobar_control_button_handle_primary_clicked( GtkButton* button, gpointer userdata ) -{ - (void)button; - FoobarControlButton* self = (FoobarControlButton*)userdata; - - if ( foobar_control_button_can_toggle( self ) ) - { - foobar_control_button_set_toggled( self, !foobar_control_button_is_toggled( self ) ); - } -} - -// -// Called when the expand button was clicked. -// -// If allowed, this will toggle the "expanded" state of the button. -// -void foobar_control_button_handle_expand_clicked( GtkButton* button, gpointer userdata ) -{ - (void)button; - FoobarControlButton* self = (FoobarControlButton*)userdata; - - if ( foobar_control_button_can_expand( self ) ) - { - foobar_control_button_set_expanded( self, !foobar_control_button_is_expanded( self ) ); - } -} diff --git a/src/widgets/control-center/control-button.h b/src/widgets/control-center/control-button.h deleted file mode 100644 index d4c3737..0000000 --- a/src/widgets/control-center/control-button.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_CONTROL_BUTTON foobar_control_button_get_type( ) - -G_DECLARE_FINAL_TYPE( FoobarControlButton, foobar_control_button, FOOBAR, CONTROL_BUTTON, GtkWidget ) - -GtkWidget* foobar_control_button_new ( void ); -gchar const* foobar_control_button_get_icon_name ( FoobarControlButton* self ); -gchar const* foobar_control_button_get_label ( FoobarControlButton* self ); -gboolean foobar_control_button_can_expand ( FoobarControlButton* self ); -gboolean foobar_control_button_can_toggle ( FoobarControlButton* self ); -gboolean foobar_control_button_is_expanded ( FoobarControlButton* self ); -gboolean foobar_control_button_is_toggled ( FoobarControlButton* self ); -void foobar_control_button_set_icon_name ( FoobarControlButton* self, - gchar const* value ); -void foobar_control_button_set_label ( FoobarControlButton* self, - gchar const* value ); -void foobar_control_button_set_can_expand( FoobarControlButton* self, - gboolean value ); -void foobar_control_button_set_can_toggle( FoobarControlButton* self, - gboolean value ); -void foobar_control_button_set_expanded ( FoobarControlButton* self, - gboolean value ); -void foobar_control_button_set_toggled ( FoobarControlButton* self, - gboolean value ); - -G_END_DECLS diff --git a/src/widgets/control-center/control-details-item.c b/src/widgets/control-center/control-details-item.c deleted file mode 100644 index cb54dd3..0000000 --- a/src/widgets/control-center/control-details-item.c +++ /dev/null @@ -1,307 +0,0 @@ -#include "widgets/control-center/control-details-item.h" - -// -// FoobarControlDetailsAccessory: -// -// The accessory shown next to an item in the control center details list (if any). -// - -G_DEFINE_ENUM_TYPE( - FoobarControlDetailsAccessory, - foobar_control_details_accessory, - G_DEFINE_ENUM_VALUE( FOOBAR_CONTROL_DETAILS_ACCESSORY_NONE, "none" ), - G_DEFINE_ENUM_VALUE( FOOBAR_CONTROL_DETAILS_ACCESSORY_PROGRESS, "progress" ), - G_DEFINE_ENUM_VALUE( FOOBAR_CONTROL_DETAILS_ACCESSORY_CHECKED, "checked" ) ) - -// -// FoobarControlDetailsItem: -// -// Standard row layout for items in a FoobarControlDetails list. The rows are made up of a label and an accessory that -// is shown or hidden depending on the item's state. -// - -struct _FoobarControlDetailsItem -{ - GtkWidget parent_instance; - GtkWidget* spinner; - GtkWidget* checkmark; - gchar* label; - FoobarControlDetailsAccessory accessory; -}; - -enum -{ - PROP_LABEL = 1, - PROP_ACCESSORY, - PROP_IS_CHECKED, - N_PROPS, -}; - -static GParamSpec* props[N_PROPS] = { 0 }; - -static void foobar_control_details_item_class_init ( FoobarControlDetailsItemClass* klass ); -static void foobar_control_details_item_init ( FoobarControlDetailsItem* self ); -static void foobar_control_details_item_get_property( GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ); -static void foobar_control_details_item_set_property( GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ); -static void foobar_control_details_item_dispose ( GObject* object ); -static void foobar_control_details_item_finalize ( GObject* object ); - -G_DEFINE_FINAL_TYPE( FoobarControlDetailsItem, foobar_control_details_item, GTK_TYPE_WIDGET ) - -// --------------------------------------------------------------------------------------------------------------------- -// Widget Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for control details items. -// -void foobar_control_details_item_class_init( FoobarControlDetailsItemClass* klass ) -{ - GtkWidgetClass* widget_klass = GTK_WIDGET_CLASS( klass ); - gtk_widget_class_set_css_name( widget_klass, "control-details-item" ); - gtk_widget_class_set_layout_manager_type( widget_klass, GTK_TYPE_BOX_LAYOUT ); - - GObjectClass* object_klass = G_OBJECT_CLASS( klass ); - object_klass->get_property = foobar_control_details_item_get_property; - object_klass->set_property = foobar_control_details_item_set_property; - object_klass->dispose = foobar_control_details_item_dispose; - object_klass->finalize = foobar_control_details_item_finalize; - - props[PROP_LABEL] = g_param_spec_string( - "label", - "Label", - "Label shown for the item.", - NULL, - G_PARAM_READWRITE ); - props[PROP_ACCESSORY] = g_param_spec_enum( - "accessory", - "Accessory", - "Accessory shown for the item.", - FOOBAR_TYPE_CONTROL_DETAILS_ACCESSORY, - 0, - G_PARAM_READWRITE ); - props[PROP_IS_CHECKED] = g_param_spec_boolean( - "is-checked", - "Is Checked", - "Current checked-state for the item.", - FALSE, - G_PARAM_READWRITE ); - g_object_class_install_properties( object_klass, N_PROPS, props ); -} - -// -// Instance initialization for control details items. -// -void foobar_control_details_item_init( FoobarControlDetailsItem* self ) -{ - GtkWidget* label = gtk_label_new( NULL ); - gtk_widget_set_hexpand( label, TRUE ); - gtk_widget_set_valign( label, GTK_ALIGN_CENTER ); - gtk_label_set_ellipsize( GTK_LABEL( label ), PANGO_ELLIPSIZE_END ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - gtk_label_set_xalign( GTK_LABEL( label ), 0 ); - gtk_label_set_wrap( GTK_LABEL( label ), FALSE ); - g_object_bind_property( - self, - "label", - label, - "label", - G_BINDING_SYNC_CREATE ); - - self->spinner = gtk_spinner_new( ); - gtk_spinner_set_spinning( GTK_SPINNER( self->spinner ), TRUE ); - gtk_widget_add_css_class( self->spinner, "accessory" ); - gtk_widget_set_valign( self->spinner, GTK_ALIGN_CENTER ); - gtk_widget_set_visible( self->spinner, FALSE ); - - self->checkmark = gtk_image_new_from_icon_name( "fluent-checkmark-symbolic" ); - gtk_widget_add_css_class( self->checkmark, "checkmark" ); - gtk_widget_add_css_class( self->checkmark, "accessory" ); - gtk_widget_set_valign( self->checkmark, GTK_ALIGN_CENTER ); - gtk_widget_set_visible( self->checkmark, FALSE ); - - gtk_widget_insert_before( label, GTK_WIDGET( self ), NULL ); - gtk_widget_insert_before( self->spinner, GTK_WIDGET( self ), NULL ); - gtk_widget_insert_before( self->checkmark, GTK_WIDGET( self ), NULL ); -} - -// -// Property getter implementation, mapping a property id to a method. -// -void foobar_control_details_item_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ) -{ - FoobarControlDetailsItem* self = (FoobarControlDetailsItem*)object; - - switch ( prop_id ) - { - case PROP_LABEL: - g_value_set_string( value, foobar_control_details_item_get_label( self ) ); - break; - case PROP_ACCESSORY: - g_value_set_enum( value, foobar_control_details_item_get_accessory( self ) ); - break; - case PROP_IS_CHECKED: - g_value_set_boolean( value, foobar_control_details_item_is_checked( self ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Property setter implementation, mapping a property id to a method. -// -void foobar_control_details_item_set_property( - GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ) -{ - FoobarControlDetailsItem* self = (FoobarControlDetailsItem*)object; - - switch ( prop_id ) - { - case PROP_LABEL: - foobar_control_details_item_set_label( self, g_value_get_string( value ) ); - break; - case PROP_ACCESSORY: - foobar_control_details_item_set_accessory( self, g_value_get_enum( value ) ); - break; - case PROP_IS_CHECKED: - foobar_control_details_item_set_checked( self, g_value_get_boolean( value ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Instance de-initialization for control details items. -// -void foobar_control_details_item_dispose( GObject* object ) -{ - FoobarControlDetailsItem* self = (FoobarControlDetailsItem*)object; - - GtkWidget* child; - while ( ( child = gtk_widget_get_first_child( GTK_WIDGET( self ) ) ) ) - { - gtk_widget_unparent( child ); - } - - G_OBJECT_CLASS( foobar_control_details_item_parent_class )->dispose( object ); -} - -// -// Instance cleanup for control details items. -// -void foobar_control_details_item_finalize( GObject* object ) -{ - FoobarControlDetailsItem* self = (FoobarControlDetailsItem*)object; - - g_clear_pointer( &self->label, g_free ); - - G_OBJECT_CLASS( foobar_control_details_item_parent_class )->finalize( object ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new control details item instance. -// -GtkWidget* foobar_control_details_item_new( void ) -{ - return g_object_new( FOOBAR_TYPE_CONTROL_DETAILS_ITEM, NULL ); -} - -// -// Get the label shown for the item. -// -gchar const* foobar_control_details_item_get_label( FoobarControlDetailsItem* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ), NULL ); - return self->label; -} - -// -// Get the accessory shown for the item. -// -FoobarControlDetailsAccessory foobar_control_details_item_get_accessory( FoobarControlDetailsItem* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ), 0 ); - return self->accessory; -} - -// -// Get the current checked-state for the item. -// -gboolean foobar_control_details_item_is_checked( FoobarControlDetailsItem* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ), FALSE ); - return self->accessory == FOOBAR_CONTROL_DETAILS_ACCESSORY_CHECKED; -} - -// -// Update the label shown for the item. -// -void foobar_control_details_item_set_label( - FoobarControlDetailsItem* self, - gchar const* value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ) ); - - if ( g_strcmp0( self->label, value ) ) - { - g_clear_pointer( &self->label, g_free ); - self->label = g_strdup( value ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_LABEL] ); - } -} - -// -// Update the current accessory shown for the item. -// -void foobar_control_details_item_set_accessory( - FoobarControlDetailsItem* self, - FoobarControlDetailsAccessory value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ) ); - - if ( self->accessory != value ) - { - self->accessory = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_ACCESSORY] ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_IS_CHECKED] ); - - gtk_widget_set_visible( self->spinner, self->accessory == FOOBAR_CONTROL_DETAILS_ACCESSORY_PROGRESS ); - gtk_widget_set_visible( self->checkmark, self->accessory == FOOBAR_CONTROL_DETAILS_ACCESSORY_CHECKED ); - } -} - -// -// Update the current checked-state for the item. -// -void foobar_control_details_item_set_checked( - FoobarControlDetailsItem* self, - gboolean value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ) ); - - FoobarControlDetailsAccessory accessory = value - ? FOOBAR_CONTROL_DETAILS_ACCESSORY_CHECKED - : FOOBAR_CONTROL_DETAILS_ACCESSORY_NONE; - foobar_control_details_item_set_accessory( self, accessory ); -} diff --git a/src/widgets/control-center/control-details-item.h b/src/widgets/control-center/control-details-item.h deleted file mode 100644 index ff890f9..0000000 --- a/src/widgets/control-center/control-details-item.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_CONTROL_DETAILS_ACCESSORY foobar_control_details_accessory_get_type( ) -#define FOOBAR_TYPE_CONTROL_DETAILS_ITEM foobar_control_details_item_get_type( ) - -typedef enum -{ - FOOBAR_CONTROL_DETAILS_ACCESSORY_NONE, - FOOBAR_CONTROL_DETAILS_ACCESSORY_CHECKED, - FOOBAR_CONTROL_DETAILS_ACCESSORY_PROGRESS, -} FoobarControlDetailsAccessory; - -GType foobar_control_details_accessory_get_type( void ); - -G_DECLARE_FINAL_TYPE( FoobarControlDetailsItem, foobar_control_details_item, FOOBAR, CONTROL_DETAILS_ITEM, GtkWidget ) - -GtkWidget* foobar_control_details_item_new ( void ); -gchar const* foobar_control_details_item_get_label ( FoobarControlDetailsItem* self ); -FoobarControlDetailsAccessory foobar_control_details_item_get_accessory( FoobarControlDetailsItem* self ); -gboolean foobar_control_details_item_is_checked ( FoobarControlDetailsItem* self ); -void foobar_control_details_item_set_label ( FoobarControlDetailsItem* self, - gchar const* value ); -void foobar_control_details_item_set_accessory( FoobarControlDetailsItem* self, - FoobarControlDetailsAccessory value ); -void foobar_control_details_item_set_checked ( FoobarControlDetailsItem* self, - gboolean value ); - -G_END_DECLS diff --git a/src/widgets/control-center/control-details.c b/src/widgets/control-center/control-details.c deleted file mode 100644 index 72a90aa..0000000 --- a/src/widgets/control-center/control-details.c +++ /dev/null @@ -1,289 +0,0 @@ -#include "widgets/control-center/control-details.h" - -// -// FoobarControlDetails: -// -// A revealer for details in the "controls" section of the control center. This widget is usually used to embed a list -// view. It takes care of scrolling by embedding the child in a GtkScrolledWindow. -// - -struct _FoobarControlDetails -{ - GtkWidget parent_instance; - GtkWidget* child; - gboolean is_expanded; - gint inset_top; -}; - -enum -{ - PROP_CHILD = 1, - PROP_IS_EXPANDED, - PROP_INSET_TOP, - N_PROPS, -}; - -static GParamSpec* props[N_PROPS] = { 0 }; - -static void foobar_control_details_class_init ( FoobarControlDetailsClass* klass ); -static void foobar_control_details_init ( FoobarControlDetails* self ); -static void foobar_control_details_get_property( GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ); -static void foobar_control_details_set_property( GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ); -static void foobar_control_details_dispose ( GObject* object ); - -G_DEFINE_FINAL_TYPE( FoobarControlDetails, foobar_control_details, GTK_TYPE_WIDGET ) - -// --------------------------------------------------------------------------------------------------------------------- -// Widget Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for control details. -// -void foobar_control_details_class_init( FoobarControlDetailsClass* klass ) -{ - GtkWidgetClass* widget_klass = GTK_WIDGET_CLASS( klass ); - gtk_widget_class_set_css_name( widget_klass, "control-details" ); - gtk_widget_class_set_layout_manager_type( widget_klass, GTK_TYPE_BIN_LAYOUT ); - - GObjectClass* object_klass = G_OBJECT_CLASS( klass ); - object_klass->get_property = foobar_control_details_get_property; - object_klass->set_property = foobar_control_details_set_property; - object_klass->dispose = foobar_control_details_dispose; - - props[PROP_CHILD] = g_param_spec_object( - "child", - "Child", - "Child widget for the details revealer.", - GTK_TYPE_WIDGET, - G_PARAM_READWRITE ); - props[PROP_IS_EXPANDED] = g_param_spec_boolean( - "is-expanded", - "Is Expanded", - "Current state of the details revealer.", - FALSE, - G_PARAM_READWRITE ); - props[PROP_INSET_TOP] = g_param_spec_int( - "inset-top", - "Inset Top", - "Inset from the top edge (only visible when expanded).", - 0, - INT_MAX, - 0, - G_PARAM_READWRITE ); - g_object_class_install_properties( object_klass, N_PROPS, props ); -} - -// -// Instance initialization for control details. -// -void foobar_control_details_init( FoobarControlDetails* self ) -{ - GtkWidget* scrolled_window = gtk_scrolled_window_new( ); - gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolled_window ), GTK_POLICY_NEVER, GTK_POLICY_EXTERNAL ); - gtk_scrolled_window_set_propagate_natural_height( GTK_SCROLLED_WINDOW( scrolled_window ), TRUE ); - g_object_bind_property( - self, - "child", - scrolled_window, - "child", - G_BINDING_SYNC_CREATE ); - g_object_bind_property( - self, - "inset-top", - scrolled_window, - "margin-top", - G_BINDING_SYNC_CREATE ); - - GtkWidget* revealer = gtk_revealer_new( ); - gtk_revealer_set_transition_type( GTK_REVEALER( revealer ), GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN ); - gtk_revealer_set_transition_duration( GTK_REVEALER( revealer ), 100 ); - gtk_revealer_set_child( GTK_REVEALER( revealer ), scrolled_window ); - g_object_bind_property( - self, - "is-expanded", - revealer, - "reveal-child", - G_BINDING_SYNC_CREATE ); - - gtk_widget_set_parent( revealer, GTK_WIDGET( self ) ); -} - -// -// Property getter implementation, mapping a property id to a method. -// -void foobar_control_details_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ) -{ - FoobarControlDetails* self = (FoobarControlDetails*)object; - - switch ( prop_id ) - { - case PROP_CHILD: - g_value_set_object( value, foobar_control_details_get_child( self ) ); - break; - case PROP_IS_EXPANDED: - g_value_set_boolean( value, foobar_control_details_is_expanded( self ) ); - break; - case PROP_INSET_TOP: - g_value_set_int( value, foobar_control_details_get_inset_top( self ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Property setter implementation, mapping a property id to a method. -// -void foobar_control_details_set_property( - GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ) -{ - FoobarControlDetails* self = (FoobarControlDetails*)object; - - switch ( prop_id ) - { - case PROP_CHILD: - foobar_control_details_set_child( self, g_value_get_object( value ) ); - break; - case PROP_IS_EXPANDED: - foobar_control_details_set_expanded( self, g_value_get_boolean( value ) ); - break; - case PROP_INSET_TOP: - foobar_control_details_set_inset_top( self, g_value_get_int( value ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Instance de-initialization for control details. -// -void foobar_control_details_dispose( GObject* object ) -{ - FoobarControlDetails* self = (FoobarControlDetails*)object; - - GtkWidget* child; - while ( ( child = gtk_widget_get_first_child( GTK_WIDGET( self ) ) ) ) - { - gtk_widget_unparent( child ); - } - - g_clear_object( &self->child ); - - G_OBJECT_CLASS( foobar_control_details_parent_class )->dispose( object ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new control details instance. -// -GtkWidget* foobar_control_details_new( void ) -{ - return g_object_new( FOOBAR_TYPE_CONTROL_DETAILS, NULL ); -} - -// -// Get the child widget for the details revealer. -// -GtkWidget* foobar_control_details_get_child( FoobarControlDetails* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ), NULL ); - return self->child; -} - -// -// Get the current state of the details revealer. -// -gboolean foobar_control_details_is_expanded( FoobarControlDetails* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ), FALSE ); - return self->is_expanded; -} - -// -// Get the inset from the top edge (only visible when expanded). -// -gint foobar_control_details_get_inset_top( FoobarControlDetails* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ), FALSE ); - return self->inset_top; -} - -// -// Update the child widget for the details revealer. -// -void foobar_control_details_set_child( - FoobarControlDetails* self, - GtkWidget* value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ) ); - - if ( self->child != value ) - { - g_clear_object( &self->child ); - if ( value ) { self->child = g_object_ref( value ); } - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_CHILD] ); - } -} - -// -// Update the current state of the details revealer. -// -void foobar_control_details_set_expanded( - FoobarControlDetails* self, - gboolean value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ) ); - - value = !!value; - if ( self->is_expanded != value ) - { - self->is_expanded = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_IS_EXPANDED] ); - - if ( self->is_expanded ) - { - gtk_widget_add_css_class( GTK_WIDGET( self ), "expanded" ); - } - else - { - gtk_widget_remove_css_class( GTK_WIDGET( self ), "expanded" ); - } - } -} - -// -// Update the inset from the top edge (only visible when expanded). -// -void foobar_control_details_set_inset_top( - FoobarControlDetails* self, - gint value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ) ); - - value = MAX( value, 0 ); - if ( self->inset_top != value ) - { - self->inset_top = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_INSET_TOP] ); - } -} diff --git a/src/widgets/control-center/control-details.h b/src/widgets/control-center/control-details.h deleted file mode 100644 index ba7b5ec..0000000 --- a/src/widgets/control-center/control-details.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_CONTROL_DETAILS foobar_control_details_get_type( ) - -G_DECLARE_FINAL_TYPE( FoobarControlDetails, foobar_control_details, FOOBAR, CONTROL_DETAILS, GtkWidget ) - -GtkWidget* foobar_control_details_new ( void ); -GtkWidget* foobar_control_details_get_child ( FoobarControlDetails* self ); -gboolean foobar_control_details_is_expanded ( FoobarControlDetails* self ); -gint foobar_control_details_get_inset_top( FoobarControlDetails* self ); -void foobar_control_details_set_child ( FoobarControlDetails* self, - GtkWidget* value ); -void foobar_control_details_set_expanded ( FoobarControlDetails* self, - gboolean value ); -void foobar_control_details_set_inset_top( FoobarControlDetails* self, - gint value ); - -G_END_DECLS diff --git a/src/widgets/control-center/control-slider.c b/src/widgets/control-center/control-slider.c deleted file mode 100644 index 9c69190..0000000 --- a/src/widgets/control-center/control-slider.c +++ /dev/null @@ -1,428 +0,0 @@ -#include "widgets/control-center/control-slider.h" - -// -// FoobarControlSlider: -// -// A slider in the "controls" section of the control center with a title and icon, as well as an optional secondary -// button to toggle a details view. -// - -struct _FoobarControlSlider -{ - GtkWidget parent_instance; - gchar* icon_name; - gchar* label; - gboolean can_expand; - gboolean is_expanded; - gint percentage; -}; - -enum -{ - PROP_ICON_NAME = 1, - PROP_LABEL, - PROP_CAN_EXPAND, - PROP_IS_EXPANDED, - PROP_PERCENTAGE, - N_PROPS, -}; - -static GParamSpec* props[N_PROPS] = { 0 }; - -static void foobar_control_slider_class_init ( FoobarControlSliderClass* klass ); -static void foobar_control_slider_init ( FoobarControlSlider* self ); -static void foobar_control_slider_get_property ( GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ); -static void foobar_control_slider_set_property ( GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ); -static void foobar_control_slider_dispose ( GObject* object ); -static void foobar_control_slider_finalize ( GObject* object ); -static void foobar_control_slider_handle_expand_clicked( GtkButton* button, - gpointer userdata ); - -G_DEFINE_FINAL_TYPE( FoobarControlSlider, foobar_control_slider, GTK_TYPE_WIDGET ) - -// --------------------------------------------------------------------------------------------------------------------- -// Widget Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for control sliders. -// -void foobar_control_slider_class_init( FoobarControlSliderClass* klass ) -{ - GtkWidgetClass* widget_klass = GTK_WIDGET_CLASS( klass ); - gtk_widget_class_set_css_name( widget_klass, "control-slider" ); - gtk_widget_class_set_layout_manager_type( widget_klass, GTK_TYPE_BOX_LAYOUT ); - - GObjectClass* object_klass = G_OBJECT_CLASS( klass ); - object_klass->get_property = foobar_control_slider_get_property; - object_klass->set_property = foobar_control_slider_set_property; - object_klass->dispose = foobar_control_slider_dispose; - object_klass->finalize = foobar_control_slider_finalize; - - props[PROP_ICON_NAME] = g_param_spec_string( - "icon-name", - "Icon Name", - "Name of the icon to be displayed next to the label.", - NULL, - G_PARAM_READWRITE ); - props[PROP_LABEL] = g_param_spec_string( - "label", - "Label", - "The slider's main label.", - NULL, - G_PARAM_READWRITE ); - props[PROP_CAN_EXPAND] = g_param_spec_boolean( - "can-expand", - "Can Expand", - "Indicates whether some details are hidden and can be revealed by a toggle button next to the slider.", - FALSE, - G_PARAM_READWRITE ); - props[PROP_IS_EXPANDED] = g_param_spec_boolean( - "is-expanded", - "Is Expanded", - "Indicates whether additional details should be shown.", - FALSE, - G_PARAM_READWRITE ); - props[PROP_PERCENTAGE] = g_param_spec_int( - "percentage", - "Percentage", - "Value shown by the slider.", - 0, - 100, - 0, - G_PARAM_READWRITE ); - g_object_class_install_properties( object_klass, N_PROPS, props ); -} - -// -// Instance initialization for control sliders. -// -void foobar_control_slider_init( FoobarControlSlider* self ) -{ - GtkWidget* icon = gtk_image_new( ); - gtk_widget_set_valign( icon, GTK_ALIGN_CENTER ); - g_object_bind_property( - self, - "icon-name", - icon, - "icon-name", - G_BINDING_SYNC_CREATE ); - - GtkWidget* label = gtk_label_new( NULL ); - gtk_widget_set_valign( label, GTK_ALIGN_CENTER ); - gtk_widget_set_hexpand( label, TRUE ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - gtk_label_set_xalign( GTK_LABEL( label ), 0 ); - g_object_bind_property( - self, - "label", - label, - "label", - G_BINDING_SYNC_CREATE ); - - GtkWidget* header = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 ); - gtk_box_append( GTK_BOX( header ), icon ); - gtk_box_append( GTK_BOX( header ), label ); - - GtkWidget* scale = gtk_scale_new_with_range( GTK_ORIENTATION_HORIZONTAL, 0, 100, 2 ); - g_object_bind_property( - self, - "percentage", - gtk_range_get_adjustment( GTK_RANGE( scale ) ), - "value", - G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL ); - - GtkWidget* primary_content = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 ); - gtk_widget_add_css_class( primary_content, "primary" ); - gtk_box_append( GTK_BOX( primary_content ), header ); - gtk_box_append( GTK_BOX( primary_content ), scale ); - - GtkWidget* expand_button = gtk_button_new_from_icon_name( "fluent-chevron-right-symbolic" ); - gtk_widget_add_css_class( expand_button, "expand" ); - g_object_bind_property( - self, - "can-expand", - expand_button, - "visible", - G_BINDING_SYNC_CREATE ); - g_signal_connect( expand_button, "clicked", G_CALLBACK( foobar_control_slider_handle_expand_clicked ), self ); - - GtkLayoutManager* layout = gtk_widget_get_layout_manager( GTK_WIDGET( self ) ); - gtk_orientable_set_orientation( GTK_ORIENTABLE( layout ), GTK_ORIENTATION_HORIZONTAL ); - gtk_widget_insert_before( primary_content, GTK_WIDGET( self ), NULL ); - gtk_widget_insert_before( expand_button, GTK_WIDGET( self ), NULL ); -} - -// -// Property getter implementation, mapping a property id to a method. -// -void foobar_control_slider_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ) -{ - FoobarControlSlider* self = (FoobarControlSlider*)object; - - switch ( prop_id ) - { - case PROP_ICON_NAME: - g_value_set_string( value, foobar_control_slider_get_icon_name( self ) ); - break; - case PROP_LABEL: - g_value_set_string( value, foobar_control_slider_get_label( self ) ); - break; - case PROP_CAN_EXPAND: - g_value_set_boolean( value, foobar_control_slider_can_expand( self ) ); - break; - case PROP_IS_EXPANDED: - g_value_set_boolean( value, foobar_control_slider_is_expanded( self ) ); - break; - case PROP_PERCENTAGE: - g_value_set_int( value, foobar_control_slider_get_percentage( self ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Property setter implementation, mapping a property id to a method. -// -void foobar_control_slider_set_property( - GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ) -{ - FoobarControlSlider* self = (FoobarControlSlider*)object; - - switch ( prop_id ) - { - case PROP_ICON_NAME: - foobar_control_slider_set_icon_name( self, g_value_get_string( value ) ); - break; - case PROP_LABEL: - foobar_control_slider_set_label( self, g_value_get_string( value ) ); - break; - case PROP_CAN_EXPAND: - foobar_control_slider_set_can_expand( self, g_value_get_boolean( value ) ); - break; - case PROP_IS_EXPANDED: - foobar_control_slider_set_expanded( self, g_value_get_boolean( value ) ); - break; - case PROP_PERCENTAGE: - foobar_control_slider_set_percentage( self, g_value_get_int( value ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Instance de-initialization for control sliders. -// -void foobar_control_slider_dispose( GObject* object ) -{ - FoobarControlSlider* self = (FoobarControlSlider*)object; - - GtkWidget* child; - while ( ( child = gtk_widget_get_first_child( GTK_WIDGET( self ) ) ) ) - { - gtk_widget_unparent( child ); - } - - G_OBJECT_CLASS( foobar_control_slider_parent_class )->dispose( object ); -} - -// -// Instance cleanup for control sliders. -// -void foobar_control_slider_finalize( GObject* object ) -{ - FoobarControlSlider* self = (FoobarControlSlider*)object; - - g_clear_pointer( &self->icon_name, g_free ); - g_clear_pointer( &self->label, g_free ); - - G_OBJECT_CLASS( foobar_control_slider_parent_class )->finalize( object ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new control slider instance. -// -GtkWidget* foobar_control_slider_new( void ) -{ - return g_object_new( FOOBAR_TYPE_CONTROL_SLIDER, NULL ); -} - -// -// Get the name of the icon to be displayed next to the label. -// -gchar const* foobar_control_slider_get_icon_name( FoobarControlSlider* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_SLIDER( self ), NULL ); - return self->icon_name; -} - -// -// Get the slider's main label. -// -gchar const* foobar_control_slider_get_label( FoobarControlSlider* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_SLIDER( self ), NULL ); - return self->label; -} - -// -// Check whether some details are hidden and can be revealed by a toggle button next to the slider. -// -gboolean foobar_control_slider_can_expand( FoobarControlSlider* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_SLIDER( self ), FALSE ); - return self->can_expand; -} - -// -// Check whether additional details should currently be shown. -// -gboolean foobar_control_slider_is_expanded( FoobarControlSlider* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_SLIDER( self ), FALSE ); - return self->is_expanded; -} - -// -// Get the value shown by the slider. -// -gint foobar_control_slider_get_percentage( FoobarControlSlider* self ) -{ - g_return_val_if_fail( FOOBAR_IS_CONTROL_SLIDER( self ), FALSE ); - return self->percentage; -} - -// -// Update the name of the icon to be displayed next to the label. -// -void foobar_control_slider_set_icon_name( - FoobarControlSlider* self, - gchar const* value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_SLIDER( self ) ); - - if ( g_strcmp0( self->icon_name, value ) ) - { - g_clear_pointer( &self->icon_name, g_free ); - self->icon_name = g_strdup( value ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_ICON_NAME] ); - } -} - -// -// Update the slider's main label. -// -void foobar_control_slider_set_label( - FoobarControlSlider* self, - gchar const* value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_SLIDER( self ) ); - - if ( g_strcmp0( self->label, value ) ) - { - g_clear_pointer( &self->label, g_free ); - self->label = g_strdup( value ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_LABEL] ); - } -} - -// -// Update whether some details are hidden and can be revealed by a toggle button next to the slider. -// -void foobar_control_slider_set_can_expand( - FoobarControlSlider* self, - gboolean value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_SLIDER( self ) ); - - if ( !value ) { foobar_control_slider_set_expanded( self, FALSE ); } - - value = !!value; - if ( self->can_expand != value ) - { - self->can_expand = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_CAN_EXPAND] ); - } -} - -// -// Update whether additional details are currently shown. -// -void foobar_control_slider_set_expanded( - FoobarControlSlider* self, - gboolean value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_SLIDER( self ) ); - - value = value && self->can_expand; - if ( self->is_expanded != value ) - { - self->is_expanded = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_IS_EXPANDED] ); - - if ( self->is_expanded ) - { - gtk_widget_add_css_class( GTK_WIDGET( self ), "expanded" ); - } - else - { - gtk_widget_remove_css_class( GTK_WIDGET( self ), "expanded" ); - } - } -} - -// -// Update the value shown by the slider. -// -void foobar_control_slider_set_percentage( FoobarControlSlider* self, gint value ) -{ - g_return_if_fail( FOOBAR_IS_CONTROL_SLIDER( self ) ); - - value = CLAMP( value, 0, 100 ); - if ( self->percentage != value ) - { - self->percentage = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_PERCENTAGE] ); - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// Signal Handlers -// --------------------------------------------------------------------------------------------------------------------- - -// -// Called when the expand button was clicked. -// -// If allowed, this will toggle the "expanded" state of the slider. -// -void foobar_control_slider_handle_expand_clicked( GtkButton* button, gpointer userdata ) -{ - (void)button; - FoobarControlSlider* self = (FoobarControlSlider*)userdata; - - if ( foobar_control_slider_can_expand( self ) ) - { - foobar_control_slider_set_expanded( self, !foobar_control_slider_is_expanded( self ) ); - } -} diff --git a/src/widgets/control-center/control-slider.h b/src/widgets/control-center/control-slider.h deleted file mode 100644 index f797b5c..0000000 --- a/src/widgets/control-center/control-slider.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_CONTROL_SLIDER foobar_control_slider_get_type( ) - -G_DECLARE_FINAL_TYPE( FoobarControlSlider, foobar_control_slider, FOOBAR, CONTROL_SLIDER, GtkWidget ) - -GtkWidget* foobar_control_slider_new ( void ); -gchar const* foobar_control_slider_get_icon_name ( FoobarControlSlider* self ); -gchar const* foobar_control_slider_get_label ( FoobarControlSlider* self ); -gboolean foobar_control_slider_can_expand ( FoobarControlSlider* self ); -gboolean foobar_control_slider_is_expanded ( FoobarControlSlider* self ); -gint foobar_control_slider_get_percentage( FoobarControlSlider* self ); -void foobar_control_slider_set_icon_name ( FoobarControlSlider* self, - gchar const* value ); -void foobar_control_slider_set_label ( FoobarControlSlider* self, - gchar const* value ); -void foobar_control_slider_set_can_expand( FoobarControlSlider* self, - gboolean value ); -void foobar_control_slider_set_expanded ( FoobarControlSlider* self, - gboolean value ); -void foobar_control_slider_set_percentage( FoobarControlSlider* self, - gint value ); - -G_END_DECLS diff --git a/src/widgets/control-center/meson.build b/src/widgets/control-center/meson.build deleted file mode 100644 index 2cdc9ca..0000000 --- a/src/widgets/control-center/meson.build +++ /dev/null @@ -1,6 +0,0 @@ -foobar_sources += files( - 'control-button.c', - 'control-slider.c', - 'control-details.c', - 'control-details-item.c', -) diff --git a/src/widgets/inset-container.c b/src/widgets/inset-container.c deleted file mode 100644 index 052f872..0000000 --- a/src/widgets/inset-container.c +++ /dev/null @@ -1,363 +0,0 @@ -#include "widgets/inset-container.h" - -// -// FoobarInsetContainer: -// -// A custom widget which renders a child with an inset/padding. -// -// Notably, it also supports negative inset values which is useful in order to provide uniform spacing between widgets. -// - -struct _FoobarInsetContainer -{ - GtkWidget parent_instance; - GtkWidget* child; - gint inset_horizontal; - gint inset_vertical; -}; - -enum -{ - PROP_CHILD = 1, - PROP_INSET_HORIZONTAL, - PROP_INSET_VERTICAL, - N_PROPS, -}; - -static GParamSpec* props[N_PROPS] = { 0 }; - -static void foobar_inset_container_class_init ( FoobarInsetContainerClass* klass ); -static void foobar_inset_container_init ( FoobarInsetContainer* self ); -static void foobar_inset_container_get_property ( GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ); -static void foobar_inset_container_set_property ( GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ); -static void foobar_inset_container_dispose ( GObject* object ); -static GtkSizeRequestMode foobar_inset_container_get_request_mode( GtkWidget* widget ); -static void foobar_inset_container_measure ( GtkWidget* widget, - GtkOrientation orientation, - int for_size, - int* minimum, - int* natural, - int* minimum_baseline, - int* natural_baseline ); -static void foobar_inset_container_size_allocate ( GtkWidget* widget, - int width, - int height, - int baseline ); - -G_DEFINE_FINAL_TYPE( FoobarInsetContainer, foobar_inset_container, GTK_TYPE_WIDGET ) - -// --------------------------------------------------------------------------------------------------------------------- -// Widget Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for inset containers. -// -void foobar_inset_container_class_init( FoobarInsetContainerClass* klass ) -{ - GtkWidgetClass* widget_klass = GTK_WIDGET_CLASS( klass ); - widget_klass->get_request_mode = foobar_inset_container_get_request_mode; - widget_klass->measure = foobar_inset_container_measure; - widget_klass->size_allocate = foobar_inset_container_size_allocate; - gtk_widget_class_set_css_name( widget_klass, "inset-container" ); - - GObjectClass* object_klass = G_OBJECT_CLASS( klass ); - object_klass->get_property = foobar_inset_container_get_property; - object_klass->set_property = foobar_inset_container_set_property; - object_klass->dispose = foobar_inset_container_dispose; - - props[PROP_CHILD] = g_param_spec_object( - "child", - "Child", - "Child widget for the panel item.", - GTK_TYPE_WIDGET, - G_PARAM_READWRITE ); - props[PROP_INSET_HORIZONTAL] = g_param_spec_int( - "inset-horizontal", - "Inset Horizontal", - "The horizontal offset (may be negative).", - INT_MIN, - INT_MAX, - 0, - G_PARAM_READWRITE ); - props[PROP_INSET_VERTICAL] = g_param_spec_int( - "inset-vertical", - "Inset Vertical", - "The vertical offset (may be negative).", - INT_MIN, - INT_MAX, - 0, - G_PARAM_READWRITE ); - g_object_class_install_properties( object_klass, N_PROPS, props ); -} - -// -// Instance initialization for inset containers. -// -void foobar_inset_container_init( FoobarInsetContainer* self ) -{ - (void)self; -} - -// -// Property getter implementation, mapping a property id to a method. -// -void foobar_inset_container_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ) -{ - FoobarInsetContainer* self = (FoobarInsetContainer*)object; - - switch ( prop_id ) - { - case PROP_CHILD: - g_value_set_object( value, foobar_inset_container_get_child( self ) ); - break; - case PROP_INSET_HORIZONTAL: - g_value_set_int( value, foobar_inset_container_get_inset_horizontal( self ) ); - break; - case PROP_INSET_VERTICAL: - g_value_set_int( value, foobar_inset_container_get_inset_vertical( self ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Property setter implementation, mapping a property id to a method. -// -void foobar_inset_container_set_property( - GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ) -{ - FoobarInsetContainer* self = (FoobarInsetContainer*)object; - - switch ( prop_id ) - { - case PROP_CHILD: - foobar_inset_container_set_child( self, g_value_get_object( value ) ); - break; - case PROP_INSET_HORIZONTAL: - foobar_inset_container_set_inset_horizontal( self, g_value_get_int( value ) ); - break; - case PROP_INSET_VERTICAL: - foobar_inset_container_set_inset_vertical( self, g_value_get_int( value ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Instance de-initialization for inset containers. -// -void foobar_inset_container_dispose( GObject* object ) -{ - FoobarInsetContainer* self = (FoobarInsetContainer*)object; - - g_clear_pointer( &self->child, gtk_widget_unparent ); - - G_OBJECT_CLASS( foobar_inset_container_parent_class )->dispose( object ); -} - -// -// Determine the size request mode used to measure the widget. -// -// This implementation just forwards the request mode from the child widget. -// -GtkSizeRequestMode foobar_inset_container_get_request_mode( GtkWidget* widget ) -{ - FoobarInsetContainer* self = (FoobarInsetContainer*)widget; - if ( !self->child ) { return GTK_SIZE_REQUEST_CONSTANT_SIZE; } - - return gtk_widget_get_request_mode( self->child ); -} - -// -// Compute the requested size of the widget. -// -// This implementation uses the size requested by the child widget and then adds the inset to it. -// -void foobar_inset_container_measure( - GtkWidget* widget, - GtkOrientation orientation, - int for_size, - int* minimum, - int* natural, - int* minimum_baseline, - int* natural_baseline ) -{ - FoobarInsetContainer* self = (FoobarInsetContainer*)widget; - if ( !self->child ) - { - *minimum = 0; - *natural = 0; - *minimum_baseline = 0; - *natural_baseline = 0; - return; - } - - // Get the inset for the given orientation and the other one. - - gint inset; - gint other_inset; - switch ( orientation ) - { - case GTK_ORIENTATION_HORIZONTAL: - inset = self->inset_horizontal; - other_inset = self->inset_vertical; - break; - case GTK_ORIENTATION_VERTICAL: - inset = self->inset_vertical; - other_inset = self->inset_horizontal; - break; - default: - g_warn_if_reached( ); - return; - } - - // Compute the new size, taking into consideration that the inset might have already been added to measure the other - // side and needs to be subtracted before passing it to the child widget's measure function. - - for_size = MAX( 0, for_size - ( 2 * other_inset ) ); - gtk_widget_measure( self->child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline ); - *minimum = MAX( 0, *minimum + ( 2 * inset ) ); - *natural = MAX( 0, *natural + ( 2 * inset ) ); - if ( orientation == GTK_ORIENTATION_VERTICAL ) - { - *minimum_baseline = MAX( 0, *minimum_baseline + inset ); - *natural_baseline = MAX( 0, *natural_baseline + inset ); - } -} - -// -// Arrange the child widget. -// -void foobar_inset_container_size_allocate( - GtkWidget* widget, - int width, - int height, - int baseline ) -{ - FoobarInsetContainer* self = (FoobarInsetContainer*)widget; - if ( !self->child ) { return; } - - GtkAllocation allocation = - { - .width = MAX( 0, width - 2 * self->inset_horizontal ), - .height = MAX( 0, height - 2 * self->inset_vertical ), - .x = self->inset_horizontal, - .y = self->inset_vertical, - }; - gtk_widget_size_allocate( self->child, &allocation, MAX( 0, baseline + self->inset_vertical ) ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new inset container instance. -// -GtkWidget* foobar_inset_container_new( void ) -{ - return g_object_new( FOOBAR_TYPE_INSET_CONTAINER, NULL ); -} - -// -// Get the container's child widget. -// -GtkWidget* foobar_inset_container_get_child( FoobarInsetContainer* self ) -{ - g_return_val_if_fail( FOOBAR_IS_INSET_CONTAINER( self ), NULL ); - return self->child; -} - -// -// Get the inset applied to the left and right side of the widget. -// -gint foobar_inset_container_get_inset_horizontal( FoobarInsetContainer* self ) -{ - g_return_val_if_fail( FOOBAR_IS_INSET_CONTAINER( self ), 0 ); - return self->inset_horizontal; -} - -// -// Get the inset applied to the top and bottom side of the widget. -// -gint foobar_inset_container_get_inset_vertical( FoobarInsetContainer* self ) -{ - g_return_val_if_fail( FOOBAR_IS_INSET_CONTAINER( self ), 0 ); - return self->inset_vertical; -} - -// -// Update the container's child widget. -// -void foobar_inset_container_set_child( - FoobarInsetContainer* self, - GtkWidget* child ) -{ - g_return_if_fail( FOOBAR_IS_INSET_CONTAINER( self ) ); - g_return_if_fail( child == NULL || self->child == child || gtk_widget_get_parent( child ) == NULL ); - - if ( self->child != child ) - { - g_clear_pointer( &self->child, gtk_widget_unparent ); - - if ( child ) - { - self->child = child; - gtk_widget_set_parent( child, GTK_WIDGET( self ) ); - } - - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_CHILD] ); - } -} - -// -// Update the inset applied to the left and right side of the widget. -// -void foobar_inset_container_set_inset_horizontal( - FoobarInsetContainer* self, - gint value ) -{ - g_return_if_fail( FOOBAR_IS_INSET_CONTAINER( self ) ); - - if ( self->inset_horizontal != value ) - { - self->inset_horizontal = value; - gtk_widget_queue_resize( GTK_WIDGET( self ) ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_INSET_HORIZONTAL] ); - } -} - -// -// Update the inset applied to the top and bottom side of the widget. -// -void foobar_inset_container_set_inset_vertical( - FoobarInsetContainer* self, - gint value ) -{ - g_return_if_fail( FOOBAR_IS_INSET_CONTAINER( self ) ); - - if ( self->inset_vertical != value ) - { - self->inset_vertical = value; - gtk_widget_queue_resize( GTK_WIDGET( self ) ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_INSET_VERTICAL] ); - } -} diff --git a/src/widgets/inset-container.h b/src/widgets/inset-container.h deleted file mode 100644 index 316d2be..0000000 --- a/src/widgets/inset-container.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_INSET_CONTAINER foobar_inset_container_get_type( ) - -G_DECLARE_FINAL_TYPE( FoobarInsetContainer, foobar_inset_container, FOOBAR, INSET_CONTAINER, GtkWidget ) - -GtkWidget* foobar_inset_container_new ( void ); -GtkWidget* foobar_inset_container_get_child ( FoobarInsetContainer* self ); -gint foobar_inset_container_get_inset_horizontal( FoobarInsetContainer* self ); -gint foobar_inset_container_get_inset_vertical ( FoobarInsetContainer* self ); -void foobar_inset_container_set_child ( FoobarInsetContainer* self, - GtkWidget* value ); -void foobar_inset_container_set_inset_horizontal( FoobarInsetContainer* self, - gint value ); -void foobar_inset_container_set_inset_vertical ( FoobarInsetContainer* self, - gint value ); - -G_END_DECLS diff --git a/src/widgets/limit-container.c b/src/widgets/limit-container.c deleted file mode 100644 index 123acef..0000000 --- a/src/widgets/limit-container.c +++ /dev/null @@ -1,341 +0,0 @@ -#include "widgets/limit-container.h" - -// -// FoobarLimitContainer: -// -// A container which uses the natural size requested by the child as its minimum size, but only up to a certain point. -// -// This is useful because gtk_scrolled_window_set_max_content_height doesn't seem to be doing what I understand it to -// do. This way, we can set propagate_natural_height to TRUE and then limit the height through this container. -// - -struct _FoobarLimitContainer -{ - GtkWidget parent_instance; - GtkWidget* child; - gint max_width; - gint max_height; -}; - -enum -{ - PROP_CHILD = 1, - PROP_MAX_WIDTH, - PROP_MAX_HEIGHT, - N_PROPS, -}; - -static GParamSpec* props[N_PROPS] = { 0 }; - -static void foobar_limit_container_class_init ( FoobarLimitContainerClass* klass ); -static void foobar_limit_container_init ( FoobarLimitContainer* self ); -static void foobar_limit_container_get_property ( GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ); -static void foobar_limit_container_set_property ( GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ); -static void foobar_limit_container_dispose ( GObject* object ); -static GtkSizeRequestMode foobar_limit_container_get_request_mode( GtkWidget* widget ); -static void foobar_limit_container_measure ( GtkWidget* widget, - GtkOrientation orientation, - int for_size, - int* minimum, - int* natural, - int* minimum_baseline, - int* natural_baseline ); -static void foobar_limit_container_size_allocate ( GtkWidget* widget, - int width, - int height, - int baseline ); - -G_DEFINE_FINAL_TYPE( FoobarLimitContainer, foobar_limit_container, GTK_TYPE_WIDGET ) - -// --------------------------------------------------------------------------------------------------------------------- -// Widget Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for limit containers. -// -void foobar_limit_container_class_init( FoobarLimitContainerClass* klass ) -{ - GtkWidgetClass* widget_klass = GTK_WIDGET_CLASS( klass ); - widget_klass->get_request_mode = foobar_limit_container_get_request_mode; - widget_klass->measure = foobar_limit_container_measure; - widget_klass->size_allocate = foobar_limit_container_size_allocate; - gtk_widget_class_set_css_name( widget_klass, "limit-container" ); - - GObjectClass* object_klass = G_OBJECT_CLASS( klass ); - object_klass->get_property = foobar_limit_container_get_property; - object_klass->set_property = foobar_limit_container_set_property; - object_klass->dispose = foobar_limit_container_dispose; - - props[PROP_CHILD] = g_param_spec_object( - "child", - "Child", - "Child widget for the panel item.", - GTK_TYPE_WIDGET, - G_PARAM_READWRITE ); - props[PROP_MAX_WIDTH] = g_param_spec_int( - "max-width", - "Max Width", - "The maximum natural width supported as a minimum size.", - 0, - INT_MAX, - 0, - G_PARAM_READWRITE ); - props[PROP_MAX_HEIGHT] = g_param_spec_int( - "max-height", - "Max Height", - "The maximum natural height supported as a minimum size.", - 0, - INT_MAX, - 0, - G_PARAM_READWRITE ); - g_object_class_install_properties( object_klass, N_PROPS, props ); -} - -// -// Instance initialization for limit containers. -// -void foobar_limit_container_init( FoobarLimitContainer* self ) -{ - (void)self; -} - -// -// Property getter implementation, mapping a property id to a method. -// -void foobar_limit_container_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ) -{ - FoobarLimitContainer* self = (FoobarLimitContainer*)object; - - switch ( prop_id ) - { - case PROP_CHILD: - g_value_set_object( value, foobar_limit_container_get_child( self ) ); - break; - case PROP_MAX_WIDTH: - g_value_set_int( value, foobar_limit_container_get_max_width( self ) ); - break; - case PROP_MAX_HEIGHT: - g_value_set_int( value, foobar_limit_container_get_max_height( self ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Property setter implementation, mapping a property id to a method. -// -void foobar_limit_container_set_property( - GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ) -{ - FoobarLimitContainer* self = (FoobarLimitContainer*)object; - - switch ( prop_id ) - { - case PROP_CHILD: - foobar_limit_container_set_child( self, g_value_get_object( value ) ); - break; - case PROP_MAX_WIDTH: - foobar_limit_container_set_max_width( self, g_value_get_int( value ) ); - break; - case PROP_MAX_HEIGHT: - foobar_limit_container_set_max_height( self, g_value_get_int( value ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Instance de-initialization for limit containers. -// -void foobar_limit_container_dispose( GObject* object ) -{ - FoobarLimitContainer* self = (FoobarLimitContainer*)object; - - g_clear_pointer( &self->child, gtk_widget_unparent ); - - G_OBJECT_CLASS( foobar_limit_container_parent_class )->dispose( object ); -} - -// -// Determine the size request mode used to measure the widget. -// -// This implementation just forwards the request mode from the child widget. -// -GtkSizeRequestMode foobar_limit_container_get_request_mode( GtkWidget* widget ) -{ - FoobarLimitContainer* self = (FoobarLimitContainer*)widget; - if ( !self->child ) { return GTK_SIZE_REQUEST_CONSTANT_SIZE; } - - return gtk_widget_get_request_mode( self->child ); -} - -// -// Compute the requested size of the widget. -// -void foobar_limit_container_measure( - GtkWidget* widget, - GtkOrientation orientation, - int for_size, - int* minimum, - int* natural, - int* minimum_baseline, - int* natural_baseline ) -{ - FoobarLimitContainer* self = (FoobarLimitContainer*)widget; - if ( !self->child ) - { - *minimum = 0; - *natural = 0; - *minimum_baseline = 0; - *natural_baseline = 0; - return; - } - - gtk_widget_measure( self->child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline ); - gint natural_minimum = *natural; - switch ( orientation ) - { - case GTK_ORIENTATION_HORIZONTAL: - natural_minimum = MIN( natural_minimum, self->max_width ); - break; - case GTK_ORIENTATION_VERTICAL: - natural_minimum = MIN( natural_minimum, self->max_height ); - break; - default: - g_warn_if_reached( ); - break; - } - *minimum = MAX( *minimum, natural_minimum ); -} - -// -// Arrange the child widget. -// -void foobar_limit_container_size_allocate( - GtkWidget* widget, - int width, - int height, - int baseline ) -{ - FoobarLimitContainer* self = (FoobarLimitContainer*)widget; - if ( !self->child ) { return; } - - gtk_widget_allocate( self->child, width, height, baseline, NULL ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new limit container instance. -// -GtkWidget* foobar_limit_container_new( void ) -{ - return g_object_new( FOOBAR_TYPE_LIMIT_CONTAINER, NULL ); -} - -// -// Get the container's child widget. -// -GtkWidget* foobar_limit_container_get_child( FoobarLimitContainer* self ) -{ - g_return_val_if_fail( FOOBAR_IS_LIMIT_CONTAINER( self ), NULL ); - return self->child; -} - -// -// Get the maximum natural width of the child to use as the minimum width for this container. -// -gint foobar_limit_container_get_max_width( FoobarLimitContainer* self ) -{ - g_return_val_if_fail( FOOBAR_IS_LIMIT_CONTAINER( self ), 0 ); - return self->max_width; -} - -// -// Get the maximum natural height of the child to use as the minimum height for this container. -// -gint foobar_limit_container_get_max_height( FoobarLimitContainer* self ) -{ - g_return_val_if_fail( FOOBAR_IS_LIMIT_CONTAINER( self ), 0 ); - return self->max_height; -} - -// -// Update the container's child widget. -// -void foobar_limit_container_set_child( - FoobarLimitContainer* self, - GtkWidget* child ) -{ - g_return_if_fail( FOOBAR_IS_LIMIT_CONTAINER( self ) ); - g_return_if_fail( child == NULL || self->child == child || gtk_widget_get_parent( child ) == NULL ); - - if ( self->child != child ) - { - g_clear_pointer( &self->child, gtk_widget_unparent ); - - if ( child ) - { - self->child = child; - gtk_widget_set_parent( child, GTK_WIDGET( self ) ); - } - - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_CHILD] ); - } -} - -// -// Update the maximum natural width of the child to use as the minimum width for this container. -// -void foobar_limit_container_set_max_width( - FoobarLimitContainer* self, - gint value ) -{ - g_return_if_fail( FOOBAR_IS_LIMIT_CONTAINER( self ) ); - g_return_if_fail( value >= 0 ); - - if ( self->max_width != value ) - { - self->max_width = value; - gtk_widget_queue_resize( GTK_WIDGET( self ) ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_MAX_WIDTH] ); - } -} - -// -// Update the maximum natural height of the child to use as the minimum height for this container. -// -void foobar_limit_container_set_max_height( - FoobarLimitContainer* self, - gint value ) -{ - g_return_if_fail( FOOBAR_IS_LIMIT_CONTAINER( self ) ); - g_return_if_fail( value >= 0 ); - - if ( self->max_height != value ) - { - self->max_height = value; - gtk_widget_queue_resize( GTK_WIDGET( self ) ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_MAX_HEIGHT] ); - } -} diff --git a/src/widgets/limit-container.h b/src/widgets/limit-container.h deleted file mode 100644 index cad19aa..0000000 --- a/src/widgets/limit-container.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_LIMIT_CONTAINER foobar_limit_container_get_type( ) - -G_DECLARE_FINAL_TYPE( FoobarLimitContainer, foobar_limit_container, FOOBAR, LIMIT_CONTAINER, GtkWidget ) - -GtkWidget* foobar_limit_container_new ( void ); -GtkWidget* foobar_limit_container_get_child ( FoobarLimitContainer* self ); -gint foobar_limit_container_get_max_width ( FoobarLimitContainer* self ); -gint foobar_limit_container_get_max_height( FoobarLimitContainer* self ); -void foobar_limit_container_set_child ( FoobarLimitContainer* self, - GtkWidget* value ); -void foobar_limit_container_set_max_width ( FoobarLimitContainer* self, - gint value ); -void foobar_limit_container_set_max_height( FoobarLimitContainer* self, - gint value ); - -G_END_DECLS diff --git a/src/widgets/meson.build b/src/widgets/meson.build deleted file mode 100644 index 7aeb3ca..0000000 --- a/src/widgets/meson.build +++ /dev/null @@ -1,8 +0,0 @@ -foobar_sources += files( - 'inset-container.c', - 'limit-container.c', - 'notification-widget.c', -) - -subdir('control-center') -subdir('panel') diff --git a/src/widgets/notification-widget.c b/src/widgets/notification-widget.c deleted file mode 100644 index 97cfc22..0000000 --- a/src/widgets/notification-widget.c +++ /dev/null @@ -1,821 +0,0 @@ -#include "widgets/notification-widget.h" - -// -// FoobarNotificationCloseAction: -// -// The action invoked when the user requests to "close" the notification. The notification is either marked as -// "dismissed" and kept around or removed from the list. -// - -G_DEFINE_ENUM_TYPE( - FoobarNotificationCloseAction, - foobar_notification_close_action, - G_DEFINE_ENUM_VALUE( FOOBAR_TYPE_NOTIFICATION_CLOSE_ACTION_REMOVE, "remove" ), - G_DEFINE_ENUM_VALUE( FOOBAR_TYPE_NOTIFICATION_CLOSE_ACTION_DISMISS, "dismiss" ) ) - -// -// FoobarNotificationWidget: -// -// Shared widget for displaying a notification. The widget also manages an inset/margin -- this is done to allow the -// "close" button to extend into the margin area. -// - -struct _FoobarNotificationWidget -{ - GtkWidget parent_instance; - GtkWidget* container; - GtkWidget* content; - GtkWidget* close_button; - FoobarNotification* notification; - FoobarNotificationCloseAction close_action; - gchar* time_format; - gint min_height; - gint close_button_inset; - gint inset_start; - gint inset_end; - gint inset_top; - gint inset_bottom; -}; - -enum -{ - PROP_NOTIFICATION = 1, - PROP_CLOSE_ACTION, - PROP_TIME_FORMAT, - PROP_MIN_HEIGHT, - PROP_CLOSE_BUTTON_INSET, - PROP_INSET_START, - PROP_INSET_END, - PROP_INSET_TOP, - PROP_INSET_BOTTOM, - N_PROPS, -}; - -static GParamSpec* props[N_PROPS] = { 0 }; - -static void foobar_notification_widget_class_init ( FoobarNotificationWidgetClass* klass ); -static void foobar_notification_widget_init ( FoobarNotificationWidget* self ); -static void foobar_notification_widget_get_property ( GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ); -static void foobar_notification_widget_set_property ( GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ); -static void foobar_notification_widget_dispose ( GObject* object ); -static void foobar_notification_widget_finalize ( GObject* object ); -static void foobar_notification_widget_handle_enter ( GtkEventControllerMotion* controller, - gdouble x, - gdouble y, - gpointer userdata ); -static void foobar_notification_widget_handle_leave ( GtkEventControllerMotion* controller, - gpointer userdata ); -static void foobar_notification_widget_handle_close_clicked( GtkButton* button, - gpointer userdata ); -static gchar* foobar_notification_widget_compute_time_label ( GtkExpression* expression, - GDateTime* time, - gchar const* format, - gpointer userdata ); -static gboolean foobar_notification_widget_compute_icon_visible( GtkExpression* expression, - GIcon* icon, - gpointer userdata ); -static gboolean foobar_notification_widget_compute_body_visible( GtkExpression* expression, - gchar const* body, - gpointer userdata ); -static void foobar_notification_widget_update_margins ( FoobarNotificationWidget* self ); - -G_DEFINE_FINAL_TYPE( FoobarNotificationWidget, foobar_notification_widget, GTK_TYPE_WIDGET ) - -// --------------------------------------------------------------------------------------------------------------------- -// Widget Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for notifications. -// -void foobar_notification_widget_class_init( FoobarNotificationWidgetClass* klass ) -{ - GtkWidgetClass* widget_klass = GTK_WIDGET_CLASS( klass ); - gtk_widget_class_set_layout_manager_type( widget_klass, GTK_TYPE_BIN_LAYOUT ); - gtk_widget_class_set_css_name( widget_klass, "notification" ); - - GObjectClass* object_klass = G_OBJECT_CLASS( klass ); - object_klass->get_property = foobar_notification_widget_get_property; - object_klass->set_property = foobar_notification_widget_set_property; - object_klass->dispose = foobar_notification_widget_dispose; - object_klass->finalize = foobar_notification_widget_finalize; - - props[PROP_NOTIFICATION] = g_param_spec_object( - "notification", - "Notification", - "Content to display.", - FOOBAR_TYPE_NOTIFICATION, - G_PARAM_READWRITE ); - props[PROP_CLOSE_ACTION] = g_param_spec_enum( - "close-action", - "Close Action", - "Action to execute when the notification is closed.", - FOOBAR_TYPE_NOTIFICATION_CLOSE_ACTION, - 0, - G_PARAM_READWRITE ); - props[PROP_TIME_FORMAT] = g_param_spec_string( - "time-format", - "Time Format", - "Time format used to display the notification's timestamp.", - NULL, - G_PARAM_READWRITE ); - props[PROP_MIN_HEIGHT] = g_param_spec_int( - "min-height", - "Minimum Height", - "Minimum requested height for the notification itself.", - 0, - INT_MAX, - 0, - G_PARAM_READWRITE ); - props[PROP_CLOSE_BUTTON_INSET] = g_param_spec_int( - "close-button-inset", - "Close Button Inset", - "Offset of the close button within the notification (may be negative, possibly increasing the actual inset).", - INT_MIN, - INT_MAX, - 0, - G_PARAM_READWRITE ); - props[PROP_INSET_START] = g_param_spec_int( - "inset-start", - "Inset Start", - "Inset for the start edge of the widget.", - 0, - INT_MAX, - 0, - G_PARAM_READWRITE ); - props[PROP_INSET_END] = g_param_spec_int( - "inset-end", - "Inset End", - "Inset for the end edge of the widget.", - 0, - INT_MAX, - 0, - G_PARAM_READWRITE ); - props[PROP_INSET_TOP] = g_param_spec_int( - "inset-top", - "Inset Top", - "Inset for the top edge of the widget.", - 0, - INT_MAX, - 0, - G_PARAM_READWRITE ); - props[PROP_INSET_BOTTOM] = g_param_spec_int( - "inset-bottom", - "Inset Bottom", - "Inset for the bottom edge of the widget.", - 0, - INT_MAX, - 0, - G_PARAM_READWRITE ); - g_object_class_install_properties( object_klass, N_PROPS, props ); -} - -// -// Instance initialization for notifications. -// -void foobar_notification_widget_init( FoobarNotificationWidget* self ) -{ - // Set up the main notification content. - - GtkWidget* icon = gtk_image_new( ); - gtk_widget_add_css_class( icon, "icon" ); - gtk_widget_set_valign( icon, GTK_ALIGN_CENTER ); - - GtkWidget* title = gtk_label_new( NULL ); - gtk_label_set_justify( GTK_LABEL( title ), GTK_JUSTIFY_LEFT ); - gtk_label_set_ellipsize( GTK_LABEL( title ), PANGO_ELLIPSIZE_END ); - gtk_label_set_wrap( GTK_LABEL( title ), FALSE ); - gtk_label_set_xalign( GTK_LABEL( title ), 0 ); - gtk_widget_add_css_class( title, "title" ); - gtk_widget_set_valign( title, GTK_ALIGN_BASELINE_CENTER ); - gtk_widget_set_hexpand( title, TRUE ); - - GtkWidget* time = gtk_label_new( NULL ); - gtk_label_set_wrap( GTK_LABEL( time ), FALSE ); - gtk_widget_add_css_class( time, "time" ); - gtk_widget_set_valign( time, GTK_ALIGN_BASELINE_CENTER ); - - GtkWidget* body = gtk_label_new( NULL ); - gtk_label_set_use_markup( GTK_LABEL( body ), TRUE ); - gtk_label_set_justify( GTK_LABEL( body ), GTK_JUSTIFY_LEFT ); - gtk_label_set_ellipsize( GTK_LABEL( body ), PANGO_ELLIPSIZE_END ); - gtk_label_set_wrap( GTK_LABEL( body ), TRUE ); - gtk_label_set_wrap_mode( GTK_LABEL( body ), PANGO_WRAP_WORD_CHAR ); - // XXX: Increase once layout is fixed in GTK (https://gitlab.gnome.org/GNOME/gtk/-/issues/5885) - gtk_label_set_lines( GTK_LABEL( body ), 1 ); - gtk_label_set_xalign( GTK_LABEL( body ), 0 ); - gtk_widget_add_css_class( body, "body" ); - - GtkWidget* header = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 ); - gtk_box_append( GTK_BOX( header ), title ); - gtk_box_append( GTK_BOX( header ), time ); - - GtkWidget* row = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 ); - gtk_box_append( GTK_BOX( row ), header ); - gtk_box_append( GTK_BOX( row ), body ); - gtk_widget_set_hexpand( row, TRUE ); - gtk_widget_set_valign( row, GTK_ALIGN_CENTER ); - - self->content = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 ); - gtk_box_append( GTK_BOX( self->content ), icon ); - gtk_box_append( GTK_BOX( self->content ), row ); - gtk_widget_add_css_class( self->content, "content" ); - - // Set up the overlay for the close button. - - GtkWidget* close_icon = gtk_image_new_from_icon_name( "fluent-dismiss-symbolic" ); - gtk_image_set_pixel_size( GTK_IMAGE( close_icon ), 12 ); - - self->close_button = gtk_button_new( ); - gtk_button_set_child( GTK_BUTTON( self->close_button ), close_icon ); - gtk_widget_add_css_class( self->close_button, "close-button" ); - gtk_widget_set_visible( self->close_button, FALSE ); - gtk_widget_set_halign( self->close_button, GTK_ALIGN_END ); - gtk_widget_set_valign( self->close_button, GTK_ALIGN_START ); - g_signal_connect( self->close_button, "clicked", G_CALLBACK( foobar_notification_widget_handle_close_clicked ), self ); - - GtkEventController* hover_controller = gtk_event_controller_motion_new( ); - g_signal_connect( hover_controller, "enter", G_CALLBACK( foobar_notification_widget_handle_enter ), self ); - g_signal_connect( hover_controller, "leave", G_CALLBACK( foobar_notification_widget_handle_leave ), self ); - - self->container = gtk_overlay_new( ); - gtk_overlay_set_child( GTK_OVERLAY( self->container ), self->content ); - gtk_overlay_add_overlay( GTK_OVERLAY( self->container ), self->close_button ); - gtk_widget_add_controller( self->container, hover_controller ); - gtk_widget_set_parent( self->container, GTK_WIDGET( self ) ); - - // Set up bindings. - - { - GtkExpression* notification_expr = gtk_property_expression_new( FOOBAR_TYPE_NOTIFICATION_WIDGET, NULL, "notification" ); - GtkExpression* image_expr = gtk_property_expression_new( FOOBAR_TYPE_NOTIFICATION, notification_expr, "image" ); - gtk_expression_bind( gtk_expression_ref( image_expr ), icon, "gicon", self ); - GtkExpression* visible_params[] = { image_expr }; - GtkExpression* visible_expr = gtk_cclosure_expression_new( - G_TYPE_BOOLEAN, - NULL, - G_N_ELEMENTS( visible_params ), - visible_params, - G_CALLBACK( foobar_notification_widget_compute_icon_visible ), - NULL, - NULL ); - gtk_expression_bind( visible_expr, icon, "visible", self ); - } - - { - GtkExpression* notification_expr = gtk_property_expression_new( FOOBAR_TYPE_NOTIFICATION_WIDGET, NULL, "notification" ); - GtkExpression* summary_expr = gtk_property_expression_new( FOOBAR_TYPE_NOTIFICATION, notification_expr, "summary" ); - gtk_expression_bind( summary_expr, title, "label", self ); - } - - { - GtkExpression* notification_expr = gtk_property_expression_new( FOOBAR_TYPE_NOTIFICATION_WIDGET, NULL, "notification" ); - GtkExpression* body_expr = gtk_property_expression_new( FOOBAR_TYPE_NOTIFICATION, notification_expr, "body" ); - gtk_expression_bind( gtk_expression_ref( body_expr ), body, "label", self ); - GtkExpression* visible_params[] = { body_expr }; - GtkExpression* visible_expr = gtk_cclosure_expression_new( - G_TYPE_BOOLEAN, - NULL, - G_N_ELEMENTS( visible_params ), - visible_params, - G_CALLBACK( foobar_notification_widget_compute_body_visible ), - NULL, - NULL ); - gtk_expression_bind( visible_expr, body, "visible", self ); - } - - { - GtkExpression* notification_expr = gtk_property_expression_new( FOOBAR_TYPE_NOTIFICATION_WIDGET, NULL, "notification" ); - GtkExpression* time_expr = gtk_property_expression_new( FOOBAR_TYPE_NOTIFICATION, notification_expr, "time" ); - GtkExpression* format_expr = gtk_property_expression_new( FOOBAR_TYPE_NOTIFICATION_WIDGET, NULL, "time-format" ); - GtkExpression* str_params[] = { time_expr, format_expr }; - GtkExpression* str_expr = gtk_cclosure_expression_new( - G_TYPE_STRING, - NULL, - G_N_ELEMENTS( str_params ), - str_params, - G_CALLBACK( foobar_notification_widget_compute_time_label ), - self, - NULL ); - gtk_expression_bind( str_expr, time, "label", self ); - } -} - -// -// Property getter implementation, mapping a property id to a method. -// -void foobar_notification_widget_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ) -{ - FoobarNotificationWidget* self = (FoobarNotificationWidget*)object; - - switch ( prop_id ) - { - case PROP_NOTIFICATION: - g_value_set_object( value, foobar_notification_widget_get_notification( self ) ); - break; - case PROP_CLOSE_ACTION: - g_value_set_enum( value, foobar_notification_widget_get_close_action( self ) ); - break; - case PROP_TIME_FORMAT: - g_value_set_string( value, foobar_notification_widget_get_time_format( self ) ); - break; - case PROP_MIN_HEIGHT: - g_value_set_int( value, foobar_notification_widget_get_min_height( self ) ); - break; - case PROP_CLOSE_BUTTON_INSET: - g_value_set_int( value, foobar_notification_widget_get_close_button_inset( self ) ); - break; - case PROP_INSET_START: - g_value_set_int( value, foobar_notification_widget_get_inset_start( self ) ); - break; - case PROP_INSET_END: - g_value_set_int( value, foobar_notification_widget_get_inset_end( self ) ); - break; - case PROP_INSET_TOP: - g_value_set_int( value, foobar_notification_widget_get_inset_top( self ) ); - break; - case PROP_INSET_BOTTOM: - g_value_set_int( value, foobar_notification_widget_get_inset_bottom( self ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Property setter implementation, mapping a property id to a method. -// -void foobar_notification_widget_set_property( - GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ) -{ - FoobarNotificationWidget* self = (FoobarNotificationWidget*)object; - - switch ( prop_id ) - { - case PROP_NOTIFICATION: - foobar_notification_widget_set_notification( self, g_value_get_object( value ) ); - break; - case PROP_CLOSE_ACTION: - foobar_notification_widget_set_close_action( self, g_value_get_enum( value ) ); - break; - case PROP_TIME_FORMAT: - foobar_notification_widget_set_time_format( self, g_value_get_string( value ) ); - break; - case PROP_MIN_HEIGHT: - foobar_notification_widget_set_min_height( self, g_value_get_int( value ) ); - break; - case PROP_CLOSE_BUTTON_INSET: - foobar_notification_widget_set_close_button_inset( self, g_value_get_int( value ) ); - break; - case PROP_INSET_START: - foobar_notification_widget_set_inset_start( self, g_value_get_int( value ) ); - break; - case PROP_INSET_END: - foobar_notification_widget_set_inset_end( self, g_value_get_int( value ) ); - break; - case PROP_INSET_TOP: - foobar_notification_widget_set_inset_top( self, g_value_get_int( value ) ); - break; - case PROP_INSET_BOTTOM: - foobar_notification_widget_set_inset_bottom( self, g_value_get_int( value ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Instance de-initialization for notifications. -// -void foobar_notification_widget_dispose( GObject* object ) -{ - FoobarNotificationWidget* self = (FoobarNotificationWidget*)object; - - GtkWidget* child; - while ( ( child = gtk_widget_get_first_child( GTK_WIDGET( self ) ) ) ) - { - gtk_widget_unparent( child ); - } - - G_OBJECT_CLASS( foobar_notification_widget_parent_class )->dispose( object ); -} - -// -// Instance cleanup for notifications. -// -void foobar_notification_widget_finalize( GObject* object ) -{ - FoobarNotificationWidget* self = (FoobarNotificationWidget*)object; - - g_clear_object( &self->notification ); - g_clear_pointer( &self->time_format, g_free ); - - G_OBJECT_CLASS( foobar_notification_widget_parent_class )->finalize( object ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new notification widget instance. -// -GtkWidget* foobar_notification_widget_new( void ) -{ - return g_object_new( FOOBAR_TYPE_NOTIFICATION_WIDGET, NULL ); -} - -// -// Get the notification model currently displayed. -// -FoobarNotification* foobar_notification_widget_get_notification( FoobarNotificationWidget* self ) -{ - g_return_val_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ), NULL ); - return self->notification; -} - -// -// Get the action invoked when the user wants to "close" a notification. -// -FoobarNotificationCloseAction foobar_notification_widget_get_close_action( FoobarNotificationWidget* self ) -{ - g_return_val_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ), 0 ); - return self->close_action; -} - -// -// Get the time format string used to display the notification's timestamp. -// -gchar const* foobar_notification_widget_get_time_format( FoobarNotificationWidget* self ) -{ - g_return_val_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ), NULL ); - return self->time_format; -} - -// -// Get the minimum height of the notification (excluding the inset). -// -gint foobar_notification_widget_get_min_height( FoobarNotificationWidget* self ) -{ - g_return_val_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ), 0 ); - return self->min_height; -} - -// -// Get the offset of the close button within the notification (may be negative, possibly increasing the actual inset). -// -gint foobar_notification_widget_get_close_button_inset( FoobarNotificationWidget* self ) -{ - g_return_val_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ), 0 ); - return self->close_button_inset; -} - -// -// Get the margin for the start edge of the notification. -// -gint foobar_notification_widget_get_inset_start( FoobarNotificationWidget* self ) -{ - g_return_val_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ), 0 ); - return self->inset_start; -} - -// -// Get the margin for the end edge of the notification. -// -gint foobar_notification_widget_get_inset_end( FoobarNotificationWidget* self ) -{ - g_return_val_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ), 0 ); - return self->inset_end; -} - -// -// Get the margin for the top edge of the notification. -// -gint foobar_notification_widget_get_inset_top( FoobarNotificationWidget* self ) -{ - g_return_val_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ), 0 ); - return self->inset_top; -} - -// -// Get the margin for the bottom edge of the notification. -// -gint foobar_notification_widget_get_inset_bottom( FoobarNotificationWidget* self ) -{ - g_return_val_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ), 0 ); - return self->inset_bottom; -} - -// -// Update the notification model currently displayed. -// -void foobar_notification_widget_set_notification( - FoobarNotificationWidget* self, - FoobarNotification* value ) -{ - g_return_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ) ); - - if ( self->notification != value ) - { - g_clear_object( &self->notification ); - if ( value ) { self->notification = g_object_ref( value ); } - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_NOTIFICATION] ); - } -} - -// -// Update the action invoked when the user wants to "close" a notification. -// -void foobar_notification_widget_set_close_action( - FoobarNotificationWidget* self, - FoobarNotificationCloseAction value ) -{ - g_return_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ) ); - - if ( self->close_action != value ) - { - self->close_action = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_CLOSE_ACTION] ); - } -} - -// -// Update the time format string used to display the notification's timestamp. -// -void foobar_notification_widget_set_time_format( - FoobarNotificationWidget* self, - gchar const* value ) -{ - g_return_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ) ); - - if ( g_strcmp0( self->time_format, value ) ) - { - g_clear_pointer( &self->time_format, g_free ); - self->time_format = g_strdup( value ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_TIME_FORMAT] ); - } -} - -// -// Update the minimum height of the notification (excluding the inset). -// -void foobar_notification_widget_set_min_height( - FoobarNotificationWidget* self, - gint value ) -{ - g_return_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ) ); - - value = MAX( value, 0 ); - if ( self->min_height != value ) - { - self->min_height = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_MIN_HEIGHT] ); - gtk_widget_set_size_request( self->content, -1, self->min_height ); - } -} - -// -// Update the offset of the close button within the notification (may be negative, possibly increasing the actual inset). -// -void foobar_notification_widget_set_close_button_inset( - FoobarNotificationWidget* self, - gint value ) -{ - g_return_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ) ); - - if ( self->close_button_inset != value ) - { - self->close_button_inset = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_CLOSE_BUTTON_INSET] ); - foobar_notification_widget_update_margins( self ); - } -} - -// -// Update the margin for the start edge of the notification. -// -void foobar_notification_widget_set_inset_start( - FoobarNotificationWidget* self, - gint value ) -{ - g_return_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ) ); - - value = MAX( value, 0 ); - if ( self->inset_start != value ) - { - self->inset_start = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_INSET_START] ); - foobar_notification_widget_update_margins( self ); - } -} - -// -// Update the margin for the end edge of the notification. -// -void foobar_notification_widget_set_inset_end( - FoobarNotificationWidget* self, - gint value ) -{ - g_return_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ) ); - - value = MAX( value, 0 ); - if ( self->inset_end != value ) - { - self->inset_end = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_INSET_END] ); - foobar_notification_widget_update_margins( self ); - } -} - -// -// Update the margin for the top edge of the notification. -// -void foobar_notification_widget_set_inset_top( - FoobarNotificationWidget* self, - gint value ) -{ - g_return_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ) ); - - value = MAX( value, 0 ); - if ( self->inset_top != value ) - { - self->inset_top = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_INSET_TOP] ); - foobar_notification_widget_update_margins( self ); - } -} - -// -// Update the margin for the bottom edge of the notification. -// -void foobar_notification_widget_set_inset_bottom( - FoobarNotificationWidget* self, - gint value ) -{ - g_return_if_fail( FOOBAR_IS_NOTIFICATION_WIDGET( self ) ); - - value = MAX( value, 0 ); - if ( self->inset_bottom != value ) - { - self->inset_bottom = value; - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_INSET_BOTTOM] ); - foobar_notification_widget_update_margins( self ); - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// Signal Handlers -// --------------------------------------------------------------------------------------------------------------------- - -// -// Called when the mouse cursor enters the notification. -// -// We will temporarily block the dismissal timeout for the notification and show the close button. -// -void foobar_notification_widget_handle_enter( - GtkEventControllerMotion* controller, - gdouble x, - gdouble y, - gpointer userdata ) -{ - (void)controller; - (void)x; - (void)y; - FoobarNotificationWidget* self = (FoobarNotificationWidget*)userdata; - - gtk_widget_set_visible( self->close_button, TRUE ); - if ( self->notification ) { foobar_notification_block_timeout( self->notification ); } -} - -// -// Called when the mouse cursor leaves the notification. -// -// We will unblock the dismissal timeout for the notification and hide the close button. -// -void foobar_notification_widget_handle_leave( - GtkEventControllerMotion* controller, - gpointer userdata ) -{ - (void)controller; - FoobarNotificationWidget* self = (FoobarNotificationWidget*)userdata; - - gtk_widget_set_visible( self->close_button, FALSE ); - if ( self->notification ) { foobar_notification_resume_timeout( self->notification ); } -} - -// -// Called when the user has clicked the "close" button. -// -// This either marks the notification as dismissed or removes it. -// -void foobar_notification_widget_handle_close_clicked( - GtkButton* button, - gpointer userdata ) -{ - (void)button; - FoobarNotificationWidget* self = (FoobarNotificationWidget*)userdata; - - if ( self->notification ) - { - switch ( self->close_action ) - { - case FOOBAR_TYPE_NOTIFICATION_CLOSE_ACTION_REMOVE: - foobar_notification_close( self->notification ); - break; - case FOOBAR_TYPE_NOTIFICATION_CLOSE_ACTION_DISMISS: - foobar_notification_dismiss( self->notification ); - break; - default: - g_warn_if_reached( ); - break; - } - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// Value Converters -// --------------------------------------------------------------------------------------------------------------------- - -// -// Derive the timestamp label value from the notification's timestamp and the selected time format. -// -gchar* foobar_notification_widget_compute_time_label( - GtkExpression* expression, - GDateTime* time, - gchar const* format, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - return format != NULL ? g_date_time_format( time, format ) : NULL; -} - -// -// Derive the visibility of the notification icon from its value. -// -gboolean foobar_notification_widget_compute_icon_visible( - GtkExpression* expression, - GIcon* icon, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - return icon != NULL; -} - -// -// Derive the visibility of the notification body label from its value. -// -gboolean foobar_notification_widget_compute_body_visible( - GtkExpression* expression, - gchar const* body, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - return body != NULL && g_strcmp0( body, "" ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Helper Methods -// --------------------------------------------------------------------------------------------------------------------- - -// -// Update the margins of the content widget and close button to the current inset values. -// -void foobar_notification_widget_update_margins( FoobarNotificationWidget* self ) -{ - gint inset = MAX( self->close_button_inset, 0 ); - gint overrun = MAX( -self->close_button_inset, 0 ); - gint actual_inset_end = MAX( self->inset_end, overrun ); - gint actual_inset_top = MAX( self->inset_top, overrun ); - - gtk_widget_set_margin_start( self->container, self->inset_start ); - gtk_widget_set_margin_end( self->container, actual_inset_end - overrun ); - gtk_widget_set_margin_top( self->container, actual_inset_top - overrun ); - gtk_widget_set_margin_bottom( self->container, self->inset_bottom ); - - gtk_widget_set_margin_end( self->content, overrun ); - gtk_widget_set_margin_top( self->content, overrun ); - - gtk_widget_set_margin_end( self->close_button, inset ); - gtk_widget_set_margin_top( self->close_button, inset ); -} diff --git a/src/widgets/notification-widget.h b/src/widgets/notification-widget.h deleted file mode 100644 index af9de49..0000000 --- a/src/widgets/notification-widget.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include -#include "services/notification-service.h" - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_NOTIFICATION_CLOSE_ACTION foobar_notification_close_action_get_type( ) -#define FOOBAR_TYPE_NOTIFICATION_WIDGET foobar_notification_widget_get_type( ) - -typedef enum -{ - FOOBAR_TYPE_NOTIFICATION_CLOSE_ACTION_REMOVE, - FOOBAR_TYPE_NOTIFICATION_CLOSE_ACTION_DISMISS, -} FoobarNotificationCloseAction; - -GType foobar_notification_close_action_get_type( void ); - -G_DECLARE_FINAL_TYPE( FoobarNotificationWidget, foobar_notification_widget, FOOBAR, NOTIFICATION_WIDGET, GtkWidget ) - -GtkWidget* foobar_notification_widget_new ( void ); -FoobarNotification* foobar_notification_widget_get_notification ( FoobarNotificationWidget* self ); -FoobarNotificationCloseAction foobar_notification_widget_get_close_action ( FoobarNotificationWidget* self ); -gchar const* foobar_notification_widget_get_time_format ( FoobarNotificationWidget* self ); -gint foobar_notification_widget_get_min_height ( FoobarNotificationWidget* self ); -gint foobar_notification_widget_get_close_button_inset( FoobarNotificationWidget* self ); -gint foobar_notification_widget_get_inset_start ( FoobarNotificationWidget* self ); -gint foobar_notification_widget_get_inset_end ( FoobarNotificationWidget* self ); -gint foobar_notification_widget_get_inset_top ( FoobarNotificationWidget* self ); -gint foobar_notification_widget_get_inset_bottom ( FoobarNotificationWidget* self ); -void foobar_notification_widget_set_notification ( FoobarNotificationWidget* self, - FoobarNotification* value ); -void foobar_notification_widget_set_close_action ( FoobarNotificationWidget* self, - FoobarNotificationCloseAction value ); -void foobar_notification_widget_set_time_format ( FoobarNotificationWidget* self, - gchar const* value ); -void foobar_notification_widget_set_min_height ( FoobarNotificationWidget* self, - gint value ); -void foobar_notification_widget_set_close_button_inset( FoobarNotificationWidget* self, - gint value ); -void foobar_notification_widget_set_inset_start ( FoobarNotificationWidget* self, - gint value ); -void foobar_notification_widget_set_inset_end ( FoobarNotificationWidget* self, - gint value ); -void foobar_notification_widget_set_inset_top ( FoobarNotificationWidget* self, - gint value ); -void foobar_notification_widget_set_inset_bottom ( FoobarNotificationWidget* self, - gint value ); - -G_END_DECLS diff --git a/src/widgets/panel/meson.build b/src/widgets/panel/meson.build deleted file mode 100644 index 10afc94..0000000 --- a/src/widgets/panel/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -foobar_sources += files( - 'panel-item.c', - 'panel-item-icon.c', - 'panel-item-clock.c', - 'panel-item-workspaces.c', - 'panel-item-status.c', -) diff --git a/src/widgets/panel/panel-item-clock.c b/src/widgets/panel/panel-item-clock.c deleted file mode 100644 index 00b2cc5..0000000 --- a/src/widgets/panel/panel-item-clock.c +++ /dev/null @@ -1,152 +0,0 @@ -#include "widgets/panel/panel-item-clock.h" - -// -// FoobarPanelItemClock: -// -// A panel item displaying the current time in the format configured by the user. -// - -struct _FoobarPanelItemClock -{ - FoobarPanelItem parent_instance; - gchar* format; - FoobarPanelItemAction action; - GtkWidget* label; - GtkWidget* button; - FoobarClockService* clock_service; -}; - -static void foobar_panel_item_clock_class_init ( FoobarPanelItemClockClass* klass ); -static void foobar_panel_item_clock_init ( FoobarPanelItemClock* self ); -static void foobar_panel_item_clock_finalize ( GObject* object ); -static void foobar_panel_item_clock_handle_clicked( GtkButton* button, - gpointer userdata ); -static gchar* foobar_panel_item_clock_compute_label ( GtkExpression* expression, - GDateTime* time, - gpointer userdata ); - -G_DEFINE_FINAL_TYPE( FoobarPanelItemClock, foobar_panel_item_clock, FOOBAR_TYPE_PANEL_ITEM ) - -// --------------------------------------------------------------------------------------------------------------------- -// Panel Item Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for clock panel items. -// -void foobar_panel_item_clock_class_init( FoobarPanelItemClockClass* klass ) -{ - GObjectClass* object_klass = G_OBJECT_CLASS( klass ); - object_klass->finalize = foobar_panel_item_clock_finalize; -} - -// -// Instance initialization for clock panel items. -// -void foobar_panel_item_clock_init( FoobarPanelItemClock* self ) -{ - self->label = gtk_label_new( NULL ); - gtk_label_set_justify( GTK_LABEL( self->label ), GTK_JUSTIFY_CENTER ); - - self->button = gtk_button_new( ); - gtk_button_set_has_frame( GTK_BUTTON( self->button ), FALSE ); - gtk_button_set_child( GTK_BUTTON( self->button ), self->label ); - gtk_widget_set_halign( self->button, GTK_ALIGN_CENTER ); - gtk_widget_set_valign( self->button, GTK_ALIGN_CENTER ); - g_signal_connect( - self->button, - "clicked", - G_CALLBACK( foobar_panel_item_clock_handle_clicked ), - self ); - - gtk_widget_add_css_class( GTK_WIDGET( self ), "clock" ); - foobar_panel_item_set_child( FOOBAR_PANEL_ITEM( self ), self->button ); -} - -// -// Instance cleanup for clock panel items. -// -void foobar_panel_item_clock_finalize( GObject* object ) -{ - FoobarPanelItemClock* self = (FoobarPanelItemClock*)object; - - g_clear_pointer( &self->format, g_free ); - g_clear_object( &self->clock_service ); - - G_OBJECT_CLASS( foobar_panel_item_clock_parent_class )->finalize( object ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new clock panel item with the given configuration. -// -FoobarPanelItem* foobar_panel_item_clock_new( - FoobarPanelItemConfiguration const* config, - FoobarClockService* clock_service ) -{ - g_return_val_if_fail( config != NULL, NULL ); - g_return_val_if_fail( foobar_panel_item_configuration_get_kind( config ) == FOOBAR_PANEL_ITEM_KIND_CLOCK, NULL ); - g_return_val_if_fail( FOOBAR_IS_CLOCK_SERVICE( clock_service ), NULL ); - - FoobarPanelItemClock* self = g_object_new( FOOBAR_TYPE_PANEL_ITEM_CLOCK, NULL ); - self->format = g_strdup( foobar_panel_item_clock_configuration_get_format( config ) ); - self->action = foobar_panel_item_configuration_get_action( config ); - self->clock_service = g_object_ref( clock_service ); - - gtk_widget_set_sensitive( self->button, self->action != FOOBAR_PANEL_ITEM_ACTION_NONE ); - - { - GtkExpression* service_expr = gtk_constant_expression_new( FOOBAR_TYPE_CLOCK_SERVICE, self->clock_service ); - GtkExpression* time_expr = gtk_property_expression_new( FOOBAR_TYPE_CLOCK_SERVICE, service_expr, "time" ); - GtkExpression* label_params[] = { time_expr }; - GtkExpression* label_expr = gtk_cclosure_expression_new( - G_TYPE_STRING, - NULL, - G_N_ELEMENTS( label_params ), - label_params, - G_CALLBACK( foobar_panel_item_clock_compute_label ), - self, - NULL ); - gtk_expression_bind( label_expr, self->label, "label", NULL ); - } - - return FOOBAR_PANEL_ITEM( self ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Signal Handlers -// --------------------------------------------------------------------------------------------------------------------- - -// -// Called when the button was clicked. -// -void foobar_panel_item_clock_handle_clicked( - GtkButton* button, - gpointer userdata ) -{ - (void)button; - FoobarPanelItemClock* self = (FoobarPanelItemClock*)userdata; - - foobar_panel_item_invoke_action( FOOBAR_PANEL_ITEM( self ), self->action ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Value Converters -// --------------------------------------------------------------------------------------------------------------------- - -// -// Derive the label from a timestamp, depending on the configured time format. -// -gchar* foobar_panel_item_clock_compute_label( - GtkExpression* expression, - GDateTime* time, - gpointer userdata ) -{ - (void)expression; - FoobarPanelItemClock* self = (FoobarPanelItemClock*)userdata; - - return g_date_time_format( time, self->format ); -} diff --git a/src/widgets/panel/panel-item-clock.h b/src/widgets/panel/panel-item-clock.h deleted file mode 100644 index 5ff7e5b..0000000 --- a/src/widgets/panel/panel-item-clock.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "widgets/panel/panel-item.h" -#include "services/clock-service.h" - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_PANEL_ITEM_CLOCK foobar_panel_item_clock_get_type( ) - -G_DECLARE_FINAL_TYPE( FoobarPanelItemClock, foobar_panel_item_clock, FOOBAR, PANEL_ITEM_CLOCK, FoobarPanelItem ) - -FoobarPanelItem* foobar_panel_item_clock_new( FoobarPanelItemConfiguration const* config, - FoobarClockService* clock_service ); - -G_END_DECLS diff --git a/src/widgets/panel/panel-item-icon.c b/src/widgets/panel/panel-item-icon.c deleted file mode 100644 index 0a3b4e9..0000000 --- a/src/widgets/panel/panel-item-icon.c +++ /dev/null @@ -1,92 +0,0 @@ -#include "widgets/panel/panel-item-icon.h" - -// -// FoobarPanelItemIcon: -// -// Simple item implementation displaying an icon. -// - -struct _FoobarPanelItemIcon -{ - FoobarPanelItem parent_instance; - GtkWidget* button; - FoobarPanelItemAction action; -}; - -static void foobar_panel_item_icon_class_init ( FoobarPanelItemIconClass* klass ); -static void foobar_panel_item_icon_init ( FoobarPanelItemIcon* self ); -static void foobar_panel_item_icon_handle_clicked( GtkButton* button, - gpointer userdata ); - -G_DEFINE_FINAL_TYPE( FoobarPanelItemIcon, foobar_panel_item_icon, FOOBAR_TYPE_PANEL_ITEM ) - -// --------------------------------------------------------------------------------------------------------------------- -// Panel Item Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for icon panel items. -// -void foobar_panel_item_icon_class_init( FoobarPanelItemIconClass* klass ) -{ - (void)klass; -} - -// -// Instance initialization for icon panel items. -// -void foobar_panel_item_icon_init( FoobarPanelItemIcon* self ) -{ - self->button = gtk_button_new( ); - gtk_button_set_has_frame( GTK_BUTTON( self->button ), FALSE ); - gtk_widget_set_halign( self->button, GTK_ALIGN_CENTER ); - gtk_widget_set_valign( self->button, GTK_ALIGN_CENTER ); - g_signal_connect( - self->button, - "clicked", - G_CALLBACK( foobar_panel_item_icon_handle_clicked ), - self ); - - gtk_widget_add_css_class( GTK_WIDGET( self ), "icon" ); - foobar_panel_item_set_child( FOOBAR_PANEL_ITEM( self ), self->button ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new icon panel item with the given configuration. -// -FoobarPanelItem* foobar_panel_item_icon_new( FoobarPanelItemConfiguration const* config ) -{ - g_return_val_if_fail( config != NULL, NULL ); - g_return_val_if_fail( foobar_panel_item_configuration_get_kind( config ) == FOOBAR_PANEL_ITEM_KIND_ICON, NULL ); - - FoobarPanelItemIcon* self = g_object_new( FOOBAR_TYPE_PANEL_ITEM_ICON, NULL ); - self->action = foobar_panel_item_configuration_get_action( config ); - - gtk_widget_set_sensitive( self->button, self->action != FOOBAR_PANEL_ITEM_ACTION_NONE ); - gtk_button_set_icon_name( - GTK_BUTTON( self->button ), - foobar_panel_item_icon_configuration_get_icon_name( config ) ); - - return FOOBAR_PANEL_ITEM( self ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Signal Handlers -// --------------------------------------------------------------------------------------------------------------------- - -// -// Called when the button was clicked. -// -void foobar_panel_item_icon_handle_clicked( - GtkButton* button, - gpointer userdata ) -{ - (void)button; - FoobarPanelItemIcon* self = (FoobarPanelItemIcon*)userdata; - - foobar_panel_item_invoke_action( FOOBAR_PANEL_ITEM( self ), self->action ); -} diff --git a/src/widgets/panel/panel-item-icon.h b/src/widgets/panel/panel-item-icon.h deleted file mode 100644 index 2b4ac1f..0000000 --- a/src/widgets/panel/panel-item-icon.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "widgets/panel/panel-item.h" - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_PANEL_ITEM_ICON foobar_panel_item_icon_get_type( ) - -G_DECLARE_FINAL_TYPE( FoobarPanelItemIcon, foobar_panel_item_icon, FOOBAR, PANEL_ITEM_ICON, FoobarPanelItem ) - -FoobarPanelItem* foobar_panel_item_icon_new( FoobarPanelItemConfiguration const* config ); - -G_END_DECLS diff --git a/src/widgets/panel/panel-item-status.c b/src/widgets/panel/panel-item-status.c deleted file mode 100644 index f06bb68..0000000 --- a/src/widgets/panel/panel-item-status.c +++ /dev/null @@ -1,955 +0,0 @@ -#include "widgets/panel/panel-item-status.h" - -// -// FoobarPanelItemStatus: -// -// A panel item showing status indicators for various things such as network state, audio volume, screen brightness, -// battery level, etc. -// - -struct _FoobarPanelItemStatus -{ - FoobarPanelItem parent_instance; - FoobarPanelItemAction action; - GtkWidget* button; - GtkWidget* layout; - FoobarBatteryService* battery_service; - FoobarBrightnessService* brightness_service; - FoobarAudioService* audio_service; - FoobarNetworkService* network_service; - FoobarBluetoothService* bluetooth_service; - FoobarNotificationService* notification_service; - GtkWidget* network_icon; - GtkWidget* network_label; - GtkExpression* network_icon_expr; - FoobarNetwork* network; - gulong network_handler_id; - gulong network_strength_handler_id; -}; - -enum -{ - PROP_ORIENTATION = 1, - N_PROPS, -}; - -static GParamSpec* props[N_PROPS] = { 0 }; - -static void foobar_panel_item_status_class_init ( FoobarPanelItemStatusClass* klass ); -static void foobar_panel_item_status_init ( FoobarPanelItemStatus* self ); -static void foobar_panel_item_status_get_property ( GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ); -static void foobar_panel_item_status_set_property ( GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ); -static void foobar_panel_item_status_finalize ( GObject* object ); -static void foobar_panel_item_status_handle_network_change ( FoobarNetworkAdapterWifi* adapter, - GParamSpec* pspec, - gpointer userdata ); -static void foobar_panel_item_status_handle_network_strength_change( GObject* object, - GParamSpec* pspec, - gpointer userdata ); -static void foobar_panel_item_status_handle_clicked ( GtkButton* button, - gpointer userdata ); -static gboolean foobar_panel_item_status_handle_brightness_scroll ( GtkEventControllerScroll* controller, - gdouble dx, - gdouble dy, - gpointer userdata ); -static gboolean foobar_panel_item_status_handle_audio_scroll ( GtkEventControllerScroll* controller, - gdouble dx, - gdouble dy, - gpointer userdata ); -static gchar* foobar_panel_item_status_compute_network_icon ( GtkExpression* expression, - FoobarNetworkAdapter* adapter, - FoobarNetworkAdapterState state, - gpointer userdata ); -static gchar* foobar_panel_item_status_compute_bluetooth_icon ( GtkExpression* expression, - gboolean is_enabled, - guint connected_device_count, - gpointer userdata ); -static gchar* foobar_panel_item_status_compute_battery_icon ( GtkExpression* expression, - FoobarBatteryState const* state, - gpointer userdata ); -static gchar* foobar_panel_item_status_compute_battery_label ( GtkExpression* expression, - FoobarBatteryState const* state, - gpointer userdata ); -static gchar* foobar_panel_item_status_compute_brightness_icon ( GtkExpression* expression, - gint percentage, - gpointer userdata ); -static gchar* foobar_panel_item_status_compute_brightness_label ( GtkExpression* expression, - gint percentage, - gpointer userdata ); -static gchar* foobar_panel_item_status_compute_audio_icon ( GtkExpression* expression, - gboolean is_available, - gint volume, - gpointer userdata ); -static gchar* foobar_panel_item_status_compute_audio_label ( GtkExpression* expression, - gboolean is_available, - gint volume, - gpointer userdata ); -static gchar* foobar_panel_item_status_compute_notifications_icon ( GtkExpression* expression, - guint count, - gpointer userdata ); -static GtkWidget* foobar_panel_item_status_create_item ( FoobarPanelItemStatus* self, - FoobarStatusItem item, - gboolean show_labels, - gboolean enable_scrolling ); -static void foobar_panel_item_status_reevaluate_network ( FoobarPanelItemStatus* self ); - -G_DEFINE_FINAL_TYPE_WITH_CODE( - FoobarPanelItemStatus, - foobar_panel_item_status, - FOOBAR_TYPE_PANEL_ITEM, - G_IMPLEMENT_INTERFACE( GTK_TYPE_ORIENTABLE, NULL ) ) - -// --------------------------------------------------------------------------------------------------------------------- -// Panel Item Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for status panel items. -// -void foobar_panel_item_status_class_init( FoobarPanelItemStatusClass* klass ) -{ - GObjectClass* object_klass = G_OBJECT_CLASS( klass ); - object_klass->get_property = foobar_panel_item_status_get_property; - object_klass->set_property = foobar_panel_item_status_set_property; - object_klass->finalize = foobar_panel_item_status_finalize; - - gpointer orientable_iface = g_type_default_interface_peek( GTK_TYPE_ORIENTABLE ); - props[PROP_ORIENTATION] = g_param_spec_override( - "orientation", - g_object_interface_find_property( orientable_iface, "orientation" ) ); - g_object_class_install_properties( object_klass, N_PROPS, props ); -} - -// -// Instance initialization for status panel items. -// -void foobar_panel_item_status_init( FoobarPanelItemStatus* self ) -{ - self->layout = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 ); - - self->button = gtk_button_new( ); - gtk_button_set_has_frame( GTK_BUTTON( self->button ), FALSE ); - gtk_button_set_child( GTK_BUTTON( self->button ), self->layout ); - gtk_widget_set_halign( self->button, GTK_ALIGN_CENTER ); - gtk_widget_set_valign( self->button, GTK_ALIGN_CENTER ); - g_signal_connect( - self->button, - "clicked", - G_CALLBACK( foobar_panel_item_status_handle_clicked ), - self ); - - gtk_widget_add_css_class( GTK_WIDGET( self ), "status" ); - foobar_panel_item_set_child( FOOBAR_PANEL_ITEM( self ), self->button ); -} - -// -// Property getter implementation, mapping a property id to a method. -// -void foobar_panel_item_status_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ) -{ - FoobarPanelItemStatus* self = (FoobarPanelItemStatus*)object; - - switch ( prop_id ) - { - case PROP_ORIENTATION: - g_value_set_enum( value, gtk_orientable_get_orientation( GTK_ORIENTABLE( self->layout ) ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Property setter implementation, mapping a property id to a method. -// -void foobar_panel_item_status_set_property( - GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ) -{ - FoobarPanelItemStatus* self = (FoobarPanelItemStatus*)object; - - switch ( prop_id ) - { - case PROP_ORIENTATION: - gtk_orientable_set_orientation( GTK_ORIENTABLE( self->layout ), g_value_get_enum( value ) ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_ORIENTATION] ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Instance cleanup for status panel items. -// -void foobar_panel_item_status_finalize( GObject* object ) -{ - FoobarPanelItemStatus* self = (FoobarPanelItemStatus*)object; - - FoobarNetworkAdapterWifi* adapter = foobar_network_service_get_wifi( self->network_service ); - g_clear_signal_handler( &self->network_handler_id, adapter ); - g_clear_signal_handler( &self->network_strength_handler_id, self->network ); - g_clear_object( &self->network ); - g_clear_object( &self->battery_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->notification_service ); - g_clear_pointer( &self->network_icon_expr, gtk_expression_unref ); - - G_OBJECT_CLASS( foobar_panel_item_status_parent_class )->finalize( object ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new status panel item with the given configuration. -// -FoobarPanelItem* foobar_panel_item_status_new( - FoobarPanelItemConfiguration const* config, - FoobarBatteryService* battery_service, - FoobarBrightnessService* brightness_service, - FoobarAudioService* audio_service, - FoobarNetworkService* network_service, - FoobarBluetoothService* bluetooth_service, - FoobarNotificationService* notification_service ) -{ - g_return_val_if_fail( config != NULL, NULL ); - g_return_val_if_fail( foobar_panel_item_configuration_get_kind( config ) == FOOBAR_PANEL_ITEM_KIND_STATUS, NULL ); - g_return_val_if_fail( FOOBAR_IS_BATTERY_SERVICE( battery_service ), NULL ); - 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 ); - - FoobarPanelItemStatus* self = g_object_new( FOOBAR_TYPE_PANEL_ITEM_STATUS, NULL ); - self->action = foobar_panel_item_configuration_get_action( config ); - self->battery_service = g_object_ref( battery_service ); - 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 ); - - gtk_widget_set_sensitive( self->button, self->action != FOOBAR_PANEL_ITEM_ACTION_NONE ); - - gtk_box_set_spacing( GTK_BOX( self->layout ), foobar_panel_item_status_configuration_get_spacing( config ) ); - gboolean show_labels = foobar_panel_item_status_configuration_get_show_labels( config ); - gboolean enable_scrolling = foobar_panel_item_status_configuration_get_enable_scrolling( config ); - gsize items_count; - FoobarStatusItem const* items = foobar_panel_item_status_configuration_get_items( config, &items_count ); - for ( gsize i = 0; i < items_count; ++i ) - { - GtkWidget* widget = foobar_panel_item_status_create_item( self, items[i], show_labels, enable_scrolling ); - if ( widget ) - { - gtk_widget_set_halign( widget, GTK_ALIGN_CENTER ); - gtk_box_append( GTK_BOX( self->layout ), widget ); - } - } - - return FOOBAR_PANEL_ITEM( self ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Signal Handlers -// --------------------------------------------------------------------------------------------------------------------- - -// -// Called when the wi-fi adapter's active network changes. -// -// This is used to then subscribe to changes to the active network's strength. Unfortunately, we can't just use -// GtkExpressions here because the active network may be NULL in which case the strength expression would fail. If one -// expression fails to evaluate, then the closure expression used to derive the network icon/label also does not get -// updated. -// -// In addition, this method also updates the network label to show the active network's name or become invisible. -// -void foobar_panel_item_status_handle_network_change( - FoobarNetworkAdapterWifi* adapter, - GParamSpec* pspec, - gpointer userdata ) -{ - (void)pspec; - FoobarPanelItemStatus* self = (FoobarPanelItemStatus*)userdata; - - FoobarNetwork* network = foobar_network_adapter_wifi_get_active( adapter ); - if ( self->network != network ) - { - g_clear_signal_handler( &self->network_strength_handler_id, self->network ); - g_clear_object( &self->network ); - - if ( network ) - { - self->network = g_object_ref( network ); - self->network_strength_handler_id = g_signal_connect( - self->network, - "notify::strength", - G_CALLBACK( foobar_panel_item_status_handle_network_strength_change ), - self ); - } - - if ( self->network_label ) - { - gtk_label_set_label( - GTK_LABEL( self->network_label ), self->network ? foobar_network_get_name( self->network ) : NULL ); - gtk_widget_set_visible( GTK_WIDGET( self->network_label ), self->network != NULL ); - } - - foobar_panel_item_status_reevaluate_network( self ); - } -} - -// -// Called when the wi-fi adapter's active network strength changes. -// -// This just forces re-evaluation of the network icon expression for reasons mentioned in -// foobar_panel_item_status_handle_network_change. -// -void foobar_panel_item_status_handle_network_strength_change( - GObject* object, - GParamSpec* pspec, - gpointer userdata ) -{ - (void)object; - (void)pspec; - FoobarPanelItemStatus* self = (FoobarPanelItemStatus*)userdata; - foobar_panel_item_status_reevaluate_network( self ); -} - -// -// Called when the button was clicked. -// -void foobar_panel_item_status_handle_clicked( - GtkButton* button, - gpointer userdata ) -{ - (void)button; - FoobarPanelItemStatus* self = (FoobarPanelItemStatus*)userdata; - - foobar_panel_item_invoke_action( FOOBAR_PANEL_ITEM( self ), self->action ); -} - -// -// Called when the user has scrolled over the brightness item, used to adjust the brightness level. -// -gboolean foobar_panel_item_status_handle_brightness_scroll( - GtkEventControllerScroll* controller, - gdouble dx, - gdouble dy, - gpointer userdata ) -{ - (void)controller; - (void)dx; - FoobarPanelItemStatus* self = (FoobarPanelItemStatus*)userdata; - - gint new_brightness = foobar_brightness_service_get_percentage( self->brightness_service ) + (gint)dy; - foobar_brightness_service_set_percentage( self->brightness_service, new_brightness ); - - return TRUE; -} - -// -// Called when the user has scrolled over the audio item, used to adjust the volume. -// -gboolean foobar_panel_item_status_handle_audio_scroll( - GtkEventControllerScroll* controller, - gdouble dx, - gdouble dy, - gpointer userdata ) -{ - (void)controller; - (void)dx; - FoobarPanelItemStatus* self = (FoobarPanelItemStatus*)userdata; - - FoobarAudioDevice* device = foobar_audio_service_get_default_output( self->audio_service ); - gint new_volume = foobar_audio_device_get_volume( device ) + (gint)dy; - foobar_audio_device_set_volume( device, new_volume ); - - return TRUE; -} - -// --------------------------------------------------------------------------------------------------------------------- -// Value Converters -// --------------------------------------------------------------------------------------------------------------------- - -// -// Derive the network icon from the active network adapter and its state. -// -// In addition, this also uses the wi-fi adapter's active network strength which is monitored separately (see -// foobar_panel_item_status_handle_network_change). -// -gchar* foobar_panel_item_status_compute_network_icon( - GtkExpression* expression, - FoobarNetworkAdapter* adapter, - FoobarNetworkAdapterState state, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - if ( FOOBAR_IS_NETWORK_ADAPTER_WIFI( adapter ) ) - { - if ( state == FOOBAR_NETWORK_ADAPTER_STATE_DISCONNECTED ) { return g_strdup( "fluent-wifi-off-symbolic" ); } - if ( state != FOOBAR_NETWORK_ADAPTER_STATE_CONNECTED ) { return g_strdup( "fluent-wifi-warning-symbolic" ); } - - FoobarNetwork* network = foobar_network_adapter_wifi_get_active( FOOBAR_NETWORK_ADAPTER_WIFI( adapter ) ); - gint strength = network ? foobar_network_get_strength( network ) : 0; - if ( strength <= 25 ) { return g_strdup( "fluent-wifi-4-symbolic" ); } - if ( strength <= 50 ) { return g_strdup( "fluent-wifi-3-symbolic" ); } - if ( strength <= 75 ) { return g_strdup( "fluent-wifi-2-symbolic" ); } - return g_strdup( "fluent-wifi-1-symbolic" ); - } - else - { - return g_strdup( "fluent-virtual-network-symbolic" ); - } -} - -// -// Derive the bluetooth icon from the bluetooth adapter's state and the number of currently connected devices. -// -gchar* foobar_panel_item_status_compute_bluetooth_icon( - GtkExpression* expression, - gboolean is_enabled, - guint connected_device_count, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - if (is_enabled) - { - return ( connected_device_count > 0 ) - ? g_strdup( "fluent-bluetooth-connected-symbolic" ) - : g_strdup( "fluent-bluetooth-symbolic" ); - } - else - { - return g_strdup( "fluent-bluetooth-off-symbolic" ); - } -} - -// -// Derive the battery icon from the current state structure. -// -gchar* foobar_panel_item_status_compute_battery_icon( - GtkExpression* expression, - FoobarBatteryState const* state, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - if ( state ) - { - gint percentage = foobar_battery_state_get_percentage( state ); - if ( foobar_battery_state_is_charging( state ) ) { return g_strdup( "fluent-battery-charge-symbolic" ); } - if ( percentage <= 5 ) { return g_strdup( "fluent-battery-0-symbolic" ); } - if ( percentage <= 15 ) { return g_strdup( "fluent-battery-1-symbolic" ); } - if ( percentage <= 25 ) { return g_strdup( "fluent-battery-2-symbolic" ); } - if ( percentage <= 35 ) { return g_strdup( "fluent-battery-3-symbolic" ); } - if ( percentage <= 45 ) { return g_strdup( "fluent-battery-4-symbolic" ); } - if ( percentage <= 55 ) { return g_strdup( "fluent-battery-5-symbolic" ); } - if ( percentage <= 65 ) { return g_strdup( "fluent-battery-6-symbolic" ); } - if ( percentage <= 75 ) { return g_strdup( "fluent-battery-7-symbolic" ); } - if ( percentage <= 85 ) { return g_strdup( "fluent-battery-8-symbolic" ); } - if ( percentage <= 95 ) { return g_strdup( "fluent-battery-9-symbolic" ); } - return g_strdup( "fluent-battery-10-symbolic" ); - } - else - { - return g_strdup( "fluent-plug-connected-symbolic" ); - } -} - -// -// Derive the battery label from the current state structure, showing the percentage if available. -// -gchar* foobar_panel_item_status_compute_battery_label( - GtkExpression* expression, - FoobarBatteryState const* state, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - if ( state ) - { - return g_strdup_printf( "%d%%", foobar_battery_state_get_percentage( state ) ); - } - else - { - return g_strdup( "n/a" ); - } -} - -// -// Derive the brightness icon from the current percentage value. -// -gchar* foobar_panel_item_status_compute_brightness_icon( - GtkExpression* expression, - gint percentage, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - if ( percentage <= 50 ) - { - return g_strdup( "fluent-brightness-low-symbolic" ); - } - else - { - return g_strdup( "fluent-brightness-high-symbolic" ); - } -} - -// -// Derive the brightness label from the current percentage value. -// -gchar* foobar_panel_item_status_compute_brightness_label( - GtkExpression* expression, - gint percentage, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - return g_strdup_printf( "%d%%", percentage ); -} - -// -// Derive the audio icon from the current state and volume of the default output device. -// -gchar* foobar_panel_item_status_compute_audio_icon( - GtkExpression* expression, - gboolean is_available, - gint volume, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - if ( is_available ) - { - if ( volume == 0 ) { return g_strdup( "fluent-speaker-mute-symbolic" ); } - if ( volume <= 33 ) { return g_strdup( "fluent-speaker-0-symbolic" ); } - if ( volume <= 67 ) { return g_strdup( "fluent-speaker-1-symbolic" ); } - return g_strdup( "fluent-speaker-2-symbolic" ); - } - else - { - return g_strdup( "fluent-speaker-off-symbolic" ); - } -} - -// -// Derive the audio label from the current state and volume of the default output device. -// -gchar* foobar_panel_item_status_compute_audio_label( - GtkExpression* expression, - gboolean is_available, - gint volume, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - if ( is_available ) - { - return g_strdup_printf( "%d%%", volume ); - } - else - { - return g_strdup( "n/a" ); - } -} - -// -// Derive the notification icon from the current number of notifications. -// -gchar* foobar_panel_item_status_compute_notifications_icon( - GtkExpression* expression, - guint count, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - switch ( count ) - { - case 0: - return g_strdup( "fluent-checkmark-circle-symbolic" ); - case 1: - return g_strdup( "fluent-number-circle-1-symbolic" ); - case 2: - return g_strdup( "fluent-number-circle-2-symbolic" ); - case 3: - return g_strdup( "fluent-number-circle-3-symbolic" ); - case 4: - return g_strdup( "fluent-number-circle-4-symbolic" ); - case 5: - return g_strdup( "fluent-number-circle-5-symbolic" ); - case 6: - return g_strdup( "fluent-number-circle-6-symbolic" ); - case 7: - return g_strdup( "fluent-number-circle-7-symbolic" ); - case 8: - return g_strdup( "fluent-number-circle-8-symbolic" ); - case 9: - return g_strdup( "fluent-number-circle-9-symbolic" ); - default: - return g_strdup( "fluent-more-circle-symbolic" ); - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// Helper Methods -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new icon displaying the specified status item, optionally adding a label to it (if supported). -// -GtkWidget* foobar_panel_item_status_create_item( - FoobarPanelItemStatus* self, - FoobarStatusItem item, - gboolean show_labels, - gboolean enable_scrolling ) -{ - switch ( item ) - { - case FOOBAR_STATUS_ITEM_NETWORK: - { - GtkWidget* box = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 ); - gtk_widget_set_valign( box, GTK_ALIGN_FILL ); - - GtkExpression* service_expr = gtk_constant_expression_new( - FOOBAR_TYPE_NETWORK_SERVICE, - self->network_service ); - GtkExpression* active_expr = gtk_property_expression_new( - FOOBAR_TYPE_NETWORK_SERVICE, - service_expr, - "active" ); - GtkExpression* state_expr = gtk_property_expression_new( - FOOBAR_TYPE_NETWORK_ADAPTER, - gtk_expression_ref( active_expr ), - "state" ); - GtkExpression* icon_params[] = { active_expr, state_expr }; - self->network_icon_expr = gtk_cclosure_expression_new( - G_TYPE_STRING, - NULL, - G_N_ELEMENTS( icon_params ), - icon_params, - G_CALLBACK( foobar_panel_item_status_compute_network_icon ), - self, - NULL ); - self->network_icon = gtk_image_new( ); - gtk_widget_set_valign( self->network_icon, GTK_ALIGN_CENTER ); - gtk_expression_bind( gtk_expression_ref( self->network_icon_expr ), self->network_icon, "icon-name", NULL ); - gtk_box_append( GTK_BOX( box ), self->network_icon ); - - if ( show_labels ) - { - self->network_label = gtk_label_new( NULL ); - gtk_widget_set_valign( self->network_label, GTK_ALIGN_CENTER ); - gtk_label_set_max_width_chars( GTK_LABEL( self->network_label ), 16 ); - gtk_label_set_ellipsize( GTK_LABEL( self->network_label ), PANGO_ELLIPSIZE_END ); - gtk_box_append( GTK_BOX( box ), self->network_label ); - } - - // Manually subscribe to network (/strength) because evaluation might fail. - - FoobarNetworkAdapterWifi* adapter = foobar_network_service_get_wifi( self->network_service ); - if ( adapter ) - { - self->network_handler_id = g_signal_connect( - adapter, - "notify::active", - G_CALLBACK( foobar_panel_item_status_handle_network_change ), - self ); - if ( foobar_network_adapter_wifi_get_active( adapter ) ) - { - self->network = g_object_ref( foobar_network_adapter_wifi_get_active( adapter ) ); - self->network_strength_handler_id = g_signal_connect( - self->network, - "notify::strength", - G_CALLBACK( foobar_panel_item_status_handle_network_strength_change ), - self ); - } - if ( self->network_label ) - { - gtk_label_set_label( - GTK_LABEL( self->network_label ), - self->network ? foobar_network_get_name( self->network ) : NULL ); - gtk_widget_set_visible( GTK_WIDGET( self->network_label ), self->network != NULL ); - } - } - - return box; - } - case FOOBAR_STATUS_ITEM_BLUETOOTH: - { - GtkWidget* icon = gtk_image_new( ); - gtk_widget_set_valign( icon, GTK_ALIGN_CENTER ); - - GtkExpression* service_expr = gtk_constant_expression_new( - FOOBAR_TYPE_BLUETOOTH_SERVICE, - self->bluetooth_service ); - GtkExpression* enabled_expr = gtk_property_expression_new( - FOOBAR_TYPE_BLUETOOTH_SERVICE, - gtk_expression_ref( service_expr ), - "is-enabled" ); - GtkExpression* connected_devices_expr = gtk_property_expression_new( - FOOBAR_TYPE_BLUETOOTH_SERVICE, - service_expr, - "connected-devices" ); - GtkExpression* connected_device_count_expr = gtk_property_expression_new( - GTK_TYPE_FILTER_LIST_MODEL, - connected_devices_expr, - "n-items" ); - GtkExpression* icon_params[] = { enabled_expr, connected_device_count_expr }; - GtkExpression* icon_expr = gtk_cclosure_expression_new( - G_TYPE_STRING, - NULL, - G_N_ELEMENTS( icon_params ), - icon_params, - G_CALLBACK( foobar_panel_item_status_compute_bluetooth_icon ), - NULL, - NULL ); - gtk_expression_bind( icon_expr, icon, "icon-name", NULL ); - - return icon; - } - case FOOBAR_STATUS_ITEM_BATTERY: - { - GtkWidget* box = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 ); - gtk_widget_set_valign( box, GTK_ALIGN_FILL ); - - GtkExpression* service_expr = gtk_constant_expression_new( - FOOBAR_TYPE_BATTERY_SERVICE, - self->battery_service ); - GtkExpression* state_expr = gtk_property_expression_new( - FOOBAR_TYPE_BATTERY_SERVICE, - service_expr, - "state" ); - - GtkExpression* icon_params[] = { state_expr }; - GtkExpression* icon_expr = gtk_cclosure_expression_new( - G_TYPE_STRING, - NULL, - G_N_ELEMENTS( icon_params ), - icon_params, - G_CALLBACK( foobar_panel_item_status_compute_battery_icon ), - NULL, - NULL ); - GtkWidget* icon = gtk_image_new( ); - gtk_widget_set_valign( icon, GTK_ALIGN_CENTER ); - gtk_expression_bind( icon_expr, icon, "icon-name", NULL ); - gtk_box_append( GTK_BOX( box ), icon ); - - if ( show_labels ) - { - GtkExpression* label_params[] = { gtk_expression_ref( state_expr ) }; - GtkExpression* label_expr = gtk_cclosure_expression_new( - G_TYPE_STRING, - NULL, - G_N_ELEMENTS( label_params ), - label_params, - G_CALLBACK( foobar_panel_item_status_compute_battery_label ), - NULL, - NULL ); - GtkWidget* label = gtk_label_new( NULL ); - gtk_widget_set_valign( label, GTK_ALIGN_CENTER ); - gtk_expression_bind( label_expr, label, "label", NULL ); - gtk_box_append( GTK_BOX( box ), label ); - } - - return box; - } - case FOOBAR_STATUS_ITEM_BRIGHTNESS: - { - GtkWidget* box = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 ); - gtk_widget_set_valign( box, GTK_ALIGN_FILL ); - - if ( enable_scrolling ) - { - GtkEventController* scroll_controller = gtk_event_controller_scroll_new( - GTK_EVENT_CONTROLLER_SCROLL_VERTICAL | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE ); - g_signal_connect( - scroll_controller, - "scroll", - G_CALLBACK( foobar_panel_item_status_handle_brightness_scroll ), - self ); - gtk_widget_add_controller( box, scroll_controller ); - } - - GtkExpression* service_expr = gtk_constant_expression_new( - FOOBAR_TYPE_BRIGHTNESS_SERVICE, - self->brightness_service ); - GtkExpression* percentage_expr = gtk_property_expression_new( - FOOBAR_TYPE_BRIGHTNESS_SERVICE, - service_expr, - "percentage" ); - - GtkExpression* icon_params[] = { percentage_expr }; - GtkExpression* icon_expr = gtk_cclosure_expression_new( - G_TYPE_STRING, - NULL, - G_N_ELEMENTS( icon_params ), - icon_params, - G_CALLBACK( foobar_panel_item_status_compute_brightness_icon ), - NULL, - NULL ); - GtkWidget* icon = gtk_image_new( ); - gtk_widget_set_valign( icon, GTK_ALIGN_CENTER ); - gtk_expression_bind( icon_expr, icon, "icon-name", NULL ); - gtk_box_append( GTK_BOX( box ), icon ); - - if ( show_labels ) - { - GtkExpression* label_params[] = { gtk_expression_ref( percentage_expr ) }; - GtkExpression* label_expr = gtk_cclosure_expression_new( - G_TYPE_STRING, - NULL, - G_N_ELEMENTS( label_params ), - label_params, - G_CALLBACK( foobar_panel_item_status_compute_brightness_label ), - NULL, - NULL ); - GtkWidget* label = gtk_label_new( NULL ); - gtk_widget_set_valign( label, GTK_ALIGN_CENTER ); - gtk_expression_bind( label_expr, label, "label", NULL ); - gtk_box_append( GTK_BOX( box ), label ); - } - - return box; - } - case FOOBAR_STATUS_ITEM_AUDIO: - { - GtkWidget* box = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 ); - gtk_widget_set_valign( box, GTK_ALIGN_FILL ); - - if ( enable_scrolling ) - { - GtkEventController* scroll_controller = gtk_event_controller_scroll_new( - GTK_EVENT_CONTROLLER_SCROLL_VERTICAL | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE ); - g_signal_connect( - scroll_controller, - "scroll", - G_CALLBACK( foobar_panel_item_status_handle_audio_scroll ), - self ); - gtk_widget_add_controller( box, scroll_controller ); - } - - GtkExpression* device_expr = gtk_constant_expression_new( - FOOBAR_TYPE_AUDIO_DEVICE, - foobar_audio_service_get_default_output( self->audio_service ) ); - GtkExpression* available_expr = gtk_property_expression_new( - FOOBAR_TYPE_AUDIO_DEVICE, - gtk_expression_ref( device_expr ), - "is-available" ); - GtkExpression* volume_expr = gtk_property_expression_new( - FOOBAR_TYPE_AUDIO_DEVICE, - gtk_expression_ref( device_expr ), - "volume" ); - - GtkExpression* icon_params[] = { available_expr, volume_expr }; - GtkExpression* icon_expr = gtk_cclosure_expression_new( - G_TYPE_STRING, - NULL, - G_N_ELEMENTS( icon_params ), - icon_params, - G_CALLBACK( foobar_panel_item_status_compute_audio_icon ), - NULL, - NULL ); - GtkWidget* icon = gtk_image_new( ); - gtk_widget_set_valign( icon, GTK_ALIGN_CENTER ); - gtk_expression_bind( icon_expr, icon, "icon-name", NULL ); - gtk_box_append( GTK_BOX( box ), icon ); - - if ( show_labels ) - { - GtkExpression* label_params[] = { gtk_expression_ref( available_expr ), gtk_expression_ref( volume_expr ) }; - GtkExpression* label_expr = gtk_cclosure_expression_new( - G_TYPE_STRING, - NULL, - G_N_ELEMENTS( label_params ), - label_params, - G_CALLBACK( foobar_panel_item_status_compute_audio_label ), - NULL, - NULL ); - GtkWidget* label = gtk_label_new( NULL ); - gtk_widget_set_valign( label, GTK_ALIGN_CENTER ); - gtk_expression_bind( label_expr, label, "label", NULL ); - gtk_box_append( GTK_BOX( box ), label ); - } - - return box; - } - case FOOBAR_STATUS_ITEM_NOTIFICATIONS: - { - GtkWidget* icon = gtk_image_new( ); - gtk_widget_set_valign( icon, GTK_ALIGN_CENTER ); - - GtkExpression* list_expr = gtk_constant_expression_new( - G_TYPE_LIST_MODEL, - foobar_notification_service_get_notifications( self->notification_service ) ); - GtkExpression* count_expr = gtk_property_expression_new( - GTK_TYPE_SORT_LIST_MODEL, - list_expr, - "n-items" ); - GtkExpression* icon_params[] = { count_expr }; - GtkExpression* icon_expr = gtk_cclosure_expression_new( - G_TYPE_STRING, - NULL, - G_N_ELEMENTS( icon_params ), - icon_params, - G_CALLBACK( foobar_panel_item_status_compute_notifications_icon ), - NULL, - NULL ); - gtk_expression_bind( icon_expr, icon, "icon-name", NULL ); - - return icon; - } - default: - g_warn_if_reached( ); - return NULL; - } -} - -// -// Force re-evaluation of the network icon expression. -// -// This is used whenever the active network or its strength changes. -// -void foobar_panel_item_status_reevaluate_network( FoobarPanelItemStatus* self ) -{ - if ( self->network_icon && self->network_icon_expr ) - { - GValue value = G_VALUE_INIT; - if ( gtk_expression_evaluate( self->network_icon_expr, NULL, &value ) ) - { - gtk_image_set_from_icon_name( GTK_IMAGE( self->network_icon ), g_value_get_string( &value ) ); - } - g_value_unset( &value ); - } -} diff --git a/src/widgets/panel/panel-item-status.h b/src/widgets/panel/panel-item-status.h deleted file mode 100644 index 0f1cfdb..0000000 --- a/src/widgets/panel/panel-item-status.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "widgets/panel/panel-item.h" -#include "services/battery-service.h" -#include "services/brightness-service.h" -#include "services/audio-service.h" -#include "services/network-service.h" -#include "services/bluetooth-service.h" -#include "services/notification-service.h" - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_PANEL_ITEM_STATUS foobar_panel_item_status_get_type( ) - -G_DECLARE_FINAL_TYPE( FoobarPanelItemStatus, foobar_panel_item_status, FOOBAR, PANEL_ITEM_STATUS, FoobarPanelItem ) - -FoobarPanelItem* foobar_panel_item_status_new( FoobarPanelItemConfiguration const* config, - FoobarBatteryService* battery_service, - FoobarBrightnessService* brightness_service, - FoobarAudioService* audio_service, - FoobarNetworkService* network_service, - FoobarBluetoothService* bluetooth_service, - FoobarNotificationService* notification_service ); - -G_END_DECLS diff --git a/src/widgets/panel/panel-item-workspaces.c b/src/widgets/panel/panel-item-workspaces.c deleted file mode 100644 index dff629b..0000000 --- a/src/widgets/panel/panel-item-workspaces.c +++ /dev/null @@ -1,327 +0,0 @@ -#include "widgets/panel/panel-item-workspaces.h" -#include "widgets/inset-container.h" - -// -// FoobarPanelItemWorkspaces: -// -// A panel item showing all workspaces for the current monitor (if multi-monitor mode is enabled) as buttons, indicating -// the current state of the workspace (i.e., whether it's active, visible, special, etc.). -// - -struct _FoobarPanelItemWorkspaces -{ - FoobarPanelItem parent_instance; - GtkWidget* list_view; - GtkWidget* inset_container; - FoobarWorkspaceService* workspace_service; - gint button_size; - gint spacing; - GtkFilter* monitor_filter; - gulong monitor_configuration_handler_id; -}; - -enum -{ - PROP_ORIENTATION = 1, - N_PROPS, -}; - -static GParamSpec* props[N_PROPS] = { 0 }; - -static void foobar_panel_item_workspaces_class_init ( FoobarPanelItemWorkspacesClass* klass ); -static void foobar_panel_item_workspaces_init ( FoobarPanelItemWorkspaces* self ); -static void foobar_panel_item_workspaces_get_property ( GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ); -static void foobar_panel_item_workspaces_set_property ( GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ); -static void foobar_panel_item_workspaces_finalize ( GObject* object ); -static void foobar_panel_item_workspaces_handle_item_setup ( GtkListItemFactory* factory, - GtkListItem* list_item, - gpointer userdata ); -static void foobar_panel_item_workspaces_handle_item_clicked ( GtkButton* button, - gpointer userdata ); -static void foobar_panel_item_workspaces_handle_monitor_configuration_changed( FoobarWorkspaceService* service, - gpointer userdata ); -static gchar** foobar_panel_item_workspaces_compute_css_classes ( GtkExpression* expression, - FoobarWorkspaceFlags flags, - gpointer userdata ); -static gboolean foobar_panel_item_workspaces_monitor_filter_func ( gpointer item, - gpointer userdata ); - -G_DEFINE_FINAL_TYPE_WITH_CODE( - FoobarPanelItemWorkspaces, - foobar_panel_item_workspaces, - FOOBAR_TYPE_PANEL_ITEM, - G_IMPLEMENT_INTERFACE( GTK_TYPE_ORIENTABLE, NULL ) ) - -// --------------------------------------------------------------------------------------------------------------------- -// Panel Item Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for workspace panel items. -// -void foobar_panel_item_workspaces_class_init( FoobarPanelItemWorkspacesClass* klass ) -{ - GObjectClass* object_klass = G_OBJECT_CLASS( klass ); - object_klass->get_property = foobar_panel_item_workspaces_get_property; - object_klass->set_property = foobar_panel_item_workspaces_set_property; - object_klass->finalize = foobar_panel_item_workspaces_finalize; - - gpointer orientable_iface = g_type_default_interface_peek( GTK_TYPE_ORIENTABLE ); - props[PROP_ORIENTATION] = g_param_spec_override( - "orientation", - g_object_interface_find_property( orientable_iface, "orientation" ) ); - g_object_class_install_properties( object_klass, N_PROPS, props ); -} - -// -// Instance initialization for workspace panel items. -// -void foobar_panel_item_workspaces_init( FoobarPanelItemWorkspaces* self ) -{ - GtkListItemFactory* item_factory = gtk_signal_list_item_factory_new( ); - g_signal_connect( item_factory, "setup", G_CALLBACK( foobar_panel_item_workspaces_handle_item_setup ), self ); - - self->list_view = gtk_list_view_new( NULL, item_factory ); - gtk_widget_set_halign( self->list_view, GTK_ALIGN_CENTER ); - gtk_widget_set_valign( self->list_view, GTK_ALIGN_CENTER ); - gtk_list_view_set_single_click_activate( GTK_LIST_VIEW( self->list_view ), TRUE ); - - self->inset_container = foobar_inset_container_new( ); - foobar_inset_container_set_child( FOOBAR_INSET_CONTAINER( self->inset_container ), GTK_WIDGET( self->list_view ) ); - - gtk_widget_add_css_class( GTK_WIDGET( self ), "workspaces" ); - foobar_panel_item_set_child( FOOBAR_PANEL_ITEM( self ), GTK_WIDGET( self->inset_container ) ); -} - -// -// Property getter implementation, mapping a property id to a method. -// -void foobar_panel_item_workspaces_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ) -{ - FoobarPanelItemWorkspaces* self = (FoobarPanelItemWorkspaces*)object; - - switch ( prop_id ) - { - case PROP_ORIENTATION: - g_value_set_enum( value, gtk_orientable_get_orientation( GTK_ORIENTABLE( self->list_view ) ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Property setter implementation, mapping a property id to a method. -// -void foobar_panel_item_workspaces_set_property( - GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ) -{ - FoobarPanelItemWorkspaces* self = (FoobarPanelItemWorkspaces*)object; - - switch ( prop_id ) - { - case PROP_ORIENTATION: - gtk_orientable_set_orientation( GTK_ORIENTABLE( self->list_view ), g_value_get_enum( value ) ); - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_ORIENTATION] ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Instance cleanup for workspace panel items. -// -void foobar_panel_item_workspaces_finalize( GObject* object ) -{ - FoobarPanelItemWorkspaces* self = (FoobarPanelItemWorkspaces*)object; - - g_clear_signal_handler( &self->monitor_configuration_handler_id, self->workspace_service ); - g_clear_object( &self->workspace_service ); - g_clear_object( &self->monitor_filter ); - - G_OBJECT_CLASS( foobar_panel_item_workspaces_parent_class )->finalize( object ); -} - - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Create a new workspaces panel item with the given configuration. -// -// If monitor is not NULL, only workspaces on this monitor will be shown. -// -FoobarPanelItem* foobar_panel_item_workspaces_new( - FoobarPanelItemConfiguration const* config, - GdkMonitor* monitor, - FoobarWorkspaceService* workspace_service ) -{ - g_return_val_if_fail( config != NULL, NULL ); - g_return_val_if_fail( foobar_panel_item_configuration_get_kind( config ) == FOOBAR_PANEL_ITEM_KIND_WORKSPACES, NULL ); - g_return_val_if_fail( monitor == NULL || GDK_IS_MONITOR( monitor ), NULL ); - g_return_val_if_fail( FOOBAR_IS_WORKSPACE_SERVICE( workspace_service ), NULL ); - - FoobarPanelItemWorkspaces* self = g_object_new( FOOBAR_TYPE_PANEL_ITEM_WORKSPACES, NULL ); - self->button_size = foobar_panel_item_workspaces_configuration_get_button_size( config ); - self->spacing = foobar_panel_item_workspaces_configuration_get_spacing( config ); - self->workspace_service = g_object_ref( workspace_service ); - - // Set up the source model, optionally enabling filtering. - - GListModel* source_model = g_object_ref( foobar_workspace_service_get_workspaces( self->workspace_service ) ); - if ( monitor ) - { - GtkCustomFilter* filter = gtk_custom_filter_new( - foobar_panel_item_workspaces_monitor_filter_func, - g_object_ref( monitor ), - g_object_unref ); - self->monitor_filter = GTK_FILTER( filter ); - source_model = G_LIST_MODEL( gtk_filter_list_model_new( source_model, g_object_ref( self->monitor_filter ) ) ); - - self->monitor_configuration_handler_id = g_signal_connect( - self->workspace_service, - "monitor-configuration-changed", - G_CALLBACK( foobar_panel_item_workspaces_handle_monitor_configuration_changed ), - self ); - } - GtkNoSelection* selection_model = gtk_no_selection_new( source_model ); - gtk_list_view_set_model( GTK_LIST_VIEW( self->list_view ), GTK_SELECTION_MODEL( selection_model ) ); - - // Wrap the list in an inset container to remove the outer margin from the items. - - foobar_inset_container_set_inset_horizontal( FOOBAR_INSET_CONTAINER( self->inset_container ), -self->spacing / 2 ); - foobar_inset_container_set_inset_vertical( FOOBAR_INSET_CONTAINER( self->inset_container ), -self->spacing / 2 ); - - return FOOBAR_PANEL_ITEM( self ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Signal Handlers -// --------------------------------------------------------------------------------------------------------------------- - -// -// Called by the list view to create a widget for displaying a workspace. -// -void foobar_panel_item_workspaces_handle_item_setup( - GtkListItemFactory* factory, - GtkListItem* list_item, - gpointer userdata ) -{ - (void)factory; - FoobarPanelItemWorkspaces* self = (FoobarPanelItemWorkspaces*)userdata; - - GtkWidget* button = gtk_button_new( ); - gtk_widget_set_size_request( button, self->button_size, self->button_size ); - gtk_widget_set_margin_top( button, self->spacing / 2 ); - gtk_widget_set_margin_bottom( button, self->spacing / 2 ); - gtk_widget_set_margin_start( button, self->spacing / 2 ); - gtk_widget_set_margin_end( button, self->spacing / 2 ); - g_signal_connect( - button, - "clicked", - G_CALLBACK( foobar_panel_item_workspaces_handle_item_clicked ), - list_item ); - - gtk_list_item_set_child( list_item, button ); - - { - GtkExpression* item_expr = gtk_property_expression_new( GTK_TYPE_LIST_ITEM, NULL, "item" ); - GtkExpression* active_expr = gtk_property_expression_new( FOOBAR_TYPE_WORKSPACE, item_expr, "flags" ); - GtkExpression* params[] = { active_expr }; - GtkExpression* css_expr = gtk_cclosure_expression_new( - G_TYPE_STRV, - NULL, - G_N_ELEMENTS( params ), - params, - G_CALLBACK( foobar_panel_item_workspaces_compute_css_classes ), - NULL, - NULL ); - gtk_expression_bind( css_expr, button, "css-classes", list_item ); - } -} - -// -// Called by the workspace service when the monitor for any workspace has changed. -// -// This is needed because the GtkFilterListModel does not track changes to the item properties and needs to be -// re-evaluated manually. -// -void foobar_panel_item_workspaces_handle_monitor_configuration_changed( - FoobarWorkspaceService* service, - gpointer userdata ) -{ - (void)service; - FoobarPanelItemWorkspaces* self = (FoobarPanelItemWorkspaces*)userdata; - - gtk_filter_changed( self->monitor_filter, GTK_FILTER_CHANGE_DIFFERENT ); -} - -// -// Called when a workspace button was clicked, activating that workspace. -// -void foobar_panel_item_workspaces_handle_item_clicked( GtkButton* button, gpointer userdata ) -{ - (void)button; - GtkListItem* item = (GtkListItem*)userdata; - - FoobarWorkspace* workspace = gtk_list_item_get_item( item ); - if ( workspace ) { foobar_workspace_activate( workspace ); } -} - -// --------------------------------------------------------------------------------------------------------------------- -// Value Converters -// --------------------------------------------------------------------------------------------------------------------- - -// -// Derive the list of CSS classes for a workspace button from the workspace's current flags. -// -gchar** foobar_panel_item_workspaces_compute_css_classes( - GtkExpression* expression, - FoobarWorkspaceFlags flags, - gpointer userdata ) -{ - (void)expression; - (void)userdata; - - GStrvBuilder* builder = g_strv_builder_new( ); - if ( flags & FOOBAR_WORKSPACE_FLAGS_ACTIVE ) { g_strv_builder_add( builder, "active" ); } - if ( flags & FOOBAR_WORKSPACE_FLAGS_VISIBLE ) { g_strv_builder_add( builder, "visible" ); } - if ( flags & FOOBAR_WORKSPACE_FLAGS_SPECIAL ) { g_strv_builder_add( builder, "special" ); } - if ( flags & FOOBAR_WORKSPACE_FLAGS_URGENT ) { g_strv_builder_add( builder, "urgent" ); } - if ( flags & FOOBAR_WORKSPACE_FLAGS_PERSISTENT ) { g_strv_builder_add( builder, "persistent" ); } - return g_strv_builder_end( builder ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Helper Methods -// --------------------------------------------------------------------------------------------------------------------- - -// -// Check if a workspace is on the panel's monitor. -// -gboolean foobar_panel_item_workspaces_monitor_filter_func( gpointer item, gpointer userdata ) -{ - FoobarWorkspace* workspace = (FoobarWorkspace*)item; - GdkMonitor* monitor = (GdkMonitor*)userdata; - - gchar const* expected = gdk_monitor_get_connector( monitor ); - gchar const* actual = foobar_workspace_get_monitor( workspace ); - return !expected || !g_strcmp0( expected, actual ); -} diff --git a/src/widgets/panel/panel-item-workspaces.h b/src/widgets/panel/panel-item-workspaces.h deleted file mode 100644 index d179217..0000000 --- a/src/widgets/panel/panel-item-workspaces.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "widgets/panel/panel-item.h" -#include "services/workspace-service.h" - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_PANEL_ITEM_WORKSPACES foobar_panel_item_workspaces_get_type( ) - -G_DECLARE_FINAL_TYPE( FoobarPanelItemWorkspaces, foobar_panel_item_workspaces, FOOBAR, PANEL_ITEM_WORKSPACES, FoobarPanelItem ) - -FoobarPanelItem* foobar_panel_item_workspaces_new( FoobarPanelItemConfiguration const* config, - GdkMonitor* monitor, - FoobarWorkspaceService* workspace_service ); - -G_END_DECLS diff --git a/src/widgets/panel/panel-item.c b/src/widgets/panel/panel-item.c deleted file mode 100644 index 918d9f5..0000000 --- a/src/widgets/panel/panel-item.c +++ /dev/null @@ -1,195 +0,0 @@ -#include "widgets/panel/panel-item.h" -#include "application.h" - -// -// FoobarPanelItem: -// -// Base class for all panel items. This is basically a bin layout where the subclass usually sets the child widget. -// - -typedef struct _FoobarPanelItemPrivate -{ - GtkWidget* child; -} FoobarPanelItemPrivate; - -enum -{ - PROP_CHILD = 1, - N_PROPS, -}; - -static GParamSpec* props[N_PROPS] = { 0 }; - -static void foobar_panel_item_class_init ( FoobarPanelItemClass* klass ); -static void foobar_panel_item_init ( FoobarPanelItem* self ); -static void foobar_panel_item_get_property( GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ); -static void foobar_panel_item_set_property( GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ); -static void foobar_panel_item_dispose ( GObject* object ); - -G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE( FoobarPanelItem, foobar_panel_item, GTK_TYPE_WIDGET ) - -// --------------------------------------------------------------------------------------------------------------------- -// Widget Implementation -// --------------------------------------------------------------------------------------------------------------------- - -// -// Static initialization for panel items. -// -void foobar_panel_item_class_init( FoobarPanelItemClass* klass ) -{ - GtkWidgetClass* widget_klass = GTK_WIDGET_CLASS( klass ); - gtk_widget_class_set_css_name( widget_klass, "panel-item" ); - gtk_widget_class_set_layout_manager_type( widget_klass, GTK_TYPE_BIN_LAYOUT ); - - GObjectClass* object_klass = G_OBJECT_CLASS( klass ); - object_klass->get_property = foobar_panel_item_get_property; - object_klass->set_property = foobar_panel_item_set_property; - object_klass->dispose = foobar_panel_item_dispose; - - props[PROP_CHILD] = g_param_spec_object( - "child", - "Child", - "Child widget for the panel item.", - GTK_TYPE_WIDGET, - G_PARAM_READWRITE ); - g_object_class_install_properties( object_klass, N_PROPS, props ); -} - -// -// Instance initialization for panel items. -// -void foobar_panel_item_init( FoobarPanelItem* self ) -{ - (void)self; -} - -// -// Property getter implementation, mapping a property id to a method. -// -void foobar_panel_item_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ) -{ - FoobarPanelItem* self = (FoobarPanelItem*)object; - - switch ( prop_id ) - { - case PROP_CHILD: - g_value_set_object( value, foobar_panel_item_get_child( self ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Property setter implementation, mapping a property id to a method. -// -void foobar_panel_item_set_property( - GObject* object, - guint prop_id, - GValue const* value, - GParamSpec* pspec ) -{ - FoobarPanelItem* self = (FoobarPanelItem*)object; - - switch ( prop_id ) - { - case PROP_CHILD: - foobar_panel_item_set_child( self, g_value_get_object( value ) ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); - break; - } -} - -// -// Instance de-initialization for panel items. -// -void foobar_panel_item_dispose( GObject* object ) -{ - FoobarPanelItem* self = (FoobarPanelItem*)object; - FoobarPanelItemPrivate* priv = foobar_panel_item_get_instance_private( self ); - - g_clear_pointer( &priv->child, gtk_widget_unparent ); - - G_OBJECT_CLASS( foobar_panel_item_parent_class )->dispose( object ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------------------------------------------------- - -// -// Get the child widget for the panel item. -// -GtkWidget* foobar_panel_item_get_child( FoobarPanelItem* self ) -{ - g_return_val_if_fail( FOOBAR_IS_PANEL_ITEM( self ), NULL ); - FoobarPanelItemPrivate* priv = foobar_panel_item_get_instance_private( self ); - - return priv->child; -} - -// -// Update the child widget for the panel item. -// -void foobar_panel_item_set_child( - FoobarPanelItem* self, - GtkWidget* child ) -{ - g_return_if_fail( FOOBAR_IS_PANEL_ITEM( self ) ); - FoobarPanelItemPrivate* priv = foobar_panel_item_get_instance_private( self ); - g_return_if_fail( child == NULL || priv->child == child || gtk_widget_get_parent( child ) == NULL ); - - if ( priv->child != child ) - { - g_clear_pointer( &priv->child, gtk_widget_unparent ); - - if ( child ) - { - priv->child = child; - gtk_widget_set_parent( child, GTK_WIDGET( self ) ); - } - - g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_CHILD] ); - } -} - -// -// Invoke the action for the panel item. -// -// This needs to be triggered by a subclass, for example by adding a button to the item. Support for panel item actions -// is opt-in and subclasses have to explicitly implement it. This is just a helper for implementing the action. -// -void foobar_panel_item_invoke_action( - FoobarPanelItem* self, - FoobarPanelItemAction action ) -{ - g_return_if_fail( FOOBAR_IS_PANEL_ITEM( self ) ); - - switch ( action ) - { - case FOOBAR_PANEL_ITEM_ACTION_NONE: - break; - case FOOBAR_PANEL_ITEM_ACTION_LAUNCHER: - foobar_application_toggle_launcher( FOOBAR_APPLICATION_DEFAULT ); - break; - case FOOBAR_PANEL_ITEM_ACTION_CONTROL_CENTER: - foobar_application_toggle_control_center( FOOBAR_APPLICATION_DEFAULT ); - break; - default: - g_warn_if_reached( ); - break; - } -} diff --git a/src/widgets/panel/panel-item.h b/src/widgets/panel/panel-item.h deleted file mode 100644 index 12a7e35..0000000 --- a/src/widgets/panel/panel-item.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#include "services/configuration-service.h" - -G_BEGIN_DECLS - -#define FOOBAR_TYPE_PANEL_ITEM foobar_panel_item_get_type( ) - -G_DECLARE_DERIVABLE_TYPE( FoobarPanelItem, foobar_panel_item, FOOBAR, PANEL_ITEM, GtkWidget ) - -struct _FoobarPanelItemClass -{ - GtkWidgetClass parent_class; -}; - -GtkWidget* foobar_panel_item_get_child ( FoobarPanelItem* self ); -void foobar_panel_item_set_child ( FoobarPanelItem* self, - GtkWidget* child ); -void foobar_panel_item_invoke_action( FoobarPanelItem* self, - FoobarPanelItemAction action ); - -G_END_DECLS -- cgit v1.3.1