Speed optimizations for the menu.
This commit is contained in:
parent
fdc2fdc41d
commit
0368d764c6
152
scripts/menu.py
152
scripts/menu.py
@ -22,10 +22,15 @@ from gi.repository import Gtk, Gdk, GLib, Atk
|
||||
def read_desktop_files(paths):
|
||||
desktopEntries = []
|
||||
for path in paths:
|
||||
if not Path(path).exists():
|
||||
continue
|
||||
for file in Path(path).rglob('*.desktop'):
|
||||
config = configparser.ConfigParser(interpolation=None)
|
||||
config.read(file)
|
||||
desktopEntries.append(config)
|
||||
try:
|
||||
config = configparser.ConfigParser(interpolation=None)
|
||||
config.read(file, encoding='utf-8')
|
||||
desktopEntries.append(config)
|
||||
except (UnicodeDecodeError, configparser.Error):
|
||||
continue
|
||||
return desktopEntries
|
||||
|
||||
userApplicationsPath = Path.home() / '.local/share/applications'
|
||||
@ -93,34 +98,24 @@ subcategories = defaultdict(set)
|
||||
for entry in desktopEntries:
|
||||
try:
|
||||
# Check if NoDisplay=true is set
|
||||
try:
|
||||
noDisplay = entry.getboolean('Desktop Entry', 'NoDisplay', fallback=False)
|
||||
if noDisplay:
|
||||
continue
|
||||
except:
|
||||
pass
|
||||
if entry.getboolean('Desktop Entry', 'NoDisplay', fallback=False):
|
||||
continue
|
||||
|
||||
name = entry.get('Desktop Entry', 'Name', fallback=None)
|
||||
execCommand = entry.get('Desktop Entry', 'Exec', fallback=None)
|
||||
|
||||
if not name or not execCommand:
|
||||
continue
|
||||
|
||||
name = entry.get('Desktop Entry', 'Name')
|
||||
execCommand = entry.get('Desktop Entry', 'Exec')
|
||||
entryCategories = entry.get('Desktop Entry', 'Categories', fallback='').split(';')
|
||||
|
||||
# For applications with categories
|
||||
mainCategory = None
|
||||
for category in entryCategories:
|
||||
if category: # Skip empty strings
|
||||
mappedCategory = categoryMap.get(category, category)
|
||||
if mainCategory is None:
|
||||
mainCategory = mappedCategory
|
||||
|
||||
# Check if this might be a subcategory
|
||||
for other in entryCategories:
|
||||
if other and other != category:
|
||||
mappedOther = categoryMap.get(other, other)
|
||||
if mappedCategory != mappedOther:
|
||||
subcategories[mappedOther].add(mappedCategory)
|
||||
validCategories = [cat for cat in entryCategories if cat.strip()]
|
||||
|
||||
# If we found a category, add the application
|
||||
if mainCategory:
|
||||
if validCategories:
|
||||
# Use first valid category as main
|
||||
mainCategory = categoryMap.get(validCategories[0], validCategories[0])
|
||||
categoryApps[mainCategory][name] = execCommand
|
||||
else:
|
||||
# If no category was found, add to "Other"
|
||||
@ -194,58 +189,17 @@ class I38_Tab_Menu(Gtk.Window):
|
||||
sortedCategories.remove("All Applications")
|
||||
sortedCategories.insert(0, "All Applications")
|
||||
|
||||
# Create tabs
|
||||
for category in sortedCategories:
|
||||
# Create tabs - defer TreeView creation for performance
|
||||
self.tabCategories = sortedCategories
|
||||
self.createdTabs = set() # Track which tabs have been created
|
||||
|
||||
for i, category in enumerate(sortedCategories):
|
||||
if not categoryApps[category]: # Skip empty categories
|
||||
continue
|
||||
|
||||
# Create a TreeStore for this category
|
||||
store = Gtk.TreeStore(str, str) # Columns: Name, Exec
|
||||
self.stores[category] = store
|
||||
|
||||
# Add applications to this category's store
|
||||
sortedApps = sorted(categoryApps[category].items())
|
||||
|
||||
# Check for potential subcategories within this category
|
||||
categorySubcategories = {}
|
||||
for appName, appExec in sortedApps:
|
||||
subcatFound = False
|
||||
for subcat in subcategories.get(category, []):
|
||||
if appName in categoryApps.get(subcat, {}):
|
||||
if subcat not in categorySubcategories:
|
||||
categorySubcategories[subcat] = []
|
||||
categorySubcategories[subcat].append((appName, appExec))
|
||||
subcatFound = True
|
||||
break
|
||||
|
||||
if not subcatFound:
|
||||
# Add directly to the category's root
|
||||
store.append(None, [appName, appExec])
|
||||
|
||||
# Add any subcategories
|
||||
for subcat, subcatApps in sorted(categorySubcategories.items()):
|
||||
subcatIter = store.append(None, [subcat, None])
|
||||
for appName, appExec in sorted(subcatApps):
|
||||
store.append(subcatIter, [appName, appExec])
|
||||
|
||||
# Create TreeView for this category
|
||||
treeView = Gtk.TreeView(model=store)
|
||||
treeView.set_headers_visible(False)
|
||||
self.treeViews[category] = treeView
|
||||
|
||||
# Add column for application names
|
||||
renderer = Gtk.CellRendererText()
|
||||
column = Gtk.TreeViewColumn("Applications", renderer, text=0)
|
||||
treeView.append_column(column)
|
||||
|
||||
# Set up scrolled window
|
||||
# Create placeholder scrolled window
|
||||
scrolledWindow = Gtk.ScrolledWindow()
|
||||
scrolledWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
||||
scrolledWindow.add(treeView)
|
||||
|
||||
# Connect signals
|
||||
treeView.connect("row-activated", self.on_row_activated)
|
||||
treeView.connect("key-press-event", self.on_key_press)
|
||||
|
||||
# Create tab label
|
||||
tabLabel = Gtk.Label(label=category)
|
||||
@ -254,13 +208,14 @@ class I38_Tab_Menu(Gtk.Window):
|
||||
self.notebook.append_page(scrolledWindow, tabLabel)
|
||||
|
||||
# Set tab accessibility properties for screen readers
|
||||
tabChild = self.notebook.get_nth_page(self.notebook.get_n_pages() - 1)
|
||||
# Get the accessible object and set properties on it instead
|
||||
accessible = tabChild.get_accessible()
|
||||
accessible = scrolledWindow.get_accessible()
|
||||
accessible.set_name(f"{category} applications")
|
||||
# Use Atk role instead of Gtk.AccessibleRole which isn't available in GTK 3.0
|
||||
accessible.set_role(Atk.Role.LIST)
|
||||
|
||||
# Create first tab immediately
|
||||
if sortedCategories:
|
||||
self.create_tab_content(0)
|
||||
|
||||
# Connect notebook signals
|
||||
self.notebook.connect("switch-page", self.on_switch_page)
|
||||
|
||||
@ -276,6 +231,48 @@ class I38_Tab_Menu(Gtk.Window):
|
||||
windowAccessible.set_name("I38 Application Menu")
|
||||
windowAccessible.set_description("Tab-based application launcher menu. Press slash to search, type app name and use down arrow to navigate results. Type letters to incrementally navigate to matching applications.")
|
||||
|
||||
def create_tab_content(self, tabIndex):
|
||||
"""Create TreeView content for a tab on demand"""
|
||||
if tabIndex in self.createdTabs or tabIndex >= len(self.tabCategories):
|
||||
return
|
||||
|
||||
category = self.tabCategories[tabIndex]
|
||||
if not categoryApps[category]:
|
||||
return
|
||||
|
||||
# Create a TreeStore for this category
|
||||
store = Gtk.TreeStore(str, str) # Columns: Name, Exec
|
||||
self.stores[category] = store
|
||||
|
||||
# Add applications to this category's store (simplified - no subcategories)
|
||||
sortedApps = sorted(categoryApps[category].items())
|
||||
for appName, appExec in sortedApps:
|
||||
store.append(None, [appName, appExec])
|
||||
|
||||
# Create TreeView for this category
|
||||
treeView = Gtk.TreeView(model=store)
|
||||
treeView.set_headers_visible(False)
|
||||
self.treeViews[category] = treeView
|
||||
|
||||
# Add column for application names
|
||||
renderer = Gtk.CellRendererText()
|
||||
column = Gtk.TreeViewColumn("Applications", renderer, text=0)
|
||||
treeView.append_column(column)
|
||||
|
||||
# Get the scrolled window for this tab
|
||||
scrolledWindow = self.notebook.get_nth_page(tabIndex)
|
||||
scrolledWindow.add(treeView)
|
||||
|
||||
# Connect signals
|
||||
treeView.connect("row-activated", self.on_row_activated)
|
||||
treeView.connect("key-press-event", self.on_key_press)
|
||||
|
||||
# Show the new content
|
||||
treeView.show()
|
||||
|
||||
# Mark this tab as created
|
||||
self.createdTabs.add(tabIndex)
|
||||
|
||||
def populate_completion_store(self):
|
||||
"""Populate completion store with all available applications"""
|
||||
self.completionStore.clear()
|
||||
@ -286,6 +283,9 @@ class I38_Tab_Menu(Gtk.Window):
|
||||
self.completionStore.append([appName, execCommand])
|
||||
|
||||
def on_switch_page(self, notebook, page, pageNum):
|
||||
# Create tab content if not already created
|
||||
self.create_tab_content(pageNum)
|
||||
|
||||
# Focus the TreeView in the newly selected tab
|
||||
tab = notebook.get_nth_page(pageNum)
|
||||
for child in tab.get_children():
|
||||
|
Loading…
x
Reference in New Issue
Block a user