diff --git a/qubes/ext/audio.py b/qubes/ext/audio.py index 3df00f9c..ff0c5f46 100644 --- a/qubes/ext/audio.py +++ b/qubes/ext/audio.py @@ -17,16 +17,42 @@ # License along with this library; if not, see . # +import asyncio + import qubes.config import qubes.ext class AUDIO(qubes.ext.Extension): # pylint: disable=unused-argument,no-self-use + @staticmethod + def attached_vms(vm): + for domain in vm.app.domains: + if getattr(domain, 'audiovm', None) and domain.audiovm == vm: + yield domain + + @qubes.ext.handler('domain-pre-shutdown') + @asyncio.coroutine + def on_domain_pre_shutdown(self, vm, event, **kwargs): + attached_vms = [domain for domain in self.attached_vms(vm) if + domain.is_running()] + if attached_vms and not kwargs.get('force', False): + raise qubes.exc.QubesVMError( + self, 'There are running VMs using this VM as AudioVM: ' + '{}'.format(', '.join(vm.name for vm in attached_vms))) + + @qubes.ext.handler('domain-pre-start') + def on_domain_pre_start(self, vm, event, start_guid, **kwargs): + if getattr(vm, 'audiovm', None): + if vm.audiovm.qid != 0: + if not vm.audiovm.is_running(): + yield from vm.audiovm.start(start_guid=start_guid, + notify_function=None) + @qubes.ext.handler('domain-init', 'domain-load') def on_domain_init_load(self, vm, event): if getattr(vm, 'audiovm', None): - if 'audiovm-' + vm.audiovm not in list(vm.tags): + if 'audiovm-' + vm.audiovm.name not in list(vm.tags): vm.fire_event('property-set:audiovm', name='audiovm', newvalue=vm.audiovm) @@ -38,8 +64,6 @@ class AUDIO(qubes.ext.Extension): @qubes.ext.handler('property-set:audiovm') def on_property_set(self, subject, event, name, newvalue, oldvalue=None): - # pylint: disable=unused-argument,no-self-use - # Clean other 'audiovm-XXX' tags. # pulseaudio agent (module-vchan-sink) can connect to only one domain tags_list = list(subject.tags) @@ -53,7 +77,6 @@ class AUDIO(qubes.ext.Extension): @qubes.ext.handler('domain-qdb-create') def on_domain_qdb_create(self, vm, event): - # pylint: disable=unused-argument,no-self-use # Add AudioVM Xen ID for gui-agent if getattr(vm, 'audiovm', None): if vm != vm.audiovm: @@ -62,8 +85,7 @@ class AUDIO(qubes.ext.Extension): @qubes.ext.handler('property-set:default_audiovm', system=True) def on_property_set_default_audiovm(self, app, event, name, newvalue, - oldvalue=None): - # pylint: disable=unused-argument,no-self-use + oldvalue=None): for vm in app.domains: if hasattr(vm, 'audiovm') and vm.property_is_default('audiovm'): vm.fire_event('property-set:audiovm', diff --git a/qubes/ext/gui.py b/qubes/ext/gui.py index f850ce89..41214c12 100644 --- a/qubes/ext/gui.py +++ b/qubes/ext/gui.py @@ -21,13 +21,38 @@ # License along with this library; if not, see . # +import asyncio + import qubes.config import qubes.ext class GUI(qubes.ext.Extension): - # pylint: disable=too-few-public-methods - # TODO put this somewhere... + # pylint: disable=too-few-public-methods,unused-argument,no-self-use + @staticmethod + def attached_vms(vm): + for domain in vm.app.domains: + if getattr(domain, 'guivm', None) and domain.guivm == vm: + yield domain + + @qubes.ext.handler('domain-pre-shutdown') + def on_domain_pre_shutdown(self, vm, event, **kwargs): + attached_vms = [domain for domain in self.attached_vms(vm) if + domain.is_running()] + if attached_vms and not kwargs.get('force', False): + raise qubes.exc.QubesVMError( + self, 'There are running VMs using this VM as GuiVM: ' + '{}'.format(', '.join(vm.name for vm in attached_vms))) + + @qubes.ext.handler('domain-pre-start') + @asyncio.coroutine + def on_domain_pre_start(self, vm, event, start_guid, **kwargs): + if getattr(vm, 'guivm', None): + if vm.guivm.qid != 0: + if not vm.guivm.is_running(): + yield from vm.guivm.start(start_guid=start_guid, + notify_function=None) + @staticmethod def send_gui_mode(vm): vm.run_service('qubes.SetGuiMode', @@ -35,11 +60,10 @@ class GUI(qubes.ext.Extension): if vm.features.get('gui-seamless', False) else 'FULLSCREEN')) - # pylint: disable=unused-argument,no-self-use @qubes.ext.handler('domain-init', 'domain-load') def on_domain_init_load(self, vm, event): if getattr(vm, 'guivm', None): - if 'guivm-' + vm.guivm not in list(vm.tags): + if 'guivm-' + vm.guivm.name not in list(vm.tags): vm.fire_event('property-set:guivm', name='guivm', newvalue=vm.guivm) @@ -51,8 +75,6 @@ class GUI(qubes.ext.Extension): @qubes.ext.handler('property-set:guivm') def on_property_set(self, subject, event, name, newvalue, oldvalue=None): - # pylint: disable=unused-argument,no-self-use - # Clean other 'guivm-XXX' tags. # gui-daemon can connect to only one domain tags_list = list(subject.tags) @@ -66,7 +88,6 @@ class GUI(qubes.ext.Extension): @qubes.ext.handler('domain-qdb-create') def on_domain_qdb_create(self, vm, event): - # pylint: disable=unused-argument,no-self-use for feature in ('gui-videoram-overhead', 'gui-videoram-min'): try: vm.untrusted_qdb.write( @@ -106,7 +127,6 @@ class GUI(qubes.ext.Extension): @qubes.ext.handler('property-set:default_guivm', system=True) def on_property_set_default_guivm(self, app, event, name, newvalue, oldvalue=None): - # pylint: disable=unused-argument,no-self-use for vm in app.domains: if hasattr(vm, 'guivm') and vm.property_is_default('guivm'): vm.fire_event('property-set:guivm',