App Info Tweaks
This commit is contained in:
1 parent
95a93cadbf
commit
1c4945f9e0
1 file changed
+101
-78
+101
-78
@@ -54,34 +54,34 @@ def get_executable_path(exec_string):
|
||||
"""Extract and find the actual executable path from Exec field"""
|
||||
if not exec_string:
|
||||
return None
|
||||
|
||||
|
||||
# Remove common exec modifiers and arguments
|
||||
exec_parts = exec_string.split()
|
||||
if not exec_parts:
|
||||
return None
|
||||
|
||||
|
||||
executable = exec_parts[0]
|
||||
|
||||
|
||||
# Remove common prefixes
|
||||
prefixes_to_remove = ['env', 'bash', 'sh', '/usr/bin/env']
|
||||
prefixes_to_remove = ["env", "bash", "sh", "/usr/bin/env"]
|
||||
while executable in prefixes_to_remove and len(exec_parts) > 1:
|
||||
exec_parts.pop(0)
|
||||
executable = exec_parts[0]
|
||||
|
||||
|
||||
# If it's already an absolute path, check if it exists
|
||||
if executable.startswith('/'):
|
||||
if executable.startswith("/"):
|
||||
if os.path.exists(executable):
|
||||
return executable
|
||||
return None
|
||||
|
||||
|
||||
# Search in PATH
|
||||
try:
|
||||
result = subprocess.run(['which', executable], capture_output=True, text=True)
|
||||
result = subprocess.run(["which", executable], capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -96,81 +96,88 @@ def get_app_info(wmclass):
|
||||
"exec": "",
|
||||
"location": "",
|
||||
"categories": "",
|
||||
"desktop_file": ""
|
||||
"desktop_file": "",
|
||||
}
|
||||
|
||||
|
||||
desktop_paths = [
|
||||
"/usr/share/applications",
|
||||
"/var/lib/flatpak/exports/share/applications",
|
||||
os.path.expanduser("~/.local/share/applications"),
|
||||
"/usr/local/share/applications"
|
||||
"/usr/local/share/applications",
|
||||
]
|
||||
|
||||
|
||||
for path in desktop_paths:
|
||||
if not os.path.exists(path):
|
||||
continue
|
||||
|
||||
|
||||
# Try exact match first
|
||||
exact_matches = [f for f in os.listdir(path)
|
||||
if f.lower() == f"{wmclass.lower()}.desktop"]
|
||||
|
||||
exact_matches = [
|
||||
f for f in os.listdir(path) if f.lower() == f"{wmclass.lower()}.desktop"
|
||||
]
|
||||
|
||||
# Then try starts with
|
||||
startswith_matches = [f for f in os.listdir(path)
|
||||
if f.startswith(wmclass.lower()) and f.endswith('.desktop')]
|
||||
|
||||
startswith_matches = [
|
||||
f
|
||||
for f in os.listdir(path)
|
||||
if f.startswith(wmclass.lower()) and f.endswith(".desktop")
|
||||
]
|
||||
|
||||
# Finally try contains
|
||||
contains_matches = [f for f in os.listdir(path)
|
||||
if wmclass.lower() in f.lower() and f.endswith('.desktop')]
|
||||
|
||||
contains_matches = [
|
||||
f
|
||||
for f in os.listdir(path)
|
||||
if wmclass.lower() in f.lower() and f.endswith(".desktop")
|
||||
]
|
||||
|
||||
# Process matches in order of preference
|
||||
for matches in [exact_matches, startswith_matches, contains_matches]:
|
||||
for filename in matches:
|
||||
desktop_file = os.path.join(path, filename)
|
||||
try:
|
||||
with open(desktop_file, 'r', encoding='utf-8') as f:
|
||||
with open(desktop_file, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
|
||||
name = wmclass.title()
|
||||
version = ""
|
||||
comment = ""
|
||||
icon = wmclass.lower()
|
||||
exec_cmd = ""
|
||||
categories = ""
|
||||
|
||||
|
||||
# Parse desktop file
|
||||
in_desktop_entry = False
|
||||
for line in content.split('\n'):
|
||||
for line in content.split("\n"):
|
||||
line = line.strip()
|
||||
if line == '[Desktop Entry]':
|
||||
if line == "[Desktop Entry]":
|
||||
in_desktop_entry = True
|
||||
continue
|
||||
elif line.startswith('[') and line.endswith(']'):
|
||||
elif line.startswith("[") and line.endswith("]"):
|
||||
in_desktop_entry = False
|
||||
continue
|
||||
|
||||
if not in_desktop_entry or '=' not in line:
|
||||
|
||||
if not in_desktop_entry or "=" not in line:
|
||||
continue
|
||||
|
||||
key, value = line.split('=', 1)
|
||||
if key == 'Name':
|
||||
|
||||
key, value = line.split("=", 1)
|
||||
if key == "Name":
|
||||
name = value
|
||||
elif key == 'Version':
|
||||
elif key == "Version":
|
||||
version = value
|
||||
elif key == 'Comment':
|
||||
elif key == "Comment":
|
||||
comment = value
|
||||
elif key == 'GenericName' and not comment:
|
||||
elif key == "GenericName" and not comment:
|
||||
# Use GenericName as fallback description
|
||||
comment = value
|
||||
elif key == 'Icon':
|
||||
elif key == "Icon":
|
||||
icon = value
|
||||
elif key == 'Exec':
|
||||
elif key == "Exec":
|
||||
exec_cmd = value
|
||||
elif key == 'Categories':
|
||||
elif key == "Categories":
|
||||
categories = value
|
||||
|
||||
|
||||
# Get executable location
|
||||
location = get_executable_path(exec_cmd)
|
||||
|
||||
|
||||
return {
|
||||
"name": name,
|
||||
"version": version,
|
||||
@@ -179,20 +186,22 @@ def get_app_info(wmclass):
|
||||
"exec": exec_cmd,
|
||||
"location": location or "",
|
||||
"categories": categories,
|
||||
"desktop_file": desktop_file
|
||||
"desktop_file": desktop_file,
|
||||
}
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
|
||||
# Fallback: try to find executable in PATH
|
||||
location = ""
|
||||
try:
|
||||
result = subprocess.run(['which', wmclass.lower()], capture_output=True, text=True)
|
||||
result = subprocess.run(
|
||||
["which", wmclass.lower()], capture_output=True, text=True
|
||||
)
|
||||
if result.returncode == 0:
|
||||
location = result.stdout.strip()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
return {
|
||||
"name": wmclass.title() if wmclass else "Unknown Application",
|
||||
"version": "",
|
||||
@@ -201,7 +210,7 @@ def get_app_info(wmclass):
|
||||
"exec": "",
|
||||
"location": location,
|
||||
"categories": "",
|
||||
"desktop_file": ""
|
||||
"desktop_file": "",
|
||||
}
|
||||
|
||||
|
||||
@@ -211,9 +220,9 @@ class AboutApp(Gtk.Window):
|
||||
self.app_name = app_name
|
||||
self.wmclass = wmclass
|
||||
self.icon_resolver = IconResolver()
|
||||
|
||||
self.set_default_size(400, 500)
|
||||
self.set_size_request(400, 480)
|
||||
|
||||
self.set_default_size(300, 500)
|
||||
self.set_size_request(300, 480)
|
||||
self.set_resizable(False)
|
||||
self.set_title(f"About {app_name}")
|
||||
self.set_name("about-app")
|
||||
@@ -223,12 +232,12 @@ class AboutApp(Gtk.Window):
|
||||
|
||||
def setup_ui(self):
|
||||
app_info = get_app_info(self.wmclass)
|
||||
|
||||
|
||||
main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
|
||||
main_box.set_margin_top(20)
|
||||
main_box.set_margin_bottom(20)
|
||||
main_box.set_margin_start(25)
|
||||
main_box.set_margin_end(25)
|
||||
main_box.set_margin_start(15)
|
||||
main_box.set_margin_end(15)
|
||||
|
||||
# App Icon
|
||||
logo_box = Gtk.Box(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER)
|
||||
@@ -242,7 +251,9 @@ class AboutApp(Gtk.Window):
|
||||
except Exception:
|
||||
# Fallback: try direct file path if it's an absolute path
|
||||
try:
|
||||
if app_info["icon"].startswith('/') and os.path.exists(app_info["icon"]):
|
||||
if app_info["icon"].startswith("/") and os.path.exists(
|
||||
app_info["icon"]
|
||||
):
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
||||
app_info["icon"], 128, 128, preserve_aspect_ratio=True
|
||||
)
|
||||
@@ -253,25 +264,28 @@ class AboutApp(Gtk.Window):
|
||||
# Final fallback: emoji
|
||||
logo = Gtk.Label()
|
||||
logo.set_markup("<span size='72000'>📱</span>")
|
||||
|
||||
|
||||
logo_box.pack_start(logo, False, False, 0)
|
||||
logo_box.set_margin_bottom(15)
|
||||
|
||||
# App Name
|
||||
app_name_label = Gtk.Label()
|
||||
app_name_label.set_markup(f"<b><span size='18000'>{app_info['name']}</span></b>")
|
||||
app_name_label.set_markup(
|
||||
f"<b><span size='18000'>{app_info['name']}</span></b>"
|
||||
)
|
||||
app_name_label.set_halign(Gtk.Align.CENTER)
|
||||
app_name_label.set_margin_bottom(5)
|
||||
|
||||
# Version (if available)
|
||||
version_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||
if app_info["version"]:
|
||||
version_label = Gtk.Label(label=f"Version {app_info['version']}")
|
||||
version_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||
version_label = Gtk.Label(
|
||||
label=f"Version {app_info.get('version', 'Unknown')}"
|
||||
)
|
||||
version_label.set_name("version-label")
|
||||
version_label.set_halign(Gtk.Align.CENTER)
|
||||
version_box.pack_start(version_label, False, False, 0)
|
||||
|
||||
version_box.set_margin_bottom(15)
|
||||
version_box.set_margin_bottom(5)
|
||||
|
||||
# Description/Comment - Make it more prominent
|
||||
description_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||
@@ -279,9 +293,9 @@ class AboutApp(Gtk.Window):
|
||||
# Create a frame for the description to make it stand out
|
||||
desc_frame = Gtk.Frame()
|
||||
desc_frame.set_shadow_type(Gtk.ShadowType.IN)
|
||||
|
||||
|
||||
description_label = Gtk.Label()
|
||||
description_label.set_markup(f"<i>{app_info['comment']}</i>")
|
||||
description_label.set_markup(f"<i><b>{app_info['comment']}</b></i>")
|
||||
description_label.set_justify(Gtk.Justification.CENTER)
|
||||
description_label.set_halign(Gtk.Align.CENTER)
|
||||
description_label.set_line_wrap(True)
|
||||
@@ -290,23 +304,30 @@ class AboutApp(Gtk.Window):
|
||||
description_label.set_margin_bottom(8)
|
||||
description_label.set_margin_start(12)
|
||||
description_label.set_margin_end(12)
|
||||
|
||||
|
||||
desc_frame.add(description_label)
|
||||
description_box.pack_start(desc_frame, False, False, 0)
|
||||
else:
|
||||
# Show a placeholder if no description is available
|
||||
placeholder_label = Gtk.Label()
|
||||
placeholder_label.set_markup("<i><span foreground='#888888'>No description available</span></i>")
|
||||
placeholder_label.set_markup(
|
||||
"<i><span foreground='#888888'>No description available</span></i>"
|
||||
)
|
||||
placeholder_label.set_halign(Gtk.Align.CENTER)
|
||||
description_box.pack_start(placeholder_label, False, False, 0)
|
||||
|
||||
|
||||
description_box.set_margin_bottom(15)
|
||||
|
||||
# Information Grid
|
||||
# Create a label with markup
|
||||
info_frame = Gtk.Frame()
|
||||
info_frame.set_label("Application Information")
|
||||
label = Gtk.Label()
|
||||
label.set_markup("<b><u>Application Information</u></b>")
|
||||
label.set_margin_bottom(5)
|
||||
info_frame.set_label_widget(label)
|
||||
|
||||
info_frame.set_label_align(0.5, 0.5)
|
||||
|
||||
|
||||
info_grid = Gtk.Grid()
|
||||
info_grid.set_row_spacing(8)
|
||||
info_grid.set_column_spacing(15)
|
||||
@@ -315,50 +336,51 @@ class AboutApp(Gtk.Window):
|
||||
info_grid.set_margin_start(15)
|
||||
info_grid.set_margin_end(15)
|
||||
info_grid.set_valign(Gtk.Align.CENTER)
|
||||
info_grid.set_halign(Gtk.Align.FILL)
|
||||
info_grid.set_halign(Gtk.Align.CENTER)
|
||||
|
||||
def make_info_row(label_text, value_text, row):
|
||||
"""Create a row in the info grid"""
|
||||
label = Gtk.Label(label=f"{label_text}:")
|
||||
label.set_halign(Gtk.Align.END)
|
||||
label.set_markup(f"<b>{label_text}:</b>")
|
||||
|
||||
value = Gtk.Label(label=value_text)
|
||||
|
||||
value = Gtk.Label()
|
||||
value.set_markup(f'<span foreground="#727272">{value_text}</span>')
|
||||
value.set_halign(Gtk.Align.START)
|
||||
value.set_line_wrap(True)
|
||||
value.set_max_width_chars(30)
|
||||
value.set_name("info-value-label")
|
||||
|
||||
|
||||
info_grid.attach(label, 0, row, 1, 1)
|
||||
info_grid.attach(value, 1, row, 1, 1)
|
||||
|
||||
row = 0
|
||||
|
||||
|
||||
# Application Name
|
||||
make_info_row("Name", app_info["name"], row)
|
||||
row += 1
|
||||
|
||||
|
||||
# Version
|
||||
if app_info["version"]:
|
||||
make_info_row("Version", app_info["version"], row)
|
||||
row += 1
|
||||
|
||||
|
||||
# Executable Location
|
||||
if app_info["location"]:
|
||||
make_info_row("Location", app_info["location"], row)
|
||||
row += 1
|
||||
|
||||
|
||||
# Window Class
|
||||
if self.wmclass:
|
||||
make_info_row("Window Class", self.wmclass, row)
|
||||
row += 1
|
||||
|
||||
|
||||
# Categories
|
||||
if app_info["categories"]:
|
||||
categories = app_info["categories"].replace(";", ", ").strip(", ")
|
||||
make_info_row("Categories", categories, row)
|
||||
row += 1
|
||||
|
||||
|
||||
# Desktop File
|
||||
if app_info["desktop_file"]:
|
||||
desktop_file_name = os.path.basename(app_info["desktop_file"])
|
||||
@@ -370,7 +392,8 @@ class AboutApp(Gtk.Window):
|
||||
# Layout
|
||||
main_box.pack_start(logo_box, False, False, 0)
|
||||
main_box.pack_start(app_name_label, False, False, 0)
|
||||
main_box.pack_start(version_box, False, False, 0)
|
||||
if app_info["version"]:
|
||||
main_box.pack_start(version_box, False, False, 0)
|
||||
main_box.pack_start(description_box, False, False, 0)
|
||||
main_box.pack_start(info_frame, False, False, 0)
|
||||
|
||||
|
||||
Reference in new issue
Block a user