File indexing completed on 2024-04-21 05:25:18

0001 # Copyright 2016 Mycroft AI Inc.
0002 #
0003 # Licensed under the Apache License, Version 2.0 (the "License");
0004 # you may not use this file except in compliance with the License.
0005 # You may obtain a copy of the License at
0006 #
0007 #    http://www.apache.org/licenses/LICENSE-2.0
0008 #
0009 # Unless required by applicable law or agreed to in writing, software
0010 # distributed under the License is distributed on an "AS IS" BASIS,
0011 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 # See the License for the specific language governing permissions and
0013 # limitations under the License.
0014 
0015 import subprocess
0016 
0017 from adapt.intent import IntentBuilder
0018 from adapt.tools.text.tokenizer import EnglishTokenizer
0019 
0020 from mycroft import MycroftSkill, intent_handler
0021 from urllib.parse import quote
0022 from gi.repository import Gio as gio
0023 
0024 class ApplicationLauncher(MycroftSkill):
0025     def __init__(self):
0026         super().__init__()
0027         self.appmap = {}
0028         self.kalterlist = ["console"]
0029 
0030     def initialize(self):
0031         tokenizer = EnglishTokenizer()
0032 
0033         for app in gio.app_info_get_all():
0034             name = app.get_name().lower()
0035             if name is None:
0036                 # Likely an empty .desktop entry, skip it
0037                 continue
0038             entry = [app]
0039             tokenized_name = tokenizer.tokenize(name)[0]
0040 
0041             if name in self.appmap:
0042                 self.appmap[name] += entry
0043             else:
0044                 self.appmap[name] = entry
0045 
0046             self.register_vocabulary(name, 'Application')
0047             if name != tokenized_name:
0048                 self.register_vocabulary(tokenized_name, 'Application')
0049                 if tokenized_name in self.appmap:
0050                     self.appmap[tokenized_name] += entry
0051                 else:
0052                     self.appmap[tokenized_name] = entry
0053 
0054     @intent_handler(IntentBuilder('LaunchDesktopApplicationIntent')
0055                     .require('LaunchKeyword')
0056                     .require('Application'))
0057     def handle_launch_desktop_app(self, message):
0058         """Launch a dektop application using Desktop file."""
0059         app_name = message.data.get('Application')
0060         if app_name in self.kalterlist:
0061             app_name == self.get_alter_name(app_name)
0062         apps = self.appmap.get(app_name)
0063         if apps and len(apps) > 0:
0064             self.log.info('Launching {}'.format(app_name))
0065             apps[0].launch()
0066 
0067     @intent_handler(IntentBuilder('CloseDesktopApplicationIntent')
0068                     .require('CloseKeyword').require('Application'))
0069     def handle_close_desktop_app(self, message):
0070         """Close application using killall"""
0071         app_name = message.data.get("Application")
0072 
0073         if not self.kill_process_by_name(app_name):
0074             self.log.info(
0075                 "Couldn't kill {} try to get executable from desktop file".format(
0076                     app_name
0077                 )
0078             )
0079             apps = self.appmap.get(app_name)
0080             if apps:
0081                 app_name = apps[0].get_string("Exec")
0082                 if not self.kill_process_by_name(app_name):
0083                     self.speak("failed to close {}".format(app_name))
0084 
0085     def kill_process_by_name(self, app_name):
0086         """Kill a process using the least powerful signal that works."""
0087         self.log.info("Killing {}".format(app_name))
0088         for signal in ["SIGINT", "SIGQUIT", "SIGTERM", "SIGKILL"]:
0089             if subprocess.call(["killall", "-s", signal, app_name]) == 0:
0090                 self.log.info("Killed {} using {}".format(app_name, signal))
0091                 return True
0092 
0093         return False
0094 
0095     def get_alter_name(self, app_name):
0096         if app_name == "console":
0097             return "konsole"
0098 
0099 def create_skill():
0100     return ApplicationLauncher()