From cabb09dc5607f11a43d958c28566c8ed9e0371f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 16 May 2025 10:56:27 -0700 Subject: [PATCH 01/24] Bump deps --- README.md | 8 ++++---- meson.build | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 09c7fa65..221f9071 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ You'll need the following dependencies: libcanberra-gtk-dev - libcanberra-gtk3-dev - libgranite-dev + libcanberra-gtk4-dev + libgranite-7-dev libglib2.0-dev - libgtk-3-dev + libgtk-4-dev libnotify-dev libpulse-dev - libwingpanel-dev + libwingpanel-8-dev meson (>= 0.57.0) valac (>= 0.26) diff --git a/meson.build b/meson.build index 7e49b012..ce1e94fe 100644 --- a/meson.build +++ b/meson.build @@ -28,7 +28,7 @@ gresource = gnome.compile_resources( source_dir: 'data' ) -wingpanel_dep = dependency('wingpanel', version: '>=2.1.0') +wingpanel_dep = dependency('wingpanel-8', version: '>=2.1.0') wingpanel_indicatorsdir = wingpanel_dep.get_pkgconfig_variable('indicatorsdir', define_variable: ['libdir', libdir]) config_data = configuration_data() @@ -63,13 +63,13 @@ shared_module( dependency('glib-2.0'), dependency('gio-2.0'), dependency('gobject-2.0'), - dependency('granite', version: '>=6.0.0'), - dependency('gtk+-3.0'), + dependency('granite-7', version: '>=6.0.0'), + dependency('gtk4'), dependency('libpulse'), dependency('libpulse-mainloop-glib'), dependency('libnotify'), dependency('libcanberra'), - dependency('libcanberra-gtk3'), + # dependency('libcanberra-gtk4'), meson.get_compiler('vala').find_library('libpulse-ext', dirs: join_paths(meson.source_root(), 'vapi')), wingpanel_dep ], From b0b763032a7d0ee170e4089189898a2f0dd81610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Thu, 22 May 2025 19:25:50 -0700 Subject: [PATCH 02/24] =?UTF-8?q?DisplayWidget:=20multipress=20=E2=86=92?= =?UTF-8?q?=20Click?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Widgets/DisplayWidget.vala | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Widgets/DisplayWidget.vala b/src/Widgets/DisplayWidget.vala index f73d8930..9821d324 100644 --- a/src/Widgets/DisplayWidget.vala +++ b/src/Widgets/DisplayWidget.vala @@ -26,9 +26,6 @@ public class Sound.DisplayWidget : Gtk.Box { public signal void volume_scroll_event (Gdk.EventScroll e); public signal void mic_scroll_event (Gdk.EventScroll e); - private Gtk.GestureMultiPress mic_gesture_click; - private Gtk.GestureMultiPress volume_gesture_click; - construct { var volume_icon = new Gtk.Image () { pixel_size = 24 @@ -71,7 +68,7 @@ public class Sound.DisplayWidget : Gtk.Box { return Gdk.EVENT_STOP; }); - mic_gesture_click = new Gtk.GestureMultiPress (mic_event_box) { + var mic_gesture_click = new Gtk.GestureClick () { button = Gdk.BUTTON_MIDDLE }; mic_gesture_click.pressed.connect (() => { @@ -80,7 +77,9 @@ public class Sound.DisplayWidget : Gtk.Box { mic_gesture_click.reset (); }); - volume_gesture_click = new Gtk.GestureMultiPress (volume_event_box) { + mic_event_box.add_controller (mic_gesture_click); + + var volume_gesture_click = new Gtk.GestureClick () { button = Gdk.BUTTON_MIDDLE }; volume_gesture_click.pressed.connect (() => { @@ -89,6 +88,8 @@ public class Sound.DisplayWidget : Gtk.Box { volume_gesture_click.reset (); }); + volume_event_box.add_controller (volume_gesture_click); + bind_property ( "icon-name", volume_icon, From 8e8707d2cedb6bd3ef804a67c8a65820fb71dc7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 12 Aug 2025 09:15:43 -0700 Subject: [PATCH 03/24] Comment out scroll events --- src/Indicator.vala | 136 ++++++++++++++++----------------- src/Widgets/DeviceItem.vala | 4 +- src/Widgets/DisplayWidget.vala | 8 +- src/Widgets/Scale.vala | 2 +- 4 files changed, 75 insertions(+), 75 deletions(-) diff --git a/src/Indicator.vala b/src/Indicator.vala index 341b912d..2116fad4 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -337,19 +337,19 @@ public class Sound.Indicator : Wingpanel.Indicator { display_widget.icon_name = get_volume_icon (volume_control.volume.volume); } - private void on_volume_icon_scroll_event (Gdk.EventScroll e) { - double dir = 0.0; - if (handle_scroll_event (e, out dir)) { - handle_change (dir, false); - } - } - - private void on_mic_icon_scroll_event (Gdk.EventScroll e) { - double dir = 0.0; - if (handle_scroll_event (e, out dir)) { - handle_change (dir, true); - } - } + // private void on_volume_icon_scroll_event (Gdk.EventScroll e) { + // double dir = 0.0; + // if (handle_scroll_event (e, out dir)) { + // handle_change (dir, false); + // } + // } + + // private void on_mic_icon_scroll_event (Gdk.EventScroll e) { + // double dir = 0.0; + // if (handle_scroll_event (e, out dir)) { + // handle_change (dir, true); + // } + // } private void update_mic_visibility () { if (volume_control.is_listening) { @@ -504,61 +504,61 @@ public class Sound.Indicator : Wingpanel.Indicator { * In the case of diagonal scrolling, it ignores the event unless movement in one direction * is more than twice the movement in the other direction. */ - private bool handle_scroll_event (Gdk.EventScroll e, out double dir) { - dir = 0.0; - bool natural_scroll; - var event_source = e.get_source_device ().input_source; - if (event_source == Gdk.InputSource.MOUSE) { - natural_scroll = natural_scroll_mouse; - } else if (event_source == Gdk.InputSource.TOUCHPAD) { - natural_scroll = natural_scroll_touchpad; - } else { - natural_scroll = false; - } - - switch (e.direction) { - case Gdk.ScrollDirection.SMOOTH: - var abs_x = double.max (e.delta_x.abs (), 0.0001); - var abs_y = double.max (e.delta_y.abs (), 0.0001); - - if (abs_y / abs_x > 2.0) { - total_y_delta += e.delta_y; - } else if (abs_x / abs_y > 2.0) { - total_x_delta += e.delta_x; - } - - break; - - case Gdk.ScrollDirection.UP: - total_y_delta = -1.0; - break; - case Gdk.ScrollDirection.DOWN: - total_y_delta = 1.0; - break; - case Gdk.ScrollDirection.LEFT: - total_x_delta = -1.0; - break; - case Gdk.ScrollDirection.RIGHT: - total_x_delta = 1.0; - break; - default: - break; - } - - if (total_y_delta.abs () > 0.5) { - dir = natural_scroll ? total_y_delta : -total_y_delta; - } else if (total_x_delta.abs () > 0.5) { - dir = natural_scroll ? -total_x_delta : total_x_delta; - } - - if (dir.abs () > 0.0) { - total_y_delta = 0.0; - total_x_delta = 0.0; - return true; - } - - return false; - } + // private bool handle_scroll_event (Gdk.EventScroll e, out double dir) { + // dir = 0.0; + // bool natural_scroll; + // var event_source = e.get_source_device ().input_source; + // if (event_source == Gdk.InputSource.MOUSE) { + // natural_scroll = natural_scroll_mouse; + // } else if (event_source == Gdk.InputSource.TOUCHPAD) { + // natural_scroll = natural_scroll_touchpad; + // } else { + // natural_scroll = false; + // } + + // switch (e.direction) { + // case Gdk.ScrollDirection.SMOOTH: + // var abs_x = double.max (e.delta_x.abs (), 0.0001); + // var abs_y = double.max (e.delta_y.abs (), 0.0001); + + // if (abs_y / abs_x > 2.0) { + // total_y_delta += e.delta_y; + // } else if (abs_x / abs_y > 2.0) { + // total_x_delta += e.delta_x; + // } + + // break; + + // case Gdk.ScrollDirection.UP: + // total_y_delta = -1.0; + // break; + // case Gdk.ScrollDirection.DOWN: + // total_y_delta = 1.0; + // break; + // case Gdk.ScrollDirection.LEFT: + // total_x_delta = -1.0; + // break; + // case Gdk.ScrollDirection.RIGHT: + // total_x_delta = 1.0; + // break; + // default: + // break; + // } + + // if (total_y_delta.abs () > 0.5) { + // dir = natural_scroll ? total_y_delta : -total_y_delta; + // } else if (total_x_delta.abs () > 0.5) { + // dir = natural_scroll ? -total_x_delta : total_x_delta; + // } + + // if (dir.abs () > 0.0) { + // total_y_delta = 0.0; + // total_x_delta = 0.0; + // return true; + // } + + // return false; + // } private void handle_change (double change, bool is_mic) { double v; diff --git a/src/Widgets/DeviceItem.vala b/src/Widgets/DeviceItem.vala index 9851f32d..3b1b33f4 100644 --- a/src/Widgets/DeviceItem.vala +++ b/src/Widgets/DeviceItem.vala @@ -12,7 +12,7 @@ public class Sound.Widgets.DeviceItem : Gtk.ListBoxRow { public Gtk.ListBoxRow? row { get; construct; } private bool is_priority; - private Gtk.RadioButton radio_button; + private Gtk.CheckButton radio_button; public DeviceItem (Device device, Gtk.ListBoxRow? row) { Object (device: device, row: row); @@ -37,7 +37,7 @@ public class Sound.Widgets.DeviceItem : Gtk.ListBoxRow { box.add (label); box.add (image); - radio_button = new Gtk.RadioButton (null) { + radio_button = new Gtk.CheckButton (null) { child = box, active = device.is_default, hexpand = true, diff --git a/src/Widgets/DisplayWidget.vala b/src/Widgets/DisplayWidget.vala index 9821d324..ebb170ef 100644 --- a/src/Widgets/DisplayWidget.vala +++ b/src/Widgets/DisplayWidget.vala @@ -23,8 +23,8 @@ public class Sound.DisplayWidget : Gtk.Box { public bool mic_muted { get; set; } public string icon_name { get; set; } - public signal void volume_scroll_event (Gdk.EventScroll e); - public signal void mic_scroll_event (Gdk.EventScroll e); + // public signal void volume_scroll_event (Gdk.EventScroll e); + // public signal void mic_scroll_event (Gdk.EventScroll e); construct { var volume_icon = new Gtk.Image () { @@ -59,12 +59,12 @@ public class Sound.DisplayWidget : Gtk.Box { * entirely clear. Only normal scroll events are received even if the SMOOTH_SCROLL_MASK * is set. */ mic_event_box.scroll_event.connect ((e) => { - mic_scroll_event (e); + // mic_scroll_event (e); return Gdk.EVENT_STOP; }); volume_event_box.scroll_event.connect ((e) => { - volume_scroll_event (e); + // volume_scroll_event (e); return Gdk.EVENT_STOP; }); diff --git a/src/Widgets/Scale.vala b/src/Widgets/Scale.vala index ceb522dd..d92631ca 100644 --- a/src/Widgets/Scale.vala +++ b/src/Widgets/Scale.vala @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -public class Sound.Widgets.Scale : Gtk.EventBox { +public class Sound.Widgets.Scale : Granite.Bin { public signal void slider_dropped (); public Gtk.Adjustment adjustment { get; construct; } From a4f11d34447cac1221209151425ffe03427bf6cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 12 Aug 2025 09:16:27 -0700 Subject: [PATCH 04/24] provider for display --- src/Indicator.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Indicator.vala b/src/Indicator.vala index 2116fad4..4738bf51 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -83,8 +83,8 @@ public class Sound.Indicator : Wingpanel.Indicator { var provider = new Gtk.CssProvider (); provider.load_from_resource ("io/elementary/wingpanel/sound/indicator.css"); - Gtk.StyleContext.add_provider_for_screen ( - Gdk.Screen.get_default (), + Gtk.StyleContext.add_provider_for_display ( + Gdk.Display.get_default (), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION ); From dcbe7c7eabefa7cf07d41a310075ff1ac7c22e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 12 Aug 2025 09:42:10 -0700 Subject: [PATCH 05/24] Get close to able to compile --- src/Indicator.vala | 72 ++++++++++++------------- src/Widgets/DeviceItem.vala | 17 +++--- src/Widgets/DeviceManagerWidget.vala | 7 ++- src/Widgets/DisplayWidget.vala | 42 ++++++--------- src/Widgets/PlayerList.vala | 16 ++---- src/Widgets/PlayerRow.vala | 79 +++++++++++----------------- src/Widgets/Scale.vala | 34 ++++++------ 7 files changed, 111 insertions(+), 156 deletions(-) diff --git a/src/Indicator.vala b/src/Indicator.vala index 4738bf51..518886ee 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -78,7 +78,7 @@ public class Sound.Indicator : Wingpanel.Indicator { // Prevent a race that skips automatic resource loading // https://github.com/elementary/wingpanel-indicator-bluetooth/issues/203 - Gtk.IconTheme.get_default ().add_resource_path ("/org/elementary/wingpanel/icons"); + Gtk.IconTheme.get_for_display (Gdk.Display.get_default ()).add_resource_path ("/org/elementary/wingpanel/icons"); var provider = new Gtk.CssProvider (); provider.load_from_resource ("io/elementary/wingpanel/sound/indicator.css"); @@ -121,8 +121,8 @@ public class Sound.Indicator : Wingpanel.Indicator { display_widget.icon_name = get_volume_icon (volume_control.volume.volume); - display_widget.volume_scroll_event.connect_after (on_volume_icon_scroll_event); - display_widget.mic_scroll_event.connect_after (on_mic_icon_scroll_event); + // display_widget.volume_scroll_event.connect_after (on_volume_icon_scroll_event); + // display_widget.mic_scroll_event.connect_after (on_mic_icon_scroll_event); volume_adjustment = new Gtk.Adjustment (0, 0, max_volume, 0.01, 0, 0); mic_adjustment = new Gtk.Adjustment (0, 0, 1, 0.01, 0, 0); @@ -353,20 +353,14 @@ public class Sound.Indicator : Wingpanel.Indicator { private void update_mic_visibility () { if (volume_control.is_listening) { - mic_scale.no_show_all = false; - mic_scale.show_all (); - mic_separator.no_show_all = false; - mic_separator.show (); - input_device_manager.no_show_all = false; - input_device_manager.show (); + mic_scale.visible = true; + mic_separator.visible = true; + input_device_manager.visible = true; display_widget.show_mic = true; } else { - mic_scale.no_show_all = true; - mic_scale.hide (); - mic_separator.no_show_all = true; - mic_separator.hide (); - input_device_manager.no_show_all = true; - input_device_manager.hide (); + mic_scale.visible = false; + mic_separator.visible = false; + input_device_manager.visible = false; display_widget.show_mic = false; } } @@ -420,24 +414,24 @@ public class Sound.Indicator : Wingpanel.Indicator { update_mic_visibility (); - var settings_button = new Gtk.ModelButton () { + var settings_button = new Wingpanel.PopoverMenuItem () { text = _("Sound Settings…"), margin_top = 3 }; main_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); if (is_in_session) { - main_box.add (mpris); - main_box.add (new Gtk.Separator (Gtk.Orientation.HORIZONTAL)); + main_box.append (mpris); + main_box.append (new Gtk.Separator (Gtk.Orientation.HORIZONTAL)); } - main_box.add (volume_scale); - main_box.add (output_device_manager); + main_box.append (volume_scale); + main_box.append (output_device_manager); if (is_in_session) { - main_box.add (new Gtk.Separator (Gtk.Orientation.HORIZONTAL)); - main_box.add (mic_scale); - main_box.add (input_device_manager); - main_box.add (mic_separator); - main_box.add (settings_button); + main_box.append (new Gtk.Separator (Gtk.Orientation.HORIZONTAL)); + main_box.append (mic_scale); + main_box.append (input_device_manager); + main_box.append (mic_separator); + main_box.append (settings_button); } mic_scale.notify["active"].connect (on_mic_switch_change); @@ -446,14 +440,14 @@ public class Sound.Indicator : Wingpanel.Indicator { volume_control.mic_volume = mic_adjustment.get_value (); }); - mic_scale.scroll_event.connect_after ((e) => { - double dir = 0.0; - if (handle_scroll_event (e, out dir)) { - handle_change (dir, true); - } + // mic_scale.scroll_event.connect_after ((e) => { + // double dir = 0.0; + // if (handle_scroll_event (e, out dir)) { + // handle_change (dir, true); + // } - return true; - }); + // return true; + // }); mpris.close.connect (() => { close (); @@ -471,14 +465,14 @@ public class Sound.Indicator : Wingpanel.Indicator { volume_scale.slider_dropped.connect (play_volume_change_sound); - volume_scale.scroll_event.connect_after ((e) => { - double dir = 0.0; - if (handle_scroll_event (e, out dir)) { - handle_change (dir, false); - } + // volume_scale.scroll_event.connect_after ((e) => { + // double dir = 0.0; + // if (handle_scroll_event (e, out dir)) { + // handle_change (dir, false); + // } - return true; - }); + // return true; + // }); volume_scale.notify["active"].connect (on_volume_switch_change); diff --git a/src/Widgets/DeviceItem.vala b/src/Widgets/DeviceItem.vala index 3b1b33f4..5c21a796 100644 --- a/src/Widgets/DeviceItem.vala +++ b/src/Widgets/DeviceItem.vala @@ -19,7 +19,7 @@ public class Sound.Widgets.DeviceItem : Gtk.ListBoxRow { } class construct { - set_css_name (Gtk.STYLE_CLASS_MENUITEM); + set_css_name ("modelbutton"); } construct { @@ -29,31 +29,30 @@ public class Sound.Widgets.DeviceItem : Gtk.ListBoxRow { ellipsize = MIDDLE }; - var image = new Gtk.Image.from_icon_name (device.icon_name + "-symbolic", MENU) { + var image = new Gtk.Image.from_icon_name (device.icon_name + "-symbolic") { use_fallback = true }; var box = new Gtk.Box (HORIZONTAL, 6); - box.add (label); - box.add (image); + box.append (label); + box.append (image); - radio_button = new Gtk.CheckButton (null) { + radio_button = new Gtk.CheckButton () { child = box, active = device.is_default, hexpand = true, - xalign = 0 + // xalign = 0 }; if (row != null) { var item = (DeviceItem) row; - radio_button.set_group (item.radio_button.get_group ()); + radio_button.set_group (item.radio_button); } child = radio_button; - show_all (); selectable = false; - no_show_all = true; + visible = false; radio_button.toggled.connect (() => { if (radio_button.active) { diff --git a/src/Widgets/DeviceManagerWidget.vala b/src/Widgets/DeviceManagerWidget.vala index 143a7055..0008867a 100644 --- a/src/Widgets/DeviceManagerWidget.vala +++ b/src/Widgets/DeviceManagerWidget.vala @@ -40,7 +40,7 @@ public class Sound.Widgets.DeviceManagerWidget : Gtk.Box { visible = true }; - var scrolled_box = new Gtk.ScrolledWindow (null, null) { + var scrolled_box = new Gtk.ScrolledWindow () { child = device_list, hscrollbar_policy = Gtk.PolicyType.NEVER, propagate_natural_height = true, @@ -52,7 +52,7 @@ public class Sound.Widgets.DeviceManagerWidget : Gtk.Box { child = scrolled_box }; - add (devices_revealer); + append (devices_revealer); update_showable (); } @@ -65,7 +65,7 @@ public class Sound.Widgets.DeviceManagerWidget : Gtk.Box { Gtk.ListBoxRow? row = device_list.get_row_at_index (0); var device_item = new DeviceItem (device, row); - device_list.add (device_item); + device_list.append (device_item); device_item.activated.connect (() => { pam.set_default_device.begin (device); @@ -74,7 +74,6 @@ public class Sound.Widgets.DeviceManagerWidget : Gtk.Box { device.removed.connect (() => { device_list.remove (device_item); - device_list.show_all (); update_showable (); }); diff --git a/src/Widgets/DisplayWidget.vala b/src/Widgets/DisplayWidget.vala index ebb170ef..f42fa7bf 100644 --- a/src/Widgets/DisplayWidget.vala +++ b/src/Widgets/DisplayWidget.vala @@ -31,42 +31,32 @@ public class Sound.DisplayWidget : Gtk.Box { pixel_size = 24 }; - var volume_event_box = new Gtk.EventBox () { - child = volume_icon - }; - volume_event_box.events = SCROLL_MASK | SMOOTH_SCROLL_MASK | BUTTON_PRESS_MASK | BUTTON_RELEASE_MASK; - var mic_icon = new Gtk.Spinner () { margin_end = 18 }; - mic_icon.get_style_context ().add_class ("mic-icon"); - - var mic_event_box = new Gtk.EventBox () { - child = mic_icon - }; - mic_event_box.events = SCROLL_MASK | SMOOTH_SCROLL_MASK | BUTTON_PRESS_MASK | BUTTON_RELEASE_MASK; + mic_icon.add_css_class ("mic-icon"); var mic_revealer = new Gtk.Revealer () { - child = mic_event_box, + child = mic_icon, transition_type = SLIDE_LEFT }; valign = Gtk.Align.CENTER; - add (mic_revealer); - add (volume_event_box); + append (mic_revealer); + append (volume_icon); /* SMOOTH_SCROLL_MASK has no effect on this widget for reasons that are not * entirely clear. Only normal scroll events are received even if the SMOOTH_SCROLL_MASK * is set. */ - mic_event_box.scroll_event.connect ((e) => { - // mic_scroll_event (e); - return Gdk.EVENT_STOP; - }); + // mic_event_box.scroll_event.connect ((e) => { + // mic_scroll_event (e); + // return Gdk.EVENT_STOP; + // }); - volume_event_box.scroll_event.connect ((e) => { - // volume_scroll_event (e); - return Gdk.EVENT_STOP; - }); + // volume_event_box.scroll_event.connect ((e) => { + // volume_scroll_event (e); + // return Gdk.EVENT_STOP; + // }); var mic_gesture_click = new Gtk.GestureClick () { button = Gdk.BUTTON_MIDDLE @@ -77,7 +67,7 @@ public class Sound.DisplayWidget : Gtk.Box { mic_gesture_click.reset (); }); - mic_event_box.add_controller (mic_gesture_click); + mic_icon.add_controller (mic_gesture_click); var volume_gesture_click = new Gtk.GestureClick () { button = Gdk.BUTTON_MIDDLE @@ -88,7 +78,7 @@ public class Sound.DisplayWidget : Gtk.Box { volume_gesture_click.reset (); }); - volume_event_box.add_controller (volume_gesture_click); + volume_icon.add_controller (volume_gesture_click); bind_property ( "icon-name", @@ -105,9 +95,9 @@ public class Sound.DisplayWidget : Gtk.Box { notify["mic-muted"].connect (() => { if (mic_muted) { - mic_icon.get_style_context ().add_class ("disabled"); + mic_icon.add_css_class ("disabled"); } else { - mic_icon.get_style_context ().remove_class ("disabled"); + mic_icon.remove_css_class ("disabled"); } }); } diff --git a/src/Widgets/PlayerList.vala b/src/Widgets/PlayerList.vala index 91d854fb..8450eb52 100644 --- a/src/Widgets/PlayerList.vala +++ b/src/Widgets/PlayerList.vala @@ -44,8 +44,7 @@ public class Sound.Widgets.PlayerList : Gtk.Box { close (); }); - bluetooth_widget.show_all (); - pack_start (bluetooth_widget, false, false, 0); + prepend (bluetooth_widget); }); object_manager.media_player_removed.connect ((media_player) => { @@ -66,7 +65,6 @@ public class Sound.Widgets.PlayerList : Gtk.Box { orientation = Gtk.Orientation.VERTICAL; margin_bottom = 3; - show_all (); } public void update_default_player () { @@ -84,8 +82,7 @@ public class Sound.Widgets.PlayerList : Gtk.Box { close (); }); - default_widget.show_all (); - pack_start (default_widget, false, false, 0); + prepend (default_widget); } } @@ -110,11 +107,9 @@ public class Sound.Widgets.PlayerList : Gtk.Box { default_widget.mpris_name = name; default_widget.client = iface; ifaces.insert (name, default_widget); - default_widget.no_show_all = false; default_widget.visible = true; } else { if (default_widget.mpris_name == "") { - default_widget.no_show_all = true; default_widget.visible = false; } @@ -122,8 +117,8 @@ public class Sound.Widgets.PlayerList : Gtk.Box { widg.close.connect (() => { close (); }); - widg.show_all (); - pack_start (widg, false, false, 0); + + prepend (widg); ifaces.insert (name, widg); } } @@ -146,12 +141,9 @@ public class Sound.Widgets.PlayerList : Gtk.Box { ifaces.remove (name); if (ifaces.length != 0 && default_widget.mpris_name == "") { - default_widget.no_show_all = true; default_widget.visible = false; } else { - default_widget.no_show_all = false; default_widget.visible = true; - show_all (); } } diff --git a/src/Widgets/PlayerRow.vala b/src/Widgets/PlayerRow.vala index 4d7531c4..5f5958f3 100644 --- a/src/Widgets/PlayerRow.vala +++ b/src/Widgets/PlayerRow.vala @@ -60,7 +60,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { var icon = value.get_icon (); if (icon != null) { app_icon = icon; - background.set_from_gicon (app_icon, Gtk.IconSize.DIALOG); + background.gicon = app_icon; } } } @@ -98,7 +98,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { }); } } else { - ((Gtk.Image) play_btn.image).icon_name = "media-playback-start-symbolic"; + play_btn.icon_name = "media-playback-start-symbolic"; prev_btn.sensitive = false; next_btn.sensitive = false; Sound.Indicator.settings.set_strv ( @@ -133,7 +133,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { mp_client = media_player_client; app_icon = new ThemedIcon (icon); - background.set_from_gicon (app_icon, Gtk.IconSize.DIALOG); + background.gicon = app_icon; title_label.label = name; artist_label.label = NOT_PLAYING; @@ -182,17 +182,17 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { }; mask = new Gtk.Image.from_resource ("/io/elementary/wingpanel/sound/image-mask.svg") { - no_show_all = true, + visible = false, pixel_size = 48 }; var overlay = new Gtk.Overlay () { + child = background, can_focus = true, margin_bottom = 2, margin_end = 4, margin_start = 4 }; - overlay.add (background); overlay.add_overlay (mask); title_label = new Gtk.Label (null) { @@ -208,8 +208,8 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { halign = Gtk.Align.START, valign = Gtk.Align.START }; - artist_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); - artist_label.get_style_context ().add_class (Granite.STYLE_CLASS_SMALL_LABEL); + artist_label.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); + artist_label.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); var titles = new Gtk.Grid () { column_spacing = 3 @@ -218,18 +218,13 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { titles.attach (title_label, 1, 0); titles.attach (artist_label, 1, 1); - var titles_events = new Gtk.EventBox () { - hexpand = true - }; - titles_events.add (titles); - prev_btn = new Gtk.Button.from_icon_name ( "media-skip-backward-symbolic" ) { sensitive = false, valign = Gtk.Align.CENTER }; - prev_btn.get_style_context ().add_class ("circular"); + prev_btn.add_css_class (Granite.STYLE_CLASS_CIRCULAR); play_btn = new Gtk.Button.from_icon_name ( "media-playback-start-symbolic" @@ -237,7 +232,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { sensitive = true, valign = Gtk.Align.CENTER }; - play_btn.get_style_context ().add_class ("circular"); + play_btn.add_css_class (Granite.STYLE_CLASS_CIRCULAR); next_btn = new Gtk.Button.from_icon_name ( "media-skip-forward-symbolic" @@ -245,14 +240,14 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { sensitive = false, valign = Gtk.Align.CENTER }; - next_btn.get_style_context ().add_class ("circular"); + next_btn.add_css_class (Granite.STYLE_CLASS_CIRCULAR); spacing = 6; margin_end = 12; - add (titles_events); - add (prev_btn); - add (play_btn); - add (next_btn); + append (titles); + append (prev_btn); + append (play_btn); + append (next_btn); if (client != null) { connect_to_client (); @@ -261,7 +256,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { update_controls (); } - titles_events.button_press_event.connect (raise_player); + // titles_events.button_press_event.connect (raise_player); prev_btn.clicked.connect (() => { Idle.add (() => { @@ -435,9 +430,9 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { */ private void update_play_status () { if (client.player.playback_status == "Playing") { - ((Gtk.Image) play_btn.image).icon_name = "media-playback-pause-symbolic"; + play_btn.icon_name = "media-playback-pause-symbolic"; } else { - ((Gtk.Image) play_btn.image).icon_name = "media-playback-start-symbolic"; + play_btn.icon_name = "media-playback-start-symbolic"; } /** @@ -446,11 +441,9 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { * browsers, but in theory any app could have temporary MPRIS playback. */ if (client.player.playback_status == "Stopped" && app_info == null) { - no_show_all = true; - hide (); + visible = false; } else { - no_show_all = false; - show (); + visible = true; } } @@ -471,12 +464,9 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { * Utility, handle updating the album art */ private void update_art (string uri) { - var scale = get_style_context ().get_scale (); if (!uri.has_prefix ("file://") && !uri.has_prefix ("http")) { background.gicon = app_icon; - background.get_style_context ().set_scale (scale); - mask.no_show_all = true; - mask.hide (); + mask.visible = false; return; } @@ -507,14 +497,13 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { } try { - var pbuf = new Gdk.Pixbuf.from_file_at_size (fname, ICON_SIZE * scale, ICON_SIZE * scale); - background.gicon = mask_pixbuf (pbuf, scale); + var pbuf = new Gdk.Pixbuf.from_file_at_size (fname, ICON_SIZE * scale_factor, ICON_SIZE * scale_factor); + background.gicon = mask_pixbuf (pbuf, scale_factor); background.get_style_context ().set_scale (1); - mask.no_show_all = false; - mask.show (); + mask.visible = true; } catch (Error e) { warning (e.message); - //background.set_from_gicon (app_icon, Gtk.IconSize.DIALOG); + //background.set_from_gicon (app_icon); } } else { load_remote_art_cancel.cancel (); @@ -524,22 +513,19 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { } private async void load_remote_art (string uri) { - var scale = get_style_context ().get_scale (); GLib.File file = GLib.File.new_for_uri (uri); try { GLib.InputStream stream = yield file.read_async (Priority.DEFAULT, load_remote_art_cancel); Gdk.Pixbuf pixbuf = yield new Gdk.Pixbuf.from_stream_async (stream, load_remote_art_cancel); if (pixbuf != null) { - background.gicon = mask_pixbuf (pixbuf, scale); + background.gicon = mask_pixbuf (pixbuf, scale_factor); background.get_style_context ().set_scale (1); - mask.no_show_all = false; - mask.show (); + mask.visible = true; } } catch (Error e) { background.gicon = app_icon; - background.get_style_context ().set_scale (scale); - mask.no_show_all = true; - mask.hide (); + background.get_style_context ().set_scale (scale_factor); + mask.visible = false; } } @@ -557,9 +543,8 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { } else { last_art_url = ""; background.pixel_size = ICON_SIZE; - background.set_from_gicon (app_icon, Gtk.IconSize.DIALOG); - mask.no_show_all = true; - mask.hide (); + background.gicon = app_icon; + mask.visible = false; } string title; @@ -610,11 +595,11 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { if (playing != "") { switch (playing) { case "playing": - ((Gtk.Image) play_btn.image).icon_name = "media-playback-pause-symbolic"; + play_btn.icon_name = "media-playback-pause-symbolic"; break; default: /* Stopped, Paused */ - ((Gtk.Image) play_btn.image).icon_name = "media-playback-start-symbolic"; + play_btn.icon_name = "media-playback-start-symbolic"; break; } } diff --git a/src/Widgets/Scale.vala b/src/Widgets/Scale.vala index d92631ca..72e22551 100644 --- a/src/Widgets/Scale.vala +++ b/src/Widgets/Scale.vala @@ -28,14 +28,11 @@ public class Sound.Widgets.Scale : Granite.Bin { } class construct { - set_css_name (Gtk.STYLE_CLASS_MENUITEM); + set_css_name ("modelbutton"); } construct { - var image = new Gtk.Image (); - var toggle = new Gtk.ToggleButton (); - toggle.image = image; var scale_widget = new Gtk.Scale (HORIZONTAL, adjustment) { draw_value = false, @@ -50,25 +47,24 @@ public class Sound.Widgets.Scale : Granite.Bin { margin_bottom = 6, margin_end = 12 }; - box.add (toggle); - box.add (scale_widget); + box.append (toggle); + box.append (scale_widget); - add (box); - add_events (Gdk.EventMask.SMOOTH_SCROLL_MASK); - above_child = false; + child = box; + // above_child = false; - scale_widget.button_release_event.connect (() => { - slider_dropped (); - return Gdk.EVENT_PROPAGATE; - }); + // scale_widget.button_release_event.connect (() => { + // slider_dropped (); + // return Gdk.EVENT_PROPAGATE; + // }); - scale_widget.scroll_event.connect ((e) => { - /* Re-emit the signal on the eventbox instead of using native handler */ - scroll_event (e); - return Gdk.EVENT_STOP; - }); + // scale_widget.scroll_event.connect ((e) => { + // /* Re-emit the signal on the eventbox instead of using native handler */ + // scroll_event (e); + // return Gdk.EVENT_STOP; + // }); - bind_property ("icon", image, "icon-name"); + bind_property ("icon", toggle, "icon-name"); bind_property ("active", scale_widget, "sensitive", BindingFlags.SYNC_CREATE); bind_property ("active", toggle, "active", BIDIRECTIONAL | SYNC_CREATE); From ef674952bfd420305e004e4f2ba9b79884e1a520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 11 Mar 2026 09:53:45 -0700 Subject: [PATCH 06/24] Fix bad merge --- src/Widgets/PlayerRow.vala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Widgets/PlayerRow.vala b/src/Widgets/PlayerRow.vala index 4aab7939..aa26867e 100644 --- a/src/Widgets/PlayerRow.vala +++ b/src/Widgets/PlayerRow.vala @@ -175,7 +175,6 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { }; var overlay = new Gtk.Overlay () { - child = background, can_focus = true, child = background, margin_bottom = 2, From 6fa8af106d973f92969f1f53fda0af6f2a3f414e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 11 Mar 2026 09:58:24 -0700 Subject: [PATCH 07/24] CanberraGtk4 --- meson.build | 3 ++ src/CanberraGtk4.vala | 78 ++++++++++++++++++++++++++++++++++++++ src/Indicator.vala | 2 +- vapi/libcanberra-gtk3.deps | 2 - vapi/libcanberra-gtk3.vapi | 37 ------------------ 5 files changed, 82 insertions(+), 40 deletions(-) create mode 100644 src/CanberraGtk4.vala delete mode 100644 vapi/libcanberra-gtk3.deps delete mode 100644 vapi/libcanberra-gtk3.vapi diff --git a/meson.build b/meson.build index e41c265c..91e0aee0 100644 --- a/meson.build +++ b/meson.build @@ -43,6 +43,7 @@ config_file = configure_file( shared_module( meson.project_name(), config_file, + 'src/CanberraGtk4.vala', 'src/Device.vala', 'src/Indicator.vala', 'src/Widgets/DisplayWidget.vala', @@ -65,6 +66,8 @@ shared_module( dependency('gobject-2.0'), dependency('granite-7', version: '>=6.0.0'), dependency('gtk4'), + dependency('gtk4-wayland'), + dependency('gtk4-x11'), dependency('libpulse'), dependency('libpulse-mainloop-glib'), dependency('libnotify'), diff --git a/src/CanberraGtk4.vala b/src/CanberraGtk4.vala new file mode 100644 index 00000000..72633a9d --- /dev/null +++ b/src/CanberraGtk4.vala @@ -0,0 +1,78 @@ +/* + * Copyright 2022 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +/* code adapted from libcanberra */ + +namespace CanberraGtk4 { + private Canberra.Context? context = null; + + public unowned Canberra.Context? context_get () { + Canberra.Proplist proplist; + + if (context != null) { + return context; + } if (Canberra.Context.create (out context) != Canberra.SUCCESS) { + return null; + } if (Canberra.Proplist.create (out proplist) != Canberra.SUCCESS) { + return null; + } + + proplist.sets (Canberra.PROP_CANBERRA_XDG_THEME_NAME, Gtk.Settings.get_default ().gtk_sound_theme_name); + + unowned var name = GLib.Environment.get_application_name (); + if (name != null) { + proplist.sets (Canberra.PROP_APPLICATION_NAME, name); + } else { + proplist.sets (Canberra.PROP_APPLICATION_NAME, "libcanberra-gtk"); + proplist.sets (Canberra.PROP_APPLICATION_VERSION, "%i.%i".printf (Canberra.MAJOR, Canberra.MINOR)); + proplist.sets (Canberra.PROP_APPLICATION_ID, "org.freedesktop.libcanberra.gtk"); + } + + unowned var icon = Gtk.Window.get_default_icon_name (); + if (icon != null) { + proplist.sets (Canberra.PROP_APPLICATION_ICON_NAME, icon); + } + + unowned var display = Gdk.Display.get_default (); + if (display is Gdk.X11.Display) { + unowned var display_name = display.get_name (); + if (display_name != null) { + proplist.sets (Canberra.PROP_WINDOW_X11_SCREEN, display_name); + } + + var screen = "%i".printf (((Gdk.X11.Display) display).get_screen ().get_screen_number ()); + proplist.sets (Canberra.PROP_WINDOW_X11_SCREEN, screen); + } + + context.change_props_full (proplist); + + var val = Value (typeof (string)); + if (display.get_setting ("gtk-sound-theme-name", val)) { + context.change_props (Canberra.PROP_CANBERRA_XDG_THEME_NAME, val.get_string ()); + } + + val = Value (typeof (bool)); + if (display.get_setting ("gtk-enable-event-sounds", val)) { + unowned var env = GLib.Environment.get_variable ("CANBERRA_FORCE_EVENT_SOUNDS"); + context.change_props (Canberra.PROP_CANBERRA_ENABLE, env != null ? true : val.get_boolean ()); + } + + display.setting_changed.connect ((setting) => { + Value new_val; + if (setting == "gtk-sound-theme-name") { + new_val = Value (typeof (string)); + display.get_setting ("gtk-sound-theme-name", new_val); + context.change_props (Canberra.PROP_CANBERRA_ENABLE, new_val.get_string ()); + } else if (setting == "gtk-enable-event-sounds") { + new_val = Value (typeof (bool)); + unowned var env = GLib.Environment.get_variable ("CANBERRA_FORCE_EVENT_SOUNDS"); + display.get_setting ("gtk-enable-event-sounds", new_val); + context.change_props (Canberra.PROP_CANBERRA_ENABLE, env != null ? true : new_val.get_boolean ()); + } + }); + + return context; + } +} diff --git a/src/Indicator.vala b/src/Indicator.vala index d316f37c..0280dedc 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -129,7 +129,7 @@ public class Sound.Indicator : Wingpanel.Indicator { mic_scale = new Widgets.Scale (mic_adjustment); - ca_context = CanberraGtk.context_get (); + ca_context = CanberraGtk4.context_get (); ca_context.change_props (Canberra.PROP_APPLICATION_NAME, "indicator-sound", Canberra.PROP_APPLICATION_ID, "wingpanel-indicator-sound", Canberra.PROP_APPLICATION_NAME, "start-here", diff --git a/vapi/libcanberra-gtk3.deps b/vapi/libcanberra-gtk3.deps deleted file mode 100644 index 7bd6beca..00000000 --- a/vapi/libcanberra-gtk3.deps +++ /dev/null @@ -1,2 +0,0 @@ -libcanberra -gtk+-3.0 diff --git a/vapi/libcanberra-gtk3.vapi b/vapi/libcanberra-gtk3.vapi deleted file mode 100644 index f788f8e0..00000000 --- a/vapi/libcanberra-gtk3.vapi +++ /dev/null @@ -1,37 +0,0 @@ -/*** - This file is part of libcanberra. - - Copyright 2009 Lennart Poettering - - libcanberra is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, either version 2.1 of the - License, or (at your option) any later version. - - libcanberra is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with libcanberra. If not, see - . -***/ - -using Canberra; -using Gdk; -using Gtk; - -[CCode (cprefix = "CA_GTK_", lower_case_cprefix = "ca_gtk_", cheader_filename = "canberra-gtk.h")] -namespace CanberraGtk { - - public unowned Context? context_get(); - public unowned Context? context_get_for_screen(Gdk.Screen? screen); - - public int proplist_set_for_widget(Proplist p, Gtk.Widget w); - public int play_for_widget(Gtk.Widget w, uint32 id, ...); - public int proplist_set_for_event(Proplist p, Gdk.Event e); - public int play_for_event(Gdk.Event e, uint32 id, ...); - - public void widget_disable_sounds(Gtk.Widget w, bool enable = false); -} From d7f25e5aeeb71303c56a27b9bd46579d6ec5bc87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 11 Mar 2026 10:00:12 -0700 Subject: [PATCH 08/24] Bump to wingpanel 9 --- .github/workflows/main.yml | 2 +- README.md | 2 +- meson.build | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index db247591..bd55baff 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: - name: Install Dependencies run: | apt update - apt install -y libcanberra-gtk3-dev libgranite-dev libglib2.0-dev libgtk-3-dev libnotify-dev libpulse-dev libwingpanel-dev libxml2-utils meson valac + apt install -y libcanberra-gtk4-dev libgranite-7-dev libglib2.0-dev libgtk-4-dev libnotify-dev libpulse-dev libwingpanel-9-dev libxml2-utils meson valac - name: Build env: DESTDIR: out diff --git a/README.md b/README.md index 221f9071..6f0e7b34 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ You'll need the following dependencies: libgtk-4-dev libnotify-dev libpulse-dev - libwingpanel-8-dev + libwingpanel-9-dev meson (>= 0.57.0) valac (>= 0.26) diff --git a/meson.build b/meson.build index 91e0aee0..56857fe0 100644 --- a/meson.build +++ b/meson.build @@ -28,7 +28,7 @@ gresource = gnome.compile_resources( source_dir: 'data' ) -wingpanel_dep = dependency('wingpanel-8', version: '>=2.1.0') +wingpanel_dep = dependency('wingpanel-9', version: '>=2.1.0') wingpanel_indicatorsdir = wingpanel_dep.get_pkgconfig_variable('indicatorsdir', define_variable: ['libdir', libdir]) config_data = configuration_data() From 12b46822269b1236d7fc51651b66a9e4dbc26b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 17 Mar 2026 13:20:20 -0700 Subject: [PATCH 09/24] Scroll controllers --- src/Indicator.vala | 183 ++++++++++++++++++--------------- src/Widgets/DisplayWidget.vala | 38 ++++--- src/Widgets/PlayerRow.vala | 11 +- 3 files changed, 127 insertions(+), 105 deletions(-) diff --git a/src/Indicator.vala b/src/Indicator.vala index 0280dedc..0dc0239a 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -119,8 +119,8 @@ public class Sound.Indicator : Wingpanel.Indicator { display_widget.icon_name = get_volume_icon (volume_control.volume.volume); - // display_widget.volume_scroll_event.connect_after (on_volume_icon_scroll_event); - // display_widget.mic_scroll_event.connect_after (on_mic_icon_scroll_event); + display_widget.volume_scroll_event.connect_after (on_volume_icon_scroll_event); + display_widget.mic_scroll_event.connect_after (on_mic_icon_scroll_event); volume_adjustment = new Gtk.Adjustment (0, 0, max_volume, 0.01, 0, 0); mic_adjustment = new Gtk.Adjustment (0, 0, 1, 0.01, 0, 0); @@ -328,19 +328,19 @@ public class Sound.Indicator : Wingpanel.Indicator { display_widget.icon_name = get_volume_icon (volume_control.volume.volume); } - // private void on_volume_icon_scroll_event (Gdk.EventScroll e) { - // double dir = 0.0; - // if (handle_scroll_event (e, out dir)) { - // handle_change (dir, false); - // } - // } + private void on_volume_icon_scroll_event (Gdk.ScrollEvent e) { + double dir = 0.0; + if (handle_scroll_event (e, out dir)) { + handle_change (dir, false); + } + } - // private void on_mic_icon_scroll_event (Gdk.EventScroll e) { - // double dir = 0.0; - // if (handle_scroll_event (e, out dir)) { - // handle_change (dir, true); - // } - // } + private void on_mic_icon_scroll_event (Gdk.ScrollEvent e) { + double dir = 0.0; + if (handle_scroll_event (e, out dir)) { + handle_change (dir, true); + } + } private void update_mic_visibility () { if (volume_control.is_listening) { @@ -431,14 +431,21 @@ public class Sound.Indicator : Wingpanel.Indicator { volume_control.mic_volume = mic_adjustment.get_value (); }); - // mic_scale.scroll_event.connect_after ((e) => { - // double dir = 0.0; - // if (handle_scroll_event (e, out dir)) { - // handle_change (dir, true); - // } + var mic_scroll_controller = new Gtk.EventControllerLegacy (); + mic_scroll_controller.event.connect_after ((e) => { + if (e.get_event_type () != Gdk.EventType.SCROLL) { + return Gdk.EVENT_PROPAGATE; + } + + double dir = 0.0; + if (handle_scroll_event ((Gdk.ScrollEvent) e, out dir)) { + handle_change (dir, true); + } + + return Gdk.EVENT_STOP; + }); - // return true; - // }); + mic_scale.add_controller (mic_scroll_controller); mpris.close.connect (() => { close (); @@ -456,14 +463,21 @@ public class Sound.Indicator : Wingpanel.Indicator { volume_scale.slider_dropped.connect (play_volume_change_sound); - // volume_scale.scroll_event.connect_after ((e) => { - // double dir = 0.0; - // if (handle_scroll_event (e, out dir)) { - // handle_change (dir, false); - // } + var volume_scroll_controller = new Gtk.EventControllerLegacy (); + volume_scroll_controller.event.connect_after ((e) => { + if (e.get_event_type () != Gdk.EventType.SCROLL) { + return Gdk.EVENT_PROPAGATE; + } + + double dir = 0.0; + if (handle_scroll_event ((Gdk.ScrollEvent) e, out dir)) { + handle_change (dir, false); + } + + return Gdk.EVENT_STOP; + }); - // return true; - // }); + volume_scale.add_controller (volume_scroll_controller); volume_scale.notify["active"].connect (on_volume_switch_change); @@ -489,61 +503,64 @@ public class Sound.Indicator : Wingpanel.Indicator { * In the case of diagonal scrolling, it ignores the event unless movement in one direction * is more than twice the movement in the other direction. */ - // private bool handle_scroll_event (Gdk.EventScroll e, out double dir) { - // dir = 0.0; - // bool natural_scroll; - // var event_source = e.get_source_device ().input_source; - // if (event_source == Gdk.InputSource.MOUSE) { - // natural_scroll = natural_scroll_mouse; - // } else if (event_source == Gdk.InputSource.TOUCHPAD) { - // natural_scroll = natural_scroll_touchpad; - // } else { - // natural_scroll = false; - // } - - // switch (e.direction) { - // case Gdk.ScrollDirection.SMOOTH: - // var abs_x = double.max (e.delta_x.abs (), 0.0001); - // var abs_y = double.max (e.delta_y.abs (), 0.0001); - - // if (abs_y / abs_x > 2.0) { - // total_y_delta += e.delta_y; - // } else if (abs_x / abs_y > 2.0) { - // total_x_delta += e.delta_x; - // } - - // break; - - // case Gdk.ScrollDirection.UP: - // total_y_delta = -1.0; - // break; - // case Gdk.ScrollDirection.DOWN: - // total_y_delta = 1.0; - // break; - // case Gdk.ScrollDirection.LEFT: - // total_x_delta = -1.0; - // break; - // case Gdk.ScrollDirection.RIGHT: - // total_x_delta = 1.0; - // break; - // default: - // break; - // } - - // if (total_y_delta.abs () > 0.5) { - // dir = natural_scroll ? total_y_delta : -total_y_delta; - // } else if (total_x_delta.abs () > 0.5) { - // dir = natural_scroll ? -total_x_delta : total_x_delta; - // } - - // if (dir.abs () > 0.0) { - // total_y_delta = 0.0; - // total_x_delta = 0.0; - // return true; - // } - - // return false; - // } + private bool handle_scroll_event (Gdk.ScrollEvent e, out double dir) { + dir = 0.0; + bool natural_scroll; + var event_source = e.get_device ().get_source (); + + if (event_source == Gdk.InputSource.MOUSE) { + natural_scroll = natural_scroll_mouse; + } else if (event_source == Gdk.InputSource.TOUCHPAD) { + natural_scroll = natural_scroll_touchpad; + } else { + natural_scroll = false; + } + + switch (e.get_direction ()) { + case Gdk.ScrollDirection.SMOOTH: + double dx, dy; + e.get_deltas (out dx, out dy); + + var abs_x = double.max (dx.abs (), 0.0001); + var abs_y = double.max (dy.abs (), 0.0001); + + if (abs_y / abs_x > 2.0) { + total_y_delta += dy; + } else if (abs_x / abs_y > 2.0) { + total_x_delta += dx; + } + + break; + case Gdk.ScrollDirection.UP: + total_y_delta = -1.0; + break; + case Gdk.ScrollDirection.DOWN: + total_y_delta = 1.0; + break; + case Gdk.ScrollDirection.LEFT: + total_x_delta = -1.0; + break; + case Gdk.ScrollDirection.RIGHT: + total_x_delta = 1.0; + break; + default: + break; + } + + if (total_y_delta.abs () > 0.5) { + dir = natural_scroll ? total_y_delta : -total_y_delta; + } else if (total_x_delta.abs () > 0.5) { + dir = natural_scroll ? -total_x_delta : total_x_delta; + } + + if (dir.abs () > 0.0) { + total_y_delta = 0.0; + total_x_delta = 0.0; + return true; + } + + return false; + } private void handle_change (double change, bool is_mic) { double v; diff --git a/src/Widgets/DisplayWidget.vala b/src/Widgets/DisplayWidget.vala index 80a747f6..67815bb7 100644 --- a/src/Widgets/DisplayWidget.vala +++ b/src/Widgets/DisplayWidget.vala @@ -23,8 +23,8 @@ public class Sound.DisplayWidget : Gtk.Box { public bool mic_muted { get; set; } public string icon_name { get; set; } - // public signal void volume_scroll_event (Gdk.EventScroll e); - // public signal void mic_scroll_event (Gdk.EventScroll e); + public signal void volume_scroll_event (Gdk.ScrollEvent e); + public signal void mic_scroll_event (Gdk.ScrollEvent e); construct { var volume_icon = new Gtk.Image () { @@ -44,18 +44,28 @@ public class Sound.DisplayWidget : Gtk.Box { append (mic_revealer); append (volume_icon); - /* SMOOTH_SCROLL_MASK has no effect on this widget for reasons that are not - * entirely clear. Only normal scroll events are received even if the SMOOTH_SCROLL_MASK - * is set. */ - // mic_event_box.scroll_event.connect ((e) => { - // mic_scroll_event (e); - // return Gdk.EVENT_STOP; - // }); - - // volume_event_box.scroll_event.connect ((e) => { - // volume_scroll_event (e); - // return Gdk.EVENT_STOP; - // }); + var mic_scroll_controller = new Gtk.EventControllerLegacy (); + mic_scroll_controller.event.connect ((e) => { + if (e.get_event_type () != Gdk.EventType.SCROLL) { + return Gdk.EVENT_PROPAGATE; + } + + mic_scroll_event ((Gdk.ScrollEvent) e); + return Gdk.EVENT_STOP; + }); + + var volume_scroll_controller = new Gtk.EventControllerLegacy (); + volume_scroll_controller.event.connect ((e) => { + if (e.get_event_type () != Gdk.EventType.SCROLL) { + return Gdk.EVENT_PROPAGATE; + } + + volume_scroll_event ((Gdk.ScrollEvent) e); + return Gdk.EVENT_STOP; + }); + + mic_icon.add_controller (mic_scroll_controller); + volume_icon.add_controller (volume_scroll_controller); var mic_gesture_click = new Gtk.GestureClick () { button = Gdk.BUTTON_MIDDLE diff --git a/src/Widgets/PlayerRow.vala b/src/Widgets/PlayerRow.vala index aa26867e..76181e64 100644 --- a/src/Widgets/PlayerRow.vala +++ b/src/Widgets/PlayerRow.vala @@ -484,14 +484,9 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { } } - try { - background.gicon = new FileIcon (File.new_for_path (fname)); - background.get_style_context ().set_scale (1); - mask.visible = true; - } catch (Error e) { - warning (e.message); - //background.gicon = app_icon; - } + background.gicon = new FileIcon (File.new_for_path (fname)); + background.get_style_context ().set_scale (1); + mask.visible = true; } else { load_remote_art_cancel.cancel (); load_remote_art_cancel.reset (); From 8d6786186db06fe5c27ceae0cfe908d288bbe71b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 17 Mar 2026 13:35:12 -0700 Subject: [PATCH 10/24] More scroll controller --- src/Indicator.vala | 26 ++++---------------------- src/Widgets/Scale.vala | 17 ++++++++++++----- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/src/Indicator.vala b/src/Indicator.vala index 0dc0239a..d9fbf4ff 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -431,22 +431,13 @@ public class Sound.Indicator : Wingpanel.Indicator { volume_control.mic_volume = mic_adjustment.get_value (); }); - var mic_scroll_controller = new Gtk.EventControllerLegacy (); - mic_scroll_controller.event.connect_after ((e) => { - if (e.get_event_type () != Gdk.EventType.SCROLL) { - return Gdk.EVENT_PROPAGATE; - } - + mic_scale.scroll_event.connect_after ((e) => { double dir = 0.0; - if (handle_scroll_event ((Gdk.ScrollEvent) e, out dir)) { + if (handle_scroll_event (e, out dir)) { handle_change (dir, true); } - - return Gdk.EVENT_STOP; }); - mic_scale.add_controller (mic_scroll_controller); - mpris.close.connect (() => { close (); }); @@ -463,22 +454,13 @@ public class Sound.Indicator : Wingpanel.Indicator { volume_scale.slider_dropped.connect (play_volume_change_sound); - var volume_scroll_controller = new Gtk.EventControllerLegacy (); - volume_scroll_controller.event.connect_after ((e) => { - if (e.get_event_type () != Gdk.EventType.SCROLL) { - return Gdk.EVENT_PROPAGATE; - } - + volume_scale.scroll_event.connect_after ((e) => { double dir = 0.0; - if (handle_scroll_event ((Gdk.ScrollEvent) e, out dir)) { + if (handle_scroll_event (e, out dir)) { handle_change (dir, false); } - - return Gdk.EVENT_STOP; }); - volume_scale.add_controller (volume_scroll_controller); - volume_scale.notify["active"].connect (on_volume_switch_change); volume_adjustment.value_changed.connect (() => { diff --git a/src/Widgets/Scale.vala b/src/Widgets/Scale.vala index ca71eb94..f3259128 100644 --- a/src/Widgets/Scale.vala +++ b/src/Widgets/Scale.vala @@ -4,6 +4,7 @@ */ public class Sound.Widgets.Scale : Granite.Bin { + public signal void scroll_event (Gdk.ScrollEvent e); public signal void slider_dropped (); public Gtk.Adjustment adjustment { get; construct; } @@ -45,13 +46,19 @@ public class Sound.Widgets.Scale : Granite.Bin { slider_dropped (); }); - // scale_widget.scroll_event.connect ((e) => { - // /* Re-emit the signal on the eventbox instead of using native handler */ - // scroll_event (e); - // return Gdk.EVENT_STOP; - // }); + var scroll_controller = new Gtk.EventControllerLegacy (); + scroll_controller.event.connect_after ((e) => { + if (e.get_event_type () != Gdk.EventType.SCROLL) { + return Gdk.EVENT_PROPAGATE; + } + + scroll_event ((Gdk.ScrollEvent) e); + + return Gdk.EVENT_STOP; + }); scale_widget.add_controller (gesture_click); + scale_widget.add_controller (scroll_controller); bind_property ("icon", toggle, "icon-name"); From 1a95639df893462cc3175e7ba7bd2d06ff7ce350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Thu, 19 Mar 2026 08:00:47 -0700 Subject: [PATCH 11/24] Update style classes --- README.md | 2 +- meson.build | 2 +- src/Widgets/PlayerRow.vala | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6f0e7b34..1b0fb41c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ You'll need the following dependencies: libcanberra-gtk-dev libcanberra-gtk4-dev - libgranite-7-dev + libgranite-7-dev > 7.7.0 libglib2.0-dev libgtk-4-dev libnotify-dev diff --git a/meson.build b/meson.build index 56857fe0..44269b5e 100644 --- a/meson.build +++ b/meson.build @@ -64,7 +64,7 @@ shared_module( dependency('glib-2.0'), dependency('gio-2.0'), dependency('gobject-2.0'), - dependency('granite-7', version: '>=6.0.0'), + dependency('granite-7', version: '>=7.7.0'), dependency('gtk4'), dependency('gtk4-wayland'), dependency('gtk4-x11'), diff --git a/src/Widgets/PlayerRow.vala b/src/Widgets/PlayerRow.vala index a942345b..cb0bcd9b 100644 --- a/src/Widgets/PlayerRow.vala +++ b/src/Widgets/PlayerRow.vala @@ -196,8 +196,8 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { halign = START, valign = START }; - artist_label.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); - artist_label.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); + artist_label.add_css_class (Granite.CssClass.DIM); + artist_label.add_css_class (Granite.CssClass.SMALL); var titles = new Gtk.Grid () { column_spacing = 3 @@ -212,7 +212,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { sensitive = false, valign = CENTER }; - prev_btn.add_css_class (Granite.STYLE_CLASS_CIRCULAR); + prev_btn.add_css_class (Granite.CssClass.CIRCULAR); play_btn = new Gtk.Button.from_icon_name ( "media-playback-start-symbolic" @@ -220,7 +220,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { sensitive = true, valign = CENTER }; - play_btn.add_css_class (Granite.STYLE_CLASS_CIRCULAR); + play_btn.add_css_class (Granite.CssClass.CIRCULAR); next_btn = new Gtk.Button.from_icon_name ( "media-skip-forward-symbolic" @@ -228,7 +228,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { sensitive = false, valign = CENTER }; - next_btn.add_css_class (Granite.STYLE_CLASS_CIRCULAR); + next_btn.add_css_class (Granite.CssClass.CIRCULAR); spacing = 6; margin_end = 12; From 337ebda35858e9ef5db941af3086071538c125d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Thu, 19 Mar 2026 08:04:21 -0700 Subject: [PATCH 12/24] Remove image mask --- data/gresource.xml | 1 - data/image-mask.svg | 235 ------------------------------------- src/Widgets/PlayerRow.vala | 27 +---- 3 files changed, 6 insertions(+), 257 deletions(-) delete mode 100644 data/image-mask.svg diff --git a/data/gresource.xml b/data/gresource.xml index 085054da..7ac75b32 100644 --- a/data/gresource.xml +++ b/data/gresource.xml @@ -1,7 +1,6 @@ - image-mask.svg indicator.css diff --git a/data/image-mask.svg b/data/image-mask.svg deleted file mode 100644 index 2209a4b6..00000000 --- a/data/image-mask.svg +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/src/Widgets/PlayerRow.vala b/src/Widgets/PlayerRow.vala index cb0bcd9b..1443413a 100644 --- a/src/Widgets/PlayerRow.vala +++ b/src/Widgets/PlayerRow.vala @@ -17,8 +17,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { public signal void close (); - private Gtk.Image? background = null; - private Gtk.Image mask; + private Gtk.Image background; private Gtk.Label title_label; private Gtk.Label artist_label; private Gtk.Button prev_btn; @@ -169,20 +168,6 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { pixel_size = ICON_SIZE }; - mask = new Gtk.Image.from_resource ("/io/elementary/wingpanel/sound/image-mask.svg") { - visible = false, - pixel_size = 48 - }; - - var overlay = new Gtk.Overlay () { - can_focus = true, - child = background, - margin_bottom = 2, - margin_end = 4, - margin_start = 4 - }; - overlay.add_overlay (mask); - title_label = new Gtk.Label (null) { ellipsize = END, max_width_chars = 16, @@ -202,7 +187,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { var titles = new Gtk.Grid () { column_spacing = 3 }; - titles.attach (overlay, 0, 0, 1, 2); + titles.attach (background, 0, 0, 1, 2); titles.attach (title_label, 1, 0); titles.attach (artist_label, 1, 1); @@ -492,7 +477,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { background.gicon = new FileIcon (File.new_for_path (fname)); background.get_style_context ().set_scale (1); - mask.visible = true; + background.add_css_class (Granite.CssClass.CARD); } else { load_remote_art_cancel.cancel (); load_remote_art_cancel.reset (); @@ -508,12 +493,12 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { if (pixbuf != null) { background.gicon = pixbuf; background.get_style_context ().set_scale (1); - mask.visible = true; + background.add_css_class (Granite.CssClass.CARD); } } catch (Error e) { background.gicon = app_icon; background.get_style_context ().set_scale (scale_factor); - mask.visible = false; + background.remove_css_class (Granite.CssClass.CARD); } } @@ -532,7 +517,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { last_art_url = ""; background.pixel_size = ICON_SIZE; background.gicon = app_icon; - mask.visible = false; + background.remove_css_class (Granite.CssClass.CARD); } string title; From 35df3aee8a0776e43b4da2091860f0c1c6afa0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Thu, 19 Mar 2026 12:18:59 -0700 Subject: [PATCH 13/24] Remove extra destroys --- src/Widgets/PlayerList.vala | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Widgets/PlayerList.vala b/src/Widgets/PlayerList.vala index 7aa28ce4..1ccfd677 100644 --- a/src/Widgets/PlayerList.vala +++ b/src/Widgets/PlayerList.vala @@ -57,7 +57,6 @@ public class Sound.Widgets.PlayerList : Granite.Bin { object_manager.media_player_removed.connect ((media_player) => { debug ("Media player %s removed", media_player.name); listbox.remove (bluetooth_widget); - bluetooth_widget.destroy (); }); object_manager.media_player_status_changed.connect ((status, title, artist) => { @@ -79,7 +78,6 @@ public class Sound.Widgets.PlayerList : Granite.Bin { if (default_widget != null) { listbox.remove (default_widget); - default_widget.destroy (); } default_widget = new PlayerRow.default (new_player); @@ -141,7 +139,6 @@ public class Sound.Widgets.PlayerList : Granite.Bin { var widg = ifaces[name]; if (widg != null) { listbox.remove (widg); - widg.destroy (); } } From bebde74502ed465aa43541eca4b033ccf33e6a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 14 Apr 2026 15:37:06 -0700 Subject: [PATCH 14/24] Fix device list hexpand --- src/Widgets/DeviceItem.vala | 3 +-- src/Widgets/DeviceManagerWidget.vala | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Widgets/DeviceItem.vala b/src/Widgets/DeviceItem.vala index 5c21a796..1d31faea 100644 --- a/src/Widgets/DeviceItem.vala +++ b/src/Widgets/DeviceItem.vala @@ -40,8 +40,7 @@ public class Sound.Widgets.DeviceItem : Gtk.ListBoxRow { radio_button = new Gtk.CheckButton () { child = box, active = device.is_default, - hexpand = true, - // xalign = 0 + hexpand = true }; if (row != null) { diff --git a/src/Widgets/DeviceManagerWidget.vala b/src/Widgets/DeviceManagerWidget.vala index 0008867a..011240af 100644 --- a/src/Widgets/DeviceManagerWidget.vala +++ b/src/Widgets/DeviceManagerWidget.vala @@ -37,6 +37,7 @@ public class Sound.Widgets.DeviceManagerWidget : Gtk.Box { device_list = new Gtk.ListBox () { activate_on_single_click = true, + hexpand = true, visible = true }; From ccbbfedbe4829ba74bce2b1db2d0887cbd4d0927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 14 Apr 2026 15:43:15 -0700 Subject: [PATCH 15/24] remove unused canberragtk dep --- meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/meson.build b/meson.build index 44269b5e..1d395461 100644 --- a/meson.build +++ b/meson.build @@ -72,7 +72,6 @@ shared_module( dependency('libpulse-mainloop-glib'), dependency('libnotify'), dependency('libcanberra'), - # dependency('libcanberra-gtk4'), meson.get_compiler('vala').find_library('libpulse-ext', dirs: join_paths(meson.source_root(), 'vapi')), wingpanel_dep ], From 0f1615c784a3e4a96c729da2231b3540198b2897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 14 Apr 2026 16:01:32 -0700 Subject: [PATCH 16/24] Remove canberragtk4 dep --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bd55baff..fc987bca 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: - name: Install Dependencies run: | apt update - apt install -y libcanberra-gtk4-dev libgranite-7-dev libglib2.0-dev libgtk-4-dev libnotify-dev libpulse-dev libwingpanel-9-dev libxml2-utils meson valac + apt install -y libgranite-7-dev libglib2.0-dev libgtk-4-dev libnotify-dev libpulse-dev libwingpanel-9-dev libxml2-utils meson valac - name: Build env: DESTDIR: out From 837a1faa94f1cebb7cdff6ab316a31f8e5e1322e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 14 Apr 2026 16:01:46 -0700 Subject: [PATCH 17/24] Remove canberragtk4 dep from README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 1b0fb41c..654f6451 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ You'll need the following dependencies: libcanberra-gtk-dev - libcanberra-gtk4-dev libgranite-7-dev > 7.7.0 libglib2.0-dev libgtk-4-dev From 47e744594bf10a877ba8c2188418ef36a2d9e3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 14 Apr 2026 16:11:13 -0700 Subject: [PATCH 18/24] See if this fixes compilation --- src/Widgets/PlayerRow.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Widgets/PlayerRow.vala b/src/Widgets/PlayerRow.vala index 1443413a..9b147a7b 100644 --- a/src/Widgets/PlayerRow.vala +++ b/src/Widgets/PlayerRow.vala @@ -238,7 +238,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { prev_btn.clicked.connect (() => { Idle.add (() => { - if (!Thread.supported ()) { + if (Thread.supported () == false) { warning ("Threading is not supported. DBus timeout could be blocking UI"); try { if (mp_client == null && client.player.can_go_previous) { @@ -271,7 +271,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { play_btn.clicked.connect (() => { Idle.add (() => { - if (!Thread.supported ()) { + if (Thread.supported () == false) { warning ("Threading is not supported. DBus timeout could be blocking UI"); try { if (mp_client == null) { From ff571c569c702dbf5c586c1b139954d53fbe1ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 14 Apr 2026 16:12:39 -0700 Subject: [PATCH 19/24] nope --- src/Widgets/PlayerRow.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Widgets/PlayerRow.vala b/src/Widgets/PlayerRow.vala index 9b147a7b..1443413a 100644 --- a/src/Widgets/PlayerRow.vala +++ b/src/Widgets/PlayerRow.vala @@ -238,7 +238,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { prev_btn.clicked.connect (() => { Idle.add (() => { - if (Thread.supported () == false) { + if (!Thread.supported ()) { warning ("Threading is not supported. DBus timeout could be blocking UI"); try { if (mp_client == null && client.player.can_go_previous) { @@ -271,7 +271,7 @@ public class Sound.Widgets.PlayerRow : Gtk.Box { play_btn.clicked.connect (() => { Idle.add (() => { - if (Thread.supported () == false) { + if (!Thread.supported ()) { warning ("Threading is not supported. DBus timeout could be blocking UI"); try { if (mp_client == null) { From 7c167bff8df604922fdf8b55ad5dc17b97293362 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Wed, 29 Jul 2026 01:23:42 +0900 Subject: [PATCH 20/24] Fix build failing when defining signals with Gdk.ScrollEvent (#329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix build failing when defining signals with Gdk.ScrollEvent I suspect this is a bug of Vala. It tries to call gdk_value_get_event() which does not exist and fails to build with the following error message: ../src/Widgets/DisplayWidget.vala: In function ‘g_cclosure_user_marshal_VOID__GDK_EVENT’: ../src/Widgets/DisplayWidget.vala:18:19: error: implicit declaration of function ‘gdk_value_get_event’; did you mean ‘g_value_get_uint’? [-Wimplicit-function-declaration] 18 | public class Sound.DisplayWidget : Gtk.Box { | ^~~~~~~~~~~~~~~~~~~ | g_value_get_uint ../src/Widgets/DisplayWidget.vala:18:19: error: passing argument 2 of ‘callback’ makes pointer from integer without a cast [-Wint-conversion] 18 | public class Sound.DisplayWidget : Gtk.Box { | ^~~~~~~~~~~~~~~~~~~~~~~~~~ | | | int This commit resolves the above build error by wrapping Gdk.ScrollEvent with GLib.Value. * Make sure scroll works * Review variable name * Improve comment --- src/Indicator.vala | 12 ++++++++---- src/Widgets/DisplayWidget.vala | 15 +++++++++++---- src/Widgets/Scale.vala | 9 +++++++-- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/Indicator.vala b/src/Indicator.vala index f572e625..86787edb 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -328,14 +328,16 @@ public class Sound.Indicator : Wingpanel.Indicator { display_widget.icon_name = get_volume_icon (volume_control.volume.volume); } - private void on_volume_icon_scroll_event (Gdk.ScrollEvent e) { + private void on_volume_icon_scroll_event (Value event_value) { + unowned var e = (Gdk.ScrollEvent) event_value.peek_pointer (); double dir = 0.0; if (handle_scroll_event (e, out dir)) { handle_change (dir, false); } } - private void on_mic_icon_scroll_event (Gdk.ScrollEvent e) { + private void on_mic_icon_scroll_event (Value event_value) { + unowned var e = (Gdk.ScrollEvent) event_value.peek_pointer (); double dir = 0.0; if (handle_scroll_event (e, out dir)) { handle_change (dir, true); @@ -420,7 +422,8 @@ public class Sound.Indicator : Wingpanel.Indicator { volume_control.mic_volume = mic_adjustment.get_value (); }); - mic_scale.scroll_event.connect_after ((e) => { + mic_scale.scroll_event.connect_after ((event_value) => { + unowned var e = (Gdk.ScrollEvent) event_value.peek_pointer (); double dir = 0.0; if (handle_scroll_event (e, out dir)) { handle_change (dir, true); @@ -443,7 +446,8 @@ public class Sound.Indicator : Wingpanel.Indicator { volume_scale.slider_dropped.connect (play_volume_change_sound); - volume_scale.scroll_event.connect_after ((e) => { + volume_scale.scroll_event.connect_after ((event_value) => { + unowned var e = (Gdk.ScrollEvent) event_value.peek_pointer (); double dir = 0.0; if (handle_scroll_event (e, out dir)) { handle_change (dir, false); diff --git a/src/Widgets/DisplayWidget.vala b/src/Widgets/DisplayWidget.vala index 67815bb7..56c13a46 100644 --- a/src/Widgets/DisplayWidget.vala +++ b/src/Widgets/DisplayWidget.vala @@ -23,8 +23,11 @@ public class Sound.DisplayWidget : Gtk.Box { public bool mic_muted { get; set; } public string icon_name { get; set; } - public signal void volume_scroll_event (Gdk.ScrollEvent e); - public signal void mic_scroll_event (Gdk.ScrollEvent e); + // HACK: Using Gdk.ScrollEvent instead of Value as the type of the parameter + // resulsts build error with valac 0.56.18 + // See https://gitlab.gnome.org/GNOME/vala/-/work_items/1671 + public signal void volume_scroll_event (Value event_value); + public signal void mic_scroll_event (Value event_value); construct { var volume_icon = new Gtk.Image () { @@ -50,7 +53,9 @@ public class Sound.DisplayWidget : Gtk.Box { return Gdk.EVENT_PROPAGATE; } - mic_scroll_event ((Gdk.ScrollEvent) e); + var event_value = Value (typeof (Gdk.ScrollEvent)); + event_value.set_instance (e); + mic_scroll_event (event_value); return Gdk.EVENT_STOP; }); @@ -60,7 +65,9 @@ public class Sound.DisplayWidget : Gtk.Box { return Gdk.EVENT_PROPAGATE; } - volume_scroll_event ((Gdk.ScrollEvent) e); + var event_value = Value (typeof (Gdk.ScrollEvent)); + event_value.set_instance (e); + volume_scroll_event (event_value); return Gdk.EVENT_STOP; }); diff --git a/src/Widgets/Scale.vala b/src/Widgets/Scale.vala index f3259128..e490b076 100644 --- a/src/Widgets/Scale.vala +++ b/src/Widgets/Scale.vala @@ -4,7 +4,10 @@ */ public class Sound.Widgets.Scale : Granite.Bin { - public signal void scroll_event (Gdk.ScrollEvent e); + // HACK: Using Gdk.ScrollEvent instead of Value as the type of the parameter + // resulsts build error with valac 0.56.18 + // See https://gitlab.gnome.org/GNOME/vala/-/work_items/1671 + public signal void scroll_event (Value event_value); public signal void slider_dropped (); public Gtk.Adjustment adjustment { get; construct; } @@ -52,7 +55,9 @@ public class Sound.Widgets.Scale : Granite.Bin { return Gdk.EVENT_PROPAGATE; } - scroll_event ((Gdk.ScrollEvent) e); + var event_value = Value (typeof (Gdk.ScrollEvent)); + event_value.set_instance (e); + scroll_event (event_value); return Gdk.EVENT_STOP; }); From 47db6982c74117c6c1a551f2e15ccfd4cda91900 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Sat, 15 Aug 2026 00:13:18 +0900 Subject: [PATCH 21/24] Fix missing player controls (#331) --- src/Widgets/PlayerList.vala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Widgets/PlayerList.vala b/src/Widgets/PlayerList.vala index 1ccfd677..51a6f1ea 100644 --- a/src/Widgets/PlayerList.vala +++ b/src/Widgets/PlayerList.vala @@ -43,7 +43,6 @@ public class Sound.Widgets.PlayerList : Granite.Bin { }); object_manager = new Services.ObjectManager (); - object_manager.bind_property ("has-object", this, "visible", GLib.BindingFlags.SYNC_CREATE); object_manager.media_player_added.connect ((media_player, name, icon) => { bluetooth_widget = new PlayerRow.bluetooth (media_player, name, icon); From 1bce5ff0d82cc4ff1d88fc1475162b2c589a1e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 19 Aug 2026 09:56:55 -0700 Subject: [PATCH 22/24] Update meson.build --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 1d395461..4d6843af 100644 --- a/meson.build +++ b/meson.build @@ -28,7 +28,7 @@ gresource = gnome.compile_resources( source_dir: 'data' ) -wingpanel_dep = dependency('wingpanel-9', version: '>=2.1.0') +wingpanel_dep = dependency('wingpanel-9') wingpanel_indicatorsdir = wingpanel_dep.get_pkgconfig_variable('indicatorsdir', define_variable: ['libdir', libdir]) config_data = configuration_data() From eb3e527b9f3e998dd81b3b37006768839b516035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 19 Aug 2026 09:59:57 -0700 Subject: [PATCH 23/24] Update src/CanberraGtk4.vala Co-authored-by: Ryo Nakano --- src/CanberraGtk4.vala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/CanberraGtk4.vala b/src/CanberraGtk4.vala index 72633a9d..b70cd195 100644 --- a/src/CanberraGtk4.vala +++ b/src/CanberraGtk4.vala @@ -13,9 +13,13 @@ namespace CanberraGtk4 { if (context != null) { return context; - } if (Canberra.Context.create (out context) != Canberra.SUCCESS) { + } + + if (Canberra.Context.create (out context) != Canberra.SUCCESS) { return null; - } if (Canberra.Proplist.create (out proplist) != Canberra.SUCCESS) { + } + + if (Canberra.Proplist.create (out proplist) != Canberra.SUCCESS) { return null; } From 32e2b4b7cc6b64434119e0a851202b791c8be455 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Thu, 20 Aug 2026 07:19:28 +0900 Subject: [PATCH 24/24] README: Update dependencies --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 654f6451..9c262485 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,7 @@ You'll need the following dependencies: - libcanberra-gtk-dev - libgranite-7-dev > 7.7.0 + libgranite-7-dev >= 7.7.0 libglib2.0-dev libgtk-4-dev libnotify-dev