@@ -7,8 +7,8 @@ import St from 'gi://St';
7
7
8
8
import { gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js' ;
9
9
import * as Main from 'resource:///org/gnome/shell/ui/main.js' ;
10
- import { Ornament , PopupMenuItem } from 'resource:///org/gnome/shell/ui/popupMenu.js' ;
11
- import { QuickMenuToggle , QuickSlider } from 'resource:///org/gnome/shell/ui/quickSettings.js' ;
10
+ import { Ornament , PopupBaseMenuItem , PopupMenuItem , PopupMenuSection } from 'resource:///org/gnome/shell/ui/popupMenu.js' ;
11
+ import { QuickMenuToggle , QuickSlider , QuickToggle } from 'resource:///org/gnome/shell/ui/quickSettings.js' ;
12
12
import * as Volume from 'resource:///org/gnome/shell/ui/status/volume.js' ;
13
13
14
14
import { get_pactl_path , spawn } from "./utils.js" ;
@@ -427,12 +427,20 @@ class ApplicationsMixerManager {
427
427
private _sa_event_id : number ;
428
428
private _sr_event_id : number ;
429
429
430
- public on_slider_added ? : ( slider : ApplicationVolumeSlider ) => void ;
431
- public on_slider_removed ? : ( slider : ApplicationVolumeSlider ) => void ;
430
+ public on_slider_added : ( slider : ApplicationVolumeSlider ) => void ;
431
+ public on_slider_removed : ( slider : ApplicationVolumeSlider ) => void ;
432
432
433
- constructor ( settings : Gio . Settings , filter_mode : string , filters : string [ ] ) {
433
+ constructor (
434
+ settings : Gio . Settings ,
435
+ filter_mode : string ,
436
+ filters : string [ ] ,
437
+ on_slider_added : ( slider : ApplicationVolumeSlider ) => void ,
438
+ on_slider_removed : ( slider : ApplicationVolumeSlider ) => void
439
+ ) {
434
440
this . _settings = settings ;
435
441
this . _mixer_control = Volume . getMixerControl ( ) ;
442
+ this . on_slider_added = on_slider_added ;
443
+ this . on_slider_removed = on_slider_removed ;
436
444
437
445
this . _sliders = new Map ( ) ;
438
446
this . _filter_mode = filter_mode ;
@@ -470,14 +478,14 @@ class ApplicationsMixerManager {
470
478
) ;
471
479
this . _sliders . set ( id , slider ) ;
472
480
473
- this . on_slider_added ?. ( slider ) ;
481
+ this . on_slider_added ( slider ) ;
474
482
}
475
483
476
484
private _stream_removed ( _control : Gvc . MixerControl , id : number ) {
477
485
if ( ! this . _sliders . has ( id ) ) return ;
478
486
479
487
const slider = this . _sliders . get ( id ) ;
480
- this . on_slider_removed ?. ( slider ) ;
488
+ this . on_slider_removed ( slider ) ;
481
489
482
490
this . _sliders . delete ( id ) ;
483
491
slider . destroy ( ) ;
@@ -513,9 +521,13 @@ export class ApplicationsMixer {
513
521
514
522
this . _sliders_ordered = [ placeholder ] ;
515
523
516
- this . _slider_manager = new ApplicationsMixerManager ( settings , filter_mode , filters ) ;
517
- this . _slider_manager . on_slider_added = this . _slider_added . bind ( this ) ;
518
- this . _slider_manager . on_slider_removed = this . _slider_removed . bind ( this ) ;
524
+ this . _slider_manager = new ApplicationsMixerManager (
525
+ settings ,
526
+ filter_mode ,
527
+ filters ,
528
+ this . _slider_added . bind ( this ) ,
529
+ this . _slider_removed . bind ( this )
530
+ ) ;
519
531
}
520
532
521
533
_slider_added ( slider : ApplicationVolumeSlider ) {
@@ -541,6 +553,75 @@ export class ApplicationsMixer {
541
553
}
542
554
} ;
543
555
556
+ // Note: lot of code taken from https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/status/backgroundApps.js?ref_type=heads#L137
557
+ export const ApplicationsMixerToggle = GObject . registerClass ( class ApplicationsMixerToggle extends QuickToggle {
558
+ private _slider_manager : ApplicationsMixerManager ;
559
+ private _slidersSection : PopupMenuSection ;
560
+
561
+ constructor ( settings : Gio . Settings , filter_mode : string , filters : string [ ] ) {
562
+ super ( {
563
+ visible : false , hasMenu : true ,
564
+ // The background apps toggle looks like a flat menu, but doesn't
565
+ // have a separate menu button. Fake it with an arrow icon.
566
+ iconName : "go-next-symbolic" ,
567
+ title : "Applications emitting sound"
568
+ } ) ;
569
+
570
+ this . add_style_class_name ( "background-apps-quick-toggle" ) ;
571
+ this . _box . set_child_above_sibling ( this . _icon , null ) ;
572
+
573
+ this . menu . setHeader ( "audio-volume-high-symbolic" , _ ( "Applications volumes" ) ) ;
574
+ this . _slidersSection = new PopupMenuSection ( ) ;
575
+ this . menu . addMenuItem ( this . _slidersSection ) ;
576
+
577
+ this . connect ( "popup-menu" , ( ) => this . menu . open ( false ) ) ;
578
+
579
+ this . menu . connect ( "open-state-changed" , ( ) => this . _syncVisibility ( ) ) ;
580
+ Main . sessionMode . connect ( "updated" , ( ) => this . _syncVisibility ( ) ) ;
581
+
582
+ this . _slider_manager = new ApplicationsMixerManager (
583
+ settings ,
584
+ filter_mode ,
585
+ filters ,
586
+ this . _slider_added . bind ( this ) ,
587
+ this . _slider_removed . bind ( this )
588
+ ) ;
589
+ }
590
+
591
+ _syncVisibility ( ) {
592
+ const { isLocked } = Main . sessionMode ;
593
+ const nSliders = this . _slidersSection . numMenuItems ;
594
+ // We cannot hide the quick toggle while the menu is open, otherwise
595
+ // the menu position goes bogus. We can't show it in locked sessions
596
+ // either
597
+ this . visible = ! isLocked && ( this . menu . isOpen || nSliders > 0 ) ;
598
+ }
599
+
600
+ _slider_added ( slider : ApplicationVolumeSlider ) {
601
+ let slider_item = new ApplicationVolumeSliderItem ( slider ) ;
602
+ slider . _item = slider_item ;
603
+ this . _slidersSection . addMenuItem ( slider_item ) ;
604
+
605
+ this . _syncVisibility ( ) ;
606
+ }
607
+
608
+ _slider_removed ( slider : ApplicationVolumeSlider ) {
609
+ this . _slidersSection . box . remove_child ( slider . _item ) ;
610
+ this . _slidersSection . disconnect_object ( slider . _item ) ;
611
+ this . _syncVisibility ( ) ;
612
+ }
613
+
614
+ vfunc_clicked ( ) {
615
+ this . menu . open ( true ) ;
616
+ }
617
+
618
+ destroy ( ) {
619
+ this . _slider_manager . destroy ( ) ;
620
+
621
+ super . destroy ( ) ;
622
+ }
623
+ } ) ;
624
+
544
625
const ApplicationVolumeSlider = GObject . registerClass ( class ApplicationVolumeSlider extends StreamSlider {
545
626
private _pactl_path : string | null ;
546
627
private _pactl_path_changed_id : number ;
@@ -645,3 +726,14 @@ const ApplicationVolumeSlider = GObject.registerClass(class ApplicationVolumeSli
645
726
this . _setActiveDevice ( device . get_id ( ) ) ;
646
727
}
647
728
} ) ;
729
+
730
+ const ApplicationVolumeSliderItem = GObject . registerClass ( class ApplicationVolumeSliderItem extends PopupBaseMenuItem {
731
+ constructor ( slider : ApplicationVolumeSlider ) {
732
+ super ( ) ;
733
+ slider . x_expand = true ;
734
+ // since it uses a quick settings menu it will be broken if opened in
735
+ // another menu
736
+ slider . _menuButton . get_parent ( ) . remove_child ( slider . _menuButton ) ;
737
+ this . add_child ( slider ) ;
738
+ }
739
+ } ) ;
0 commit comments