-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
151 lines (129 loc) · 6.42 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import os
import configparser
import logging
from ulauncher.api.client.EventListener import EventListener
from ulauncher.api.client.Extension import Extension
from ulauncher.api.shared.event import KeywordQueryEvent
from ulauncher.api.shared.item.ExtensionResultItem import ExtensionResultItem
from ulauncher.api.shared.action.RenderResultListAction import RenderResultListAction
from ulauncher.api.shared.action.RunScriptAction import RunScriptAction
logger = logging.getLogger(__name__)
class DemoExtension(Extension):
def __init__(self):
super().__init__()
self.subscribe(KeywordQueryEvent, KeywordQueryEventListener())
class KeywordQueryEventListener(EventListener):
def on_event(self, event, extension):
query = event.get_argument() or ""
if not query:
return RenderResultListAction([
ExtensionResultItem(icon='images/icon.png',
name='Enter an application name to view or launch it',
description='For example: firefox or nemo',
on_enter=None)
])
# Extract the application name from the query
app_name = query.strip()
if not app_name:
return RenderResultListAction([
ExtensionResultItem(icon='images/icon.png',
name='No application name provided',
description='Please enter an application name',
on_enter=None)
])
# Define directories to search for .desktop files
desktop_files_dirs = [
"/usr/share/applications",
os.path.expanduser("~/.local/share/applications"),
"/var/lib/flatpak/exports/share/applications"
]
# Find all matching desktop files for the given application name
desktop_files = self.find_desktop_files(app_name, desktop_files_dirs)
if not desktop_files:
return RenderResultListAction([
ExtensionResultItem(icon='images/icon.png',
name=f'No .desktop file found for {app_name}',
description='Please check the application name and try again',
on_enter=None)
])
# Create items for each matching desktop file
items = []
for desktop_file in desktop_files:
# Get the desktop file information (Name, Exec, Icon, Actions)
desktop_data = self.parse_desktop_file(desktop_file)
if not desktop_data:
continue
# If there are no specific desktop actions, just add the main app launch
desktop_actions = desktop_data.get('actions', {})
if not desktop_actions:
items.append(ExtensionResultItem(
icon=self.find_icon(desktop_data["Icon"]),
name=f'Launch {desktop_data["Name"]}',
description=f'Exec: {desktop_data["Exec"]}',
on_enter=RunScriptAction(desktop_data["Exec"], None)
))
else:
# Prepare items to display the desktop actions if present
for action_name, action_details in desktop_actions.items():
items.append(ExtensionResultItem(
icon=self.find_icon(desktop_data["Icon"]),
name=action_name,
description=f"Exec: {action_details['Exec']}",
on_enter=RunScriptAction(action_details['Exec'], None)
))
return RenderResultListAction(items)
def find_desktop_files(self, app_name, directories):
""" Find all matching desktop files for the given app name """
matching_files = []
for directory in directories:
if os.path.isdir(directory):
logger.info(f"Scanning directory: {directory}")
for file_name in os.listdir(directory):
if file_name.endswith(".desktop"):
file_path = os.path.join(directory, file_name)
desktop_data = self.parse_desktop_file(file_path)
if (app_name.lower() in file_name.lower() or
app_name.lower() in desktop_data.get('Name', '').lower() or
app_name.lower() in desktop_data.get('Exec', '').lower()):
matching_files.append(file_path)
return matching_files
def parse_desktop_file(self, file_path):
""" Parse the .desktop file and extract the relevant fields """
config = configparser.ConfigParser(interpolation=None)
try:
config.read(file_path)
logger.info(f"Parsing desktop file: {file_path}")
except Exception as e:
logger.error(f"Error reading {file_path}: {e}")
return {}
# Extract basic desktop file fields
desktop_data = {
'Name': config['Desktop Entry'].get('Name', ''),
'Exec': config['Desktop Entry'].get('Exec', '').split(" ")[0], # Keep the main executable command
'Icon': config['Desktop Entry'].get('Icon', 'images/icon.png'), # Default to a generic icon if not present
'actions': {}
}
# Extract desktop actions if present
for section in config.sections():
if section.startswith("Desktop Action"):
action_name = section.split()[-1]
desktop_data['actions'][action_name] = {
'Name': config[section].get('Name', ''),
'Exec': config[section].get('Exec', '')
}
return desktop_data
def find_icon(self, icon_name):
""" Locate the icon file from various directories or return a default icon """
icon_dirs = [
"/usr/share/icons/hicolor/", # Common system icon directory
os.path.expanduser("~/.local/share/icons/"), # User icon directory
"/usr/share/pixmaps/" # Fallback system directory
]
for icon_dir in icon_dirs:
icon_path = os.path.join(icon_dir, f"{icon_name}.png")
if os.path.isfile(icon_path):
return icon_path
# Fallback to the default icon
return "images/icon.png"
if __name__ == '__main__':
DemoExtension().run()