Source code for fortrace.utility.desktop_environments.Linux.kde_plasma

import time

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
from fortrace.utility.distribution_constants import DesktopEnvironmentType, OSType
from fortrace.utility.exceptions import ConfigurationError, DesktopEnvironmentException
from fortrace.utility.image_processing.image_similarity import (
    detect_newly_opened_window,
)
from fortrace.utility.image_processing.text_detection import (
    detect_and_recognize_text,
    text_line_contains,
)
from fortrace.utility.logger_helper import setup_logger

logger = setup_logger(__name__)


[docs] class Plasma(DesktopEnvironment): """Implementation of KDE Plasma desktop environment""" def __init__( self, qemu_monitor_session: QEMUMonitorSession, ): super().__init__( OSType.LINUX, DesktopEnvironmentType.KDE_Plasma, qemu_monitor_session ) self._application_launcher_coordinates = None
[docs] def open_application( self, application_type: ApplicationType, application_name: str, **kwargs ) -> GenericApplication: """Opens a specified application with Plasma's Application Launcher. Args: application_type: application_name: **kwargs: Todo: Currently, this method only works with a light theme, since the application launcher cannot be recognized properly in a dark theme Returns: """ before = ( self._qs.take_screenshot() ) # take screenshot when application is not opened if not self._application_launcher_coordinates: self._qs.send_key_combination("meta_l") time.sleep(2) for _ in range(5): windows_menu_coordinates = detect_newly_opened_window( before, self._qs.take_screenshot() ) if windows_menu_coordinates: self._application_launcher_coordinates = windows_menu_coordinates logger.debug( "Set application launcher coordinates to %s", self._application_launcher_coordinates, ) break time.sleep(2) else: raise DesktopEnvironmentException( "Cannot determine application launcher coordinates" ) else: self._qs.send_key_combination("meta_l") for _ in range(5): # detect if Windows menu has loaded text = detect_and_recognize_text( self._qs.take_screenshot(), self._application_launcher_coordinates )[1] if text_line_contains( text, ["Favorites", "Applications", "Places"], "ignore_case" ): logger.debug("Application launcher opened") break time.sleep(5) else: logger.error("Could not open application launcher within 25 seconds") raise DesktopEnvironmentException( "Application launcher window is not responding as expected" ) self._qs.send_text(application_name) # crop out search bar to search only results window for application name launcher_result_window = list(self._application_launcher_coordinates) launcher_result_window[1] += 45 launcher_result_window = tuple(launcher_result_window) for _ in range(5): if text_line_contains( detect_and_recognize_text( self._qs.take_screenshot(), launcher_result_window, )[1], application_name, "sequence", ): break elif text_line_contains( detected := detect_and_recognize_text( self._qs.take_screenshot(), self._application_launcher_coordinates )[1], ["No matches"], "ignore_case", ): raise DesktopEnvironmentException( f"Application {application_name} not found!" ) logger.debug( "Search for application has not completed yet. Will wait longer." ) time.sleep(5) else: logger.warning( "Could not find %s with application launchers search. Maybe a typo? " "Or the search hang up.", application_name, ) logger.warning("Detected strings: %s", detected) raise DesktopEnvironmentException( f"Application {application_name} not found!" ) logger.info("Open application %s", application_name) self._qs.send_key_combination("ret") application = get_application( application_type, application_name, self._qs, self._on_change, **kwargs ) time.sleep(5) for _ in range(5): coordinates = detect_newly_opened_window(before, self._qs.take_screenshot()) if coordinates is None: logger.debug( "Application %s is currently not opened. Will wait.", application_name, ) else: break time.sleep(5) else: raise DesktopEnvironmentException( "Failed to open application %s", application_name ) application.coordinates = coordinates return application
[docs] def login(self, username: str, password: str | None): self._qs.send_text(password, True) for i in range(5): text = detect_and_recognize_text(self._qs.take_screenshot())[1] if text_line_contains(text, "Login failed"): raise ConfigurationError( f"The provided password '{password}' is not correct" ) time.sleep(2) self._session_unlocked = True # TODO: determine when Desktop env is ready time.sleep(10) self._qs.mouse.init()
[docs] def focus_application(self, application: GenericApplication): if application.focused: return self._qs.send_key_combination("alt-spc") # open KRunner time.sleep(2) self._qs.send_text(f"Windows {application.name}", True) self._on_change( ApplicationEvent.FOCUS_SHIFTED, application_reference=application )
[docs] def command_krunner(self, command: str): """Send a command to KRunner. Args: command: the command to send Notes: This method does only send a command to KRunner and does not take care of newly opened windows or other focus shifts that might happen. """ self._qs.send_key_combination("alt-spc") # open Krunner time.sleep(2) logger.info("Executing command %s in KRunner", command) self._qs.send_text(command, True)