Something went wrong. Try again.
A Material 3 inspired desktop shell for Niri and Hyprland created with Ignis.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130import refrom typing import Any, ClassVar
from ignis.base_widget import BaseWidgetfrom ignis.gobject import IgnisPropertyfrom ignis.services.applications import ApplicationsService
from ignis import utils, widgets
class AppIcon(widgets.Icon, BaseWidget): __gtype_name__ = "ExoAppIcon" __gproperties__: ClassVar[dict[str, Any]] = {**BaseWidget.gproperties}
def __init__(self, **kwargs): widgets.Icon.__init__(self) self._app = None self._app_id: str = None self._name: str = None self.icon_path: str = None self.applications = ApplicationsService.get_default()
self.get_icon()
BaseWidget.__init__(self, **kwargs)
def get_match_score(self, app, app_id: str) -> int: if not app or not app_id: return 0
app_id_lower = app_id.lower() app_id_from_app_lower = app.id.lower()
if app_id_lower == app_id_from_app_lower: return 400
if app_id_lower in app_id_from_app_lower or app_id_from_app_lower in app_id_lower: return 300
score = 0 app_name_lower = "" if hasattr(app, 'name') and app.name: app_name_lower = app.name.lower() if app_id_lower == app_name_lower: score = 200
app_id_tokens = set(re.split(r'[._-]', app_id_lower)) app_id_from_app_tokens = set(re.split(r'[._-]', app_id_from_app_lower)) id_intersection = app_id_tokens.intersection(app_id_from_app_tokens) id_union = app_id_tokens.union(app_id_from_app_tokens) if id_union: id_jaccard_score = int(100 * len(id_intersection) / len(id_union)) score = max(score, id_jaccard_score)
if app_name_lower: app_name_tokens = set(re.split(r'[._-]', app_name_lower)) name_intersection = app_id_tokens.intersection(app_name_tokens) name_union = app_id_tokens.union(app_name_tokens) if name_union: name_jaccard_score = int(100 * len(name_intersection) / len(name_union)) score = max(score, name_jaccard_score)
return score
def get_icon(self): FALLBACK_ICON = "application-x-executable-symbolic"
if self._app: self.icon_path = self._app.icon or FALLBACK_ICON else: self.icon_path = None if self._app_id: self.icon_path = utils.get_app_icon_name(self._app_id) or None if not self.icon_path and self._name: self.icon_path = utils.get_app_icon_name(self._name) or None
if not self.icon_path and (self._app_id or self._name): best_match = None highest_score = 0 for app in self.applications.apps: score = 0 if self._name: score = self.get_match_score(app, self._name) if self._app_id: score = max(score, self.get_match_score(app, self._app_id))
if score > highest_score: highest_score = score best_match = app
if best_match: self.icon_path = best_match.icon if best_match.icon else FALLBACK_ICON
self.set_image(self.icon_path or "application-x-executable-symbolic")
@IgnisProperty def app(self): return self._app
@app.setter def app(self, value) -> None: if value == self._app: return self._app = value self.get_icon()
@IgnisProperty def app_id(self) -> str: return self._app_id
@app_id.setter def app_id(self, value: str) -> None: if value == self._app_id: return self._app_id = value self.get_icon()
@IgnisProperty def name(self) -> str: return self._name
@name.setter def name(self, value: str) -> None: if value == self._name: return self._name = value self.get_icon()