from time import sleep
import libvirt
from fortrace.core.qemu_monitor import QEMUMonitorSession
from fortrace.utility.applications.application import (
ApplicationEvent,
ApplicationType,
GenericApplication,
)
from fortrace.utility.applications.application_factory import get_application
from fortrace.utility.desktop_environments.desktop_environment import (
DesktopEnvironment,
DesktopEnvironmentType,
OSType,
)
[docs]
class GNOME(DesktopEnvironment):
"""Explicit class to interact with GNOME desktop environments."""
def __init__(self, qemu_monitor_session: QEMUMonitorSession):
super().__init__(
OSType.LINUX, DesktopEnvironmentType.GNOME, qemu_monitor_session
)
[docs]
def open_application(
self, application_type: ApplicationType, application_name: str, **kwargs
) -> GenericApplication:
"""Open and focus a new application on the GUI with the possibility to pass down further arguments.
Args:
application_type: type of application (needed for application factory)
application_name: the name of the application to open (capitalization matters!)
*args: pass further arguments to the opening process, if necessary
Returns:
an application object for further interaction
"""
# command window in ubuntu is somewhat broken and opens only certain applications
# thus we use activities window which will also set the focus on the opened application
self._qs.send_key_combination("meta_l")
sleep(0.5) # wait for prompt to show up
self._qs.send_text(application_name)
sleep(1) # necessary so keystroke is not omitted
# if the same application is already open, GNOME will focus it when not hitting ctrl-ret
if self.is_application_open(application_name):
self._qs.send_key_combination("ctrl-ret")
else:
self._qs.send_key_combination("ret")
application = get_application(
application_type, application_name, self._qs, self._on_change, **kwargs
)
sleep(5) # wait for application to be opened
# GNOME focuses own applications automatically, but not external ones
# FIXME: This will only work if firefox is not opened multiple times
if application_name == "Firefox":
self._qs.send_key_combination("meta_l")
self._qs.send_text(application_name, True)
return application
[docs]
def focus_application(self, application: GenericApplication):
if application.focused:
return
if application not in self._applications:
raise ValueError(
f"Could not focus on application {application.name} as it is not open"
)
if len([app for app in self._applications if application.name == app.name]) > 1:
raise NotImplementedError(
"Selection of this kind is not implemented right now."
)
else:
self._qs.send_key_combination("meta_l")
self._qs.send_text(application.name, True)
self._on_change(
ApplicationEvent.FOCUS_SHIFTED, application_reference=application
)
[docs]
def login(self, username: str, password: str):
# TODO: GNOME has two different login screens --> determine which one
# to select different users <-- standard login screen after startup
# the other if a user session is already active and the user is preselected
if not self._user_selected: # normal login screen with multiple users to select
# TODO: select the correct user -> text recognition and selection recognition necessary
pass
self._qs.send_key_combination("ret") # select user
sleep(0.5) # necessary, so password can be typed in correctly
self._qs.send_text(password, True)
sleep(5) # wait for desktop env to come up
# TODO: determine when desktop env is ready
self._session_unlocked = True
self._qs.mouse.init()
[docs]
def system_power_down(self):
"""Power down the system via GUI functionality.
Send a power-down request via QEMU to the guest (domain is not available and qemu controls direct key inputs),
and confirms the power-down message. This is by far the most graceful and fastest way to shut down a domain.
Notes:
Works in lock screen as well.
"""
try:
self._qs.direct_command("system_powerdown")
self._qs.send_key_combination("tab")
self._qs.send_key_combination("ret")
sleep(3)
except libvirt.libvirtError:
# TODO: Find better way than excepting the error
pass # in tests the domain might be powered down by virSession teardown, which results in an exception
# try:
# while self._qs.direct_command("info status") is not None:
# sleep(1)
# except libvirt.libvirtError as e:
# if str(e).find("domain is not running"):
# return
# else:
# raise e
[docs]
def run_a_command(self, command: str):
"""Opens GNOME's 'Run a Command' dialogue and enters the provided command.
Notes:
Please do not use this method to open applications, as the dialogue is unreliable with names
Args:
command: command to be entered
"""
self._qs.send_key_combination("alt-f2")
self._qs.send_text(command, True)