✨ feat(launcher): improve launcher experience with mouse tracking, application search, and visual enhancements

This commit is contained in:
sankalp committed 2025-08-03 07:48:33 +05:45
1 parent ac067abd0e
commit db210e2e6c
19 files changed
+513 -339

No files matched your search

+35 -7
View File
@@ -4,7 +4,6 @@ from typing import List
from fabric.utils import DesktopApp
from fabric.utils.helpers import get_desktop_applications, get_relative_path
from modules.dock import Dock
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
@@ -17,8 +16,7 @@ class ApplicationsPlugin(PluginBase):
self.description = "Search and launch desktop applications"
def initialize(self):
# Set up triggers for applications - both with and without spaces
self.set_triggers(["app"])
pass
def cleanup(self):
pass
@@ -71,9 +69,8 @@ class ApplicationsPlugin(PluginBase):
def query(self, query_string: str) -> List[Result]:
"""Search applications based on query."""
if not query_string.strip():
return []
return self._get_all_applications()
# Get fresh applications list each time (like examples/app-launcher)
try:
applications = get_desktop_applications(include_hidden=False)
except Exception as e:
@@ -86,9 +83,8 @@ class ApplicationsPlugin(PluginBase):
for app in applications:
relevance = self._calculate_relevance(app, query)
if relevance > 0:
# Truncate description to prevent overflow beyond 550px window
description = app.description or app.generic_name or ""
if len(description) > 80: # Limit to ~80 characters to fit in 550px
if len(description) > 80:
description = description[:70] + "..."
result = Result(
@@ -161,3 +157,35 @@ class ApplicationsPlugin(PluginBase):
def _launch_application(self, app: DesktopApp):
app.launch()
def _get_all_applications(self) -> List[Result]:
"""Get a list of all available applications."""
try:
applications = get_desktop_applications(include_hidden=False)
except Exception as e:
print(f"Failed to load applications: {e}")
return []
results = []
for app in applications:
# Truncate description
description = app.description or app.generic_name or ""
if len(description) > 80:
description = description[:70] + "..."
result = Result(
title=app.display_name or app.name,
subtitle=description,
icon=app.get_icon_pixbuf(size=48),
action=lambda a=app: self._launch_application(a),
relevance=0.5, # Default relevance for all apps
plugin_name=self.display_name,
data={
"app": app,
"pin_action": lambda a=app: self._pin_application(a),
},
)
results.append(result)
return results
+22 -20
View File
@@ -4,10 +4,8 @@ import threading
import time
from typing import Dict, List
from fabric.utils import exec_shell_command_async
import config.data as data
import utils.icons as icons
from fabric.utils import exec_shell_command_async
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
@@ -38,17 +36,17 @@ class BashScriptsPlugin(PluginBase):
"pm balanced": {
"description": "Switch to balanced power profile",
"profile": "balanced",
"icon": icons.power_balanced,
"icon": "power-balanced",
},
"pm performance": {
"description": "Switch to performance power profile",
"profile": "performance",
"icon": icons.power_performance,
"icon": "power-performance",
},
"pm saver": {
"description": "Switch to power saver profile",
"profile": "power-saver",
"icon": icons.power_saving,
"icon": "power-saving",
},
}
@@ -134,12 +132,16 @@ class BashScriptsPlugin(PluginBase):
if actual_profile:
self._battery_service._profile_proxy.ActiveProfile = actual_profile
print(
f"BashScriptsPlugin: Successfully set power profile to {actual_profile}"
f"BashScriptsPlugin: Successfully set power profile to {
actual_profile
}"
)
return True
else:
print(
f"BashScriptsPlugin: No matching profile found for '{profile}' in available profiles: {available_profiles}"
f"BashScriptsPlugin: No matching profile found for '{
profile
}' in available profiles: {available_profiles}"
)
return False
@@ -186,7 +188,6 @@ class BashScriptsPlugin(PluginBase):
current_time - self._last_cache_update > self._cache_update_interval
or not self._scripts_cache
):
if not self._cache_building:
self._cache_building = True
self._cache_thread = threading.Thread(
@@ -197,7 +198,6 @@ class BashScriptsPlugin(PluginBase):
def _build_scripts_cache_background(self):
"""Build scripts cache in background thread."""
try:
new_cache = {}
# Scan Modus scripts directory for discovered scripts
@@ -208,7 +208,9 @@ class BashScriptsPlugin(PluginBase):
self._scan_directory_for_scripts(self.modus_scripts_dir, new_cache)
except (PermissionError, FileNotFoundError, OSError) as e:
print(
f"BashScriptsPlugin: Error scanning Modus scripts directory: {e}"
f"BashScriptsPlugin: Error scanning Modus scripts directory: {
e
}"
)
# Update cache atomically
@@ -423,13 +425,12 @@ class BashScriptsPlugin(PluginBase):
or query_lower in cmd_lower
or query_lower in description_lower
):
relevance = 1.0 if query_lower == cmd_lower else 0.9
result = Result(
title=cmd,
subtitle=info["description"],
icon_markup=info["icon"],
icon_name=info["icon"],
action=self._create_power_action(info["profile"]),
relevance=relevance,
plugin_name=self.display_name,
@@ -451,7 +452,7 @@ class BashScriptsPlugin(PluginBase):
result = Result(
title=cmd,
subtitle=info["description"],
icon_markup=info["icon"],
icon_name=info["icon"],
action=self._create_power_action(info["profile"]),
relevance=0.8,
plugin_name=self.display_name,
@@ -473,9 +474,10 @@ class BashScriptsPlugin(PluginBase):
if success:
# Clear the search query after successful execution
try:
from fabric import Application
from gi.repository import GLib
from fabric import Application
app = Application.get_default()
if app and hasattr(app, "launcher"):
launcher = app.launcher
@@ -517,16 +519,16 @@ class BashScriptsPlugin(PluginBase):
# Choose icon based on script type and status
if not executable:
icon_markup = icons.file
icon_name = "gtk-file"
elif script_type == "custom":
icon_markup = icons.star
icon_name = "folder-script-symbolic"
else:
icon_markup = icons.terminal
icon_name = "terminalc"
return Result(
title=script_name,
subtitle=subtitle,
icon_markup=icon_markup,
icon_name=icon_name,
action=self._create_script_action(script_name, script_info),
relevance=relevance,
plugin_name=self.display_name,
@@ -556,7 +558,7 @@ class BashScriptsPlugin(PluginBase):
variant_result = Result(
title=f"{script_name} {arg}",
subtitle=f"{desc} | [scripts]",
icon_markup=icons.terminal,
icon_name="terminal-symbolic",
action=self._create_script_action_with_args(
script_name, script_info, [arg]
),
+19 -19
View File
@@ -6,10 +6,9 @@ from pathlib import Path
from typing import Dict, List, Optional
from urllib.parse import urlparse
from fabric.utils.helpers import get_relative_path
from thefuzz import fuzz
import utils.icons as icons
from fabric.utils.helpers import get_relative_path
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
@@ -268,7 +267,7 @@ class BookmarksPlugin(PluginBase):
Result(
title="No Bookmarks Found",
subtitle="Use 'add <title> <url>' to add first bookmark",
icon_markup=icons.info,
icon_name="info",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -298,7 +297,7 @@ class BookmarksPlugin(PluginBase):
Result(
title="No Bookmarks Yet",
subtitle="Use 'add <title> <url>' to add first bookmark",
icon_markup=icons.info,
icon_name="info",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -307,7 +306,7 @@ class BookmarksPlugin(PluginBase):
Result(
title="Example: Add Google",
subtitle="add Google https://google.com",
icon_markup=icons.bulb,
icon_name="info",
action=lambda: None,
relevance=0.9,
plugin_name=self.display_name,
@@ -334,7 +333,7 @@ class BookmarksPlugin(PluginBase):
Result(
title="Add Bookmark",
subtitle="Usage: add <title> <url> [description]",
icon_markup=icons.info,
icon_name="info",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -343,7 +342,7 @@ class BookmarksPlugin(PluginBase):
Result(
title="Example",
subtitle="add Google https://google.com Search engine",
icon_markup=icons.bulb,
icon_name="info",
action=lambda: None,
relevance=0.9,
plugin_name=self.display_name,
@@ -358,7 +357,7 @@ class BookmarksPlugin(PluginBase):
Result(
title="Invalid Format",
subtitle="Usage: add <title> <url> [description]",
icon_markup=icons.alert,
icon_name="alert",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -387,7 +386,7 @@ class BookmarksPlugin(PluginBase):
Result(
title="Bookmark Already Exists",
subtitle=f"URL '{display_url}' already exists",
icon_markup=icons.alert,
icon_name="alert",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -407,7 +406,7 @@ class BookmarksPlugin(PluginBase):
# Truncate description to prevent launcher resize
max_desc_len = 35 - len(domain) # Account for domain + separator
if len(description) > max_desc_len:
description = description[:max_desc_len-3] + "..."
description = description[: max_desc_len - 3] + "..."
subtitle += f" • {description}"
# Truncate title for display
@@ -419,7 +418,7 @@ class BookmarksPlugin(PluginBase):
Result(
title=f"Add bookmark '{display_title}'",
subtitle=subtitle,
icon_markup=icons.plus,
icon_name="plus",
action=lambda: self._add_bookmark_action(title, url, description),
relevance=1.0,
plugin_name=self.display_name,
@@ -451,7 +450,7 @@ class BookmarksPlugin(PluginBase):
Result(
title="Bookmark Not Found",
subtitle=f"No bookmark found matching '{identifier}'",
icon_markup=icons.alert,
icon_name="alert",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -477,7 +476,7 @@ class BookmarksPlugin(PluginBase):
Result(
title=f"Remove '{display_title}'?",
subtitle=f"Click to confirm: {display_domain}",
icon_markup=icons.trash,
icon_name="trash",
action=lambda: self._remove_bookmark_action(identifier),
relevance=1.0,
plugin_name=self.display_name,
@@ -492,7 +491,7 @@ class BookmarksPlugin(PluginBase):
Result(
title="Remove Bookmark",
subtitle="Usage: remove <title|url|domain>",
icon_markup=icons.info,
icon_name="info",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -506,7 +505,7 @@ class BookmarksPlugin(PluginBase):
Result(
title="Available Bookmarks:",
subtitle=f"{len(bookmarks)} bookmarks available to remove",
icon_markup=icons.bookmark,
icon_name="bookmarks-organize",
action=lambda: None,
relevance=0.9,
plugin_name=self.display_name,
@@ -532,7 +531,7 @@ class BookmarksPlugin(PluginBase):
Result(
title=f"remove {display_title}",
subtitle=f"Click to remove: {display_title} ({display_domain})",
icon_markup=icons.trash,
icon_name="trash",
action=lambda t=title: self._remove_bookmark_action(t),
relevance=0.8,
plugin_name=self.display_name,
@@ -643,9 +642,10 @@ class BookmarksPlugin(PluginBase):
if description:
# Truncate description to prevent launcher resize
max_desc_len = 50 - len(domain) # Account for domain + separator
# Account for domain + separator
max_desc_len = 50 - len(domain)
if len(description) > max_desc_len:
description = description[:max_desc_len-3] + "..."
description = description[: max_desc_len - 3] + "..."
subtitle = f"{domain} • {description}"
else:
subtitle = domain
@@ -657,7 +657,7 @@ class BookmarksPlugin(PluginBase):
return Result(
title=title,
subtitle=subtitle,
icon_markup=icons.bookmark,
icon_name="bookmark-organize",
action=lambda u=url: self._open_bookmark(u),
relevance=relevance,
plugin_name=self.display_name,
+4 -5
View File
@@ -3,11 +3,10 @@ from threading import Timer
from typing import List
import gi
from fabric.utils import get_relative_path
from fabric.utils.helpers import exec_shell_command_async
import config.data as data
import utils.icons as icons
from fabric.utils import get_relative_path
from fabric.utils.helpers import exec_shell_command_async
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
@@ -173,7 +172,7 @@ class CaffeinePlugin(PluginBase):
result = Result(
title=f"Custom: {query}",
subtitle="Set custom duration",
icon_markup=icons.coffee,
icon_name="caffeine",
action=self._create_inhibit_action(query),
relevance=1.0,
plugin_name=self.display_name,
@@ -194,7 +193,7 @@ class CaffeinePlugin(PluginBase):
result = Result(
title=description,
subtitle=subtitle,
icon_markup=icons.coffee,
icon_name="caffeine",
action=self._create_inhibit_action(duration),
relevance=0.9 if query == duration else 0.7,
plugin_name=self.display_name,
+3 -4
View File
@@ -4,7 +4,6 @@ import subprocess
import time
from typing import List
import utils.icons as icons
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
from utils.conversion import Conversion
@@ -99,7 +98,7 @@ class CalculatorPlugin(PluginBase):
Result(
title=f"{result:.6g} {to_unit}",
subtitle=subtitle,
icon_markup=icons.calculator,
icon_name="calculator-symbolic",
action=lambda r=f"{result:.6g}": self._copy_to_clipboard(r),
relevance=1.0,
plugin_name=self.display_name,
@@ -111,7 +110,7 @@ class CalculatorPlugin(PluginBase):
Result(
title="Invalid conversion",
subtitle=str(e),
icon_markup=icons.calculator,
icon_name="calculator-symbolic",
relevance=0.0,
plugin_name=self.display_name,
)
@@ -127,7 +126,7 @@ class CalculatorPlugin(PluginBase):
Result(
title=f"{result:.6g}",
subtitle=f"{query} = {result:.6g}",
icon_markup=icons.calculator,
icon_name="calculator-symbolic",
action=lambda r=f"{result:.6g}": self._copy_to_clipboard(r),
relevance=1.0,
plugin_name=self.display_name,
+1 -2
View File
@@ -5,9 +5,8 @@ import time
from collections import OrderedDict
from typing import Dict, List
from fabric.utils import get_relative_path
import config.data as data
from fabric.utils import get_relative_path
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
+27 -29
View File
@@ -6,8 +6,6 @@ from pathlib import Path
from typing import Dict, List, Optional
from fabric.utils import get_relative_path
import utils.icons as icons
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
from services.auth import (
@@ -354,7 +352,7 @@ class OTPPlugin(PluginBase):
Result(
title="Invalid format",
subtitle="Usage: add <account_name> <secret> or add <account_name>```<secret>```",
icon_markup=icons.question,
icon_name="info",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -373,7 +371,7 @@ class OTPPlugin(PluginBase):
Result(
title="Error adding account",
subtitle=f"Debug: {str(e)}",
icon_markup=icons.cancel,
icon_name="cancel",
action=lambda: None,
relevance=0.5,
plugin_name=self.display_name,
@@ -390,7 +388,7 @@ class OTPPlugin(PluginBase):
Result(
title="No OTP accounts configured",
subtitle="Use 'add <account> <secret>' to add your first account",
icon_markup=icons.key,
icon_name="gtk-authentication-symbolic",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -401,7 +399,7 @@ class OTPPlugin(PluginBase):
Result(
title="Available commands:",
subtitle="add <account> <secret> | remove <account> | qr <account>",
icon_markup=icons.info,
icon_name="info",
action=lambda: None,
relevance=0.9,
plugin_name=self.display_name,
@@ -425,7 +423,7 @@ class OTPPlugin(PluginBase):
subtitle_markup=f"{display_name} • {
time_display
} remaining • Shift+Enter: remove",
icon_markup=icons.key,
icon_name="gtk-authentication-symbolic",
action=lambda code=totp_code: self._copy_to_clipboard(code),
relevance=1.0,
plugin_name=self.display_name,
@@ -444,7 +442,7 @@ class OTPPlugin(PluginBase):
Result(
title=f"Error: {account_name}",
subtitle="Invalid secret or configuration",
icon_markup=icons.cancel,
icon_name="dialog-cancel-symbolic",
action=lambda: None,
relevance=0.5,
plugin_name=self.display_name,
@@ -485,7 +483,7 @@ class OTPPlugin(PluginBase):
subtitle_markup=f"{display_name} • {
time_display
} remaining • Shift+Enter: remove",
icon_markup=icons.key,
icon_name="gtk-authentication-symbolic",
action=lambda code=totp_code: self._copy_to_clipboard(code),
relevance=1.0,
plugin_name=self.display_name,
@@ -505,7 +503,7 @@ class OTPPlugin(PluginBase):
Result(
title=f"No accounts found for '{query}'",
subtitle="Use 'add <account> <secret>' to create new account",
icon_markup=icons.magnifier,
icon_name="edit-find-symbolic",
action=lambda: None,
relevance=0.5,
plugin_name=self.display_name,
@@ -516,7 +514,7 @@ class OTPPlugin(PluginBase):
Result(
title="Available commands:",
subtitle="add <account> <secret> | remove <account> | qr <account>",
icon_markup=icons.info,
icon_name="info",
action=lambda: None,
relevance=0.4,
plugin_name=self.display_name,
@@ -533,7 +531,7 @@ class OTPPlugin(PluginBase):
Result(
title="Enter account name",
subtitle="Usage: add <account_name> <secret>",
icon_markup=icons.question,
icon_name="dialog-question-symbolic",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -545,7 +543,7 @@ class OTPPlugin(PluginBase):
Result(
title=f"To add '{account_name}':",
subtitle=f"Type: add {account_name} <secret>",
icon_markup=icons.bulb,
icon_name="info",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -558,7 +556,7 @@ class OTPPlugin(PluginBase):
Result(
title="Base32 Secret Format:",
subtitle="Example: add gmail JBSWY3DPEHPK3PXP",
icon_markup=icons.info,
icon_name="info",
action=lambda: None,
relevance=0.9,
plugin_name=self.display_name,
@@ -567,7 +565,7 @@ class OTPPlugin(PluginBase):
Result(
title="otpauth URI Format:",
subtitle="Example: add github otpauth://totp/GitHub:user?secret=JBSWY3DPEHPK3PXP",
icon_markup=icons.info,
icon_name="info",
action=lambda: None,
relevance=0.9,
plugin_name=self.display_name,
@@ -576,7 +574,7 @@ class OTPPlugin(PluginBase):
Result(
title="Remove Account:",
subtitle="Example: remove gmail",
icon_markup=icons.trash,
icon_name="trash",
action=lambda: None,
relevance=0.8,
plugin_name=self.display_name,
@@ -591,7 +589,7 @@ class OTPPlugin(PluginBase):
Result(
title="Scan QR Code",
subtitle="Click to scan QR code from screen",
icon_markup=icons.connect,
icon_name="view-barcode-qr-symbolic",
action=lambda: self._scan_qr_and_add_account(""),
relevance=1.0,
plugin_name=self.display_name,
@@ -600,7 +598,7 @@ class OTPPlugin(PluginBase):
Result(
title="QR Scan Instructions:",
subtitle="Use 'qr <account_name>' to specify account name",
icon_markup=icons.info,
icon_name="info",
action=lambda: None,
relevance=0.9,
plugin_name=self.display_name,
@@ -612,7 +610,7 @@ class OTPPlugin(PluginBase):
Result(
title=f"Scan QR Code for '{account_name}'",
subtitle="Click to scan QR code from screen",
icon_markup=icons.connect,
icon_name="view-barcode-qr-symbolic",
action=lambda name=account_name: self._scan_qr_and_add_account(
name
),
@@ -658,7 +656,7 @@ class OTPPlugin(PluginBase):
Result(
title="No OTP accounts to remove",
subtitle="Use 'add <account> <secret>' to add accounts first",
icon_markup=icons.info,
icon_name="info",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -670,7 +668,7 @@ class OTPPlugin(PluginBase):
Result(
title="Select account to remove:",
subtitle="Type: remove <account_name> to remove an account",
icon_markup=icons.trash,
icon_name="user-trash-symbolic",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -697,7 +695,7 @@ class OTPPlugin(PluginBase):
subtitle_markup=f"Press Enter to remove • {
time_display
} remaining",
icon_markup=icons.trash,
icon_name="user-trash-symbolic",
action=lambda acc=acc_name: self._remove_account_and_refresh(
acc
),
@@ -716,7 +714,7 @@ class OTPPlugin(PluginBase):
Result(
title=f"Error: {acc_name}",
subtitle="Press Enter to remove (Invalid secret)",
icon_markup=icons.trash,
icon_name="user-trash-symbolic",
action=lambda acc=acc_name: self._remove_account_and_refresh(
acc
),
@@ -738,7 +736,7 @@ class OTPPlugin(PluginBase):
Result(
title=f"Account '{account_name}' not found",
subtitle="Use 'remove' to see all available accounts",
icon_markup=icons.cancel,
icon_name="dialog-cancel-symbolic",
action=lambda: None,
relevance=0.5,
plugin_name=self.display_name,
@@ -756,7 +754,7 @@ class OTPPlugin(PluginBase):
Result(
title=f"Remove '{display_name}'?",
subtitle="Press Enter to confirm removal",
icon_markup=icons.trash,
icon_name="user-trash-symbolic",
action=lambda acc=account_name: self._remove_account_and_refresh(acc),
relevance=1.0,
plugin_name=self.display_name,
@@ -777,7 +775,7 @@ class OTPPlugin(PluginBase):
Result(
title="Invalid Base32 secret",
subtitle=result["error"],
icon_markup=icons.cancel,
icon_name="dialog-cancel-symbolic",
action=lambda: None,
relevance=0.5,
plugin_name=self.display_name,
@@ -800,7 +798,7 @@ class OTPPlugin(PluginBase):
subtitle=f"OTP account added successfully (secret: {
result['secret'][:4]
}...)",
icon_markup=icons.check,
icon_name="emblem-ok-symbolic",
action=lambda: self._trigger_refresh(),
relevance=1.0,
plugin_name=self.display_name,
@@ -817,7 +815,7 @@ class OTPPlugin(PluginBase):
Result(
title="Error parsing otpauth URI",
subtitle=result["error"],
icon_markup=icons.cancel,
icon_name="dialog-cancel-symbolic",
action=lambda: None,
relevance=0.5,
plugin_name=self.display_name,
@@ -843,7 +841,7 @@ class OTPPlugin(PluginBase):
Result(
title=f"✓ Added '{display_name}'",
subtitle="OTP account added from URI",
icon_markup=icons.check,
icon_name="emblem-ok-symbolic",
action=lambda: self._trigger_refresh(),
relevance=1.0,
plugin_name=self.display_name,
+11 -13
View File
@@ -8,8 +8,6 @@ from pathlib import Path
from typing import Dict, List, Optional
from fabric.utils import get_relative_path
import utils.icons as icons
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
@@ -242,7 +240,7 @@ class PasswordPlugin(PluginBase):
Result(
title="No passwords stored",
subtitle="Use 'pass add <name> <password>' to add your first password",
icon_markup=icons.key,
icon_name="password-symbolic",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -253,7 +251,7 @@ class PasswordPlugin(PluginBase):
Result(
title="Available commands:",
subtitle="add <name> <password> | remove <name> | <name> (to search)",
icon_markup=icons.info,
icon_name="info",
action=lambda: None,
relevance=0.9,
plugin_name=self.display_name,
@@ -284,7 +282,7 @@ class PasswordPlugin(PluginBase):
Result(
title=title,
subtitle=subtitle,
icon_markup=icons.key,
icon_name="key",
action=lambda n=name: self._copy_password_to_clipboard(n),
relevance=1.0,
plugin_name=self.display_name,
@@ -311,7 +309,7 @@ class PasswordPlugin(PluginBase):
Result(
title="Add Password - Invalid format",
subtitle="Usage: add <name> <password> [description]",
icon_markup=icons.cancel,
icon_name="cancel",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -330,7 +328,7 @@ class PasswordPlugin(PluginBase):
Result(
title=f"Update password for '{name}'?",
subtitle="Password already exists. Click to update it.",
icon_markup=icons.key,
icon_name="key",
action=lambda: self._add_password_action(
name, password, description, update=True
),
@@ -345,7 +343,7 @@ class PasswordPlugin(PluginBase):
title=f"Add password for '{name}'",
subtitle="Click to save password"
+ (f" | {description}" if description else ""),
icon_markup=icons.plus,
icon_name="plus",
action=lambda: self._add_password_action(
name, password, description
),
@@ -367,7 +365,7 @@ class PasswordPlugin(PluginBase):
Result(
title="Remove Password - Invalid format",
subtitle="Usage: remove <name>",
icon_markup=icons.cancel,
icon_name="cancel",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -383,7 +381,7 @@ class PasswordPlugin(PluginBase):
Result(
title=f"Password '{name}' not found",
subtitle="Check the name and try again",
icon_markup=icons.cancel,
icon_name="cancel",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -395,7 +393,7 @@ class PasswordPlugin(PluginBase):
Result(
title=f"Remove password '{name}'?",
subtitle="Click to confirm deletion (this cannot be undone)",
icon_markup=icons.trash,
icon_name="trash",
action=lambda: self._remove_password_action(name),
relevance=1.0,
plugin_name=self.display_name,
@@ -420,7 +418,7 @@ class PasswordPlugin(PluginBase):
Result(
title=f"No passwords found matching '{query}'",
subtitle="Try a different search term or use 'pass' to see all passwords",
icon_markup=icons.magnifier,
icon_name="magnifier",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -462,7 +460,7 @@ class PasswordPlugin(PluginBase):
Result(
title=title,
subtitle=subtitle,
icon_markup=icons.key,
icon_name="key",
action=lambda n=name: self._copy_password_to_clipboard(n),
relevance=get_relevance(name),
plugin_name=self.display_name,
+7 -9
View File
@@ -1,8 +1,6 @@
from typing import List
from fabric.utils import exec_shell_command_async
import utils.icons as icons
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
@@ -19,27 +17,27 @@ class PowerPlugin(PluginBase):
self.commands = {
"shutdown": {
"description": "Shutdown the system",
"icon": icons.shutdown,
"icon": "system-shutdown-symbolic",
"action": self.shutdown,
},
"restart": {
"description": "Restart the system",
"icon": icons.reboot,
"icon": "system-reboot-symbolic",
"action": self.restart,
},
"lock": {
"description": "Lock the screen",
"icon": icons.lock,
"icon": "system-lock-screen-symbolic",
"action": self.lock,
},
"suspend": {
"description": "Suspend the system",
"icon": icons.suspend,
"icon": "system-suspend-symbolic",
"action": self.suspend,
},
"logout": {
"description": "Logout from current session",
"icon": icons.logout,
"icon": "system-log-out-symbolic",
"action": self.logout,
},
}
@@ -63,7 +61,7 @@ class PowerPlugin(PluginBase):
result = Result(
title=cmd.capitalize(),
subtitle=info["description"],
icon_markup=info["icon"],
icon_name=info["icon"],
action=info["action"],
relevance=1.0,
plugin_name=self.display_name,
@@ -77,7 +75,7 @@ class PowerPlugin(PluginBase):
result = Result(
title=cmd.capitalize(),
subtitle=info["description"],
icon_markup=info["icon"],
icon_name=info["icon"],
action=info["action"],
relevance=1.0 if query == cmd else 0.7,
plugin_name=self.display_name,
+11 -12
View File
@@ -4,7 +4,6 @@ import threading
from datetime import datetime, timedelta
from typing import Dict, List, Optional
import utils.icons as icons
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
@@ -258,7 +257,7 @@ class RemindersPlugin(PluginBase):
subtitle=f"Active reminders: {
active_count
} | Usage: remind 5m Take a break",
icon_markup=icons.timer_on,
icon_name="alarm-timer",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -279,7 +278,7 @@ class RemindersPlugin(PluginBase):
Result(
title=example,
subtitle=desc,
icon_markup=icons.timer_on,
icon_name="alarm-timer",
action=lambda: None,
relevance=0.8,
plugin_name=self.display_name,
@@ -296,7 +295,7 @@ class RemindersPlugin(PluginBase):
Result(
title="No Active Reminders",
subtitle="Use 'remind 5m message' to set a reminder",
icon_markup=icons.timer_off,
icon_name="timer-off",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -314,7 +313,7 @@ class RemindersPlugin(PluginBase):
Result(
title=f"#{reminder.id}: {reminder.message}",
subtitle=f"In {time_remaining} (at {target_time})",
icon_markup=icons.timer_on,
icon_name="alarm-timer",
action=lambda rid=reminder.id: self._cancel_reminder(rid),
relevance=1.0,
plugin_name=self.display_name,
@@ -334,7 +333,7 @@ class RemindersPlugin(PluginBase):
Result(
title=f"Cancelled {count} Reminders",
subtitle="All active reminders have been cancelled",
icon_markup=icons.timer_off,
icon_name="timer-off",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -351,7 +350,7 @@ class RemindersPlugin(PluginBase):
Result(
title=f"Cancelled Reminder #{reminder_id}",
subtitle="Reminder has been cancelled",
icon_markup=icons.timer_off,
icon_name="timer-off",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -363,7 +362,7 @@ class RemindersPlugin(PluginBase):
Result(
title="Reminder Not Found",
subtitle=f"No reminder with ID #{reminder_id}",
icon_markup=icons.alert,
icon_name="alert",
action=lambda: None,
relevance=0.5,
plugin_name=self.display_name,
@@ -375,7 +374,7 @@ class RemindersPlugin(PluginBase):
Result(
title="Invalid Reminder ID",
subtitle="Please provide a valid reminder ID number",
icon_markup=icons.alert,
icon_name="alert",
action=lambda: None,
relevance=0.5,
plugin_name=self.display_name,
@@ -407,7 +406,7 @@ class RemindersPlugin(PluginBase):
subtitle=f"Will remind in {time_remaining} (at {
target_time_str
})",
icon_markup=icons.timer_on,
icon_name="alarm-timer",
action=lambda ts=time_str, msg=message: self._create_and_confirm_reminder(
ts, msg
),
@@ -425,7 +424,7 @@ class RemindersPlugin(PluginBase):
Result(
title="Time is in the Past",
subtitle="Please specify a future time",
icon_markup=icons.alert,
icon_name="alert",
action=lambda: None,
relevance=0.5,
plugin_name=self.display_name,
@@ -438,7 +437,7 @@ class RemindersPlugin(PluginBase):
Result(
title="Invalid Time Format",
subtitle="Use formats like: 5m, 30s, 2h, 14:30, or '5 minutes'",
icon_markup=icons.alert,
icon_name="alert",
action=lambda: None,
relevance=0.5,
plugin_name=self.display_name,
+74 -73
View File
@@ -2,10 +2,8 @@ import subprocess
from typing import List
from fabric.utils import get_relative_path
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
from utils.icons import screenrecord, screenshots, ssfull, ssregion, stop
class ScreencapturePlugin(PluginBase):
@@ -17,7 +15,6 @@ class ScreencapturePlugin(PluginBase):
super().__init__()
self.display_name = "Screencapture"
self.description = "Take screenshots and screen recordings"
# Path to the screen-capture script
self.script_path = get_relative_path("../../../scripts/screen-capture.sh")
def initialize(self):
@@ -121,290 +118,290 @@ class ScreencapturePlugin(PluginBase):
"screenshot": (
"Take Screenshot (eDP-1)",
"Capture the main display",
ssfull,
"camera-photo-symbolic",
lambda: self._run_script("screenshot", "eDP-1"),
),
"ss": (
"Take Screenshot (eDP-1)",
"Capture the main display",
ssfull,
"camera-photo-symbolic",
lambda: self._run_script("screenshot", "eDP-1"),
),
"screenshot-region": (
"Take Region Screenshot",
"Capture a selected region",
ssregion,
"camera-photo-symbolic",
lambda: self._run_script("screenshot", "selection"),
),
"ss-region": (
"Take Region Screenshot",
"Capture a selected region",
ssregion,
"camera-photo-symbolic",
lambda: self._run_script("screenshot", "selection"),
),
"screenshot-both": (
"Take Screenshot (Both Displays)",
"Capture both displays combined",
screenshots,
"video-joined-displays-symbolic",
lambda: self._run_script("screenshot", "both"),
),
"ss-both": (
"Take Screenshot (Both Displays)",
"Capture both displays combined",
screenshots,
"video-joined-displays-symbolic",
lambda: self._run_script("screenshot", "both"),
),
"screenshot-hdmi": (
"Take Screenshot (HDMI-A-1)",
"Capture HDMI display",
ssfull,
"video-display-symbolic",
lambda: self._run_script("screenshot", "HDMI-A-1"),
),
"ss-hdmi": (
"Take Screenshot (HDMI-A-1)",
"Capture HDMI display",
ssfull,
"video-display-symbolic",
lambda: self._run_script("screenshot", "HDMI-A-1"),
),
# Recording commands (with audio)
"record": (
"Start Recording (eDP-1)",
"Record the main display with audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record", "eDP-1"),
),
"rec": (
"Start Recording (eDP-1)",
"Record the main display with audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record", "eDP-1"),
),
"record-region": (
"Start Region Recording",
"Record a selected region with audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record", "selection"),
),
"rec-region": (
"Start Region Recording",
"Record a selected region with audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record", "selection"),
),
"record-hdmi": (
"Start Recording (HDMI-A-1)",
"Record HDMI display with audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record", "HDMI-A-1"),
),
"rec-hdmi": (
"Start Recording (HDMI-A-1)",
"Record HDMI display with audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record", "HDMI-A-1"),
),
# Recording commands (no audio)
"record-noaudio": (
"Start Recording No Audio (eDP-1)",
"Record the main display without audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-noaudio", "eDP-1"),
),
"rec-noaudio": (
"Start Recording No Audio (eDP-1)",
"Record the main display without audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-noaudio", "eDP-1"),
),
"record-noaudio-region": (
"Start Region Recording No Audio",
"Record a selected region without audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-noaudio", "selection"),
),
"rec-noaudio-region": (
"Start Region Recording No Audio",
"Record a selected region without audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-noaudio", "selection"),
),
"record-noaudio-hdmi": (
"Start Recording No Audio (HDMI-A-1)",
"Record HDMI display without audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-noaudio", "HDMI-A-1"),
),
"rec-noaudio-hdmi": (
"Start Recording No Audio (HDMI-A-1)",
"Record HDMI display without audio",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-noaudio", "HDMI-A-1"),
),
# High-quality recording commands
"record-hq": (
"Start HQ Recording (eDP-1)",
"High-quality recording for YouTube",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-hq", "eDP-1"),
),
"rec-hq": (
"Start HQ Recording (eDP-1)",
"High-quality recording for YouTube",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-hq", "eDP-1"),
),
"record-hq-region": (
"Start HQ Region Recording",
"High-quality region recording",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-hq", "selection"),
),
"rec-hq-region": (
"Start HQ Region Recording",
"High-quality region recording",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-hq", "selection"),
),
"record-hq-hdmi": (
"Start HQ Recording (HDMI-A-1)",
"High-quality HDMI recording",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-hq", "HDMI-A-1"),
),
"rec-hq-hdmi": (
"Start HQ Recording (HDMI-A-1)",
"High-quality HDMI recording",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-hq", "HDMI-A-1"),
),
# GIF recording commands
"record-gif": (
"Start GIF Recording (eDP-1)",
"Record as optimized GIF",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-gif", "eDP-1"),
),
"rec-gif": (
"Start GIF Recording (eDP-1)",
"Record as optimized GIF",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-gif", "eDP-1"),
),
"record-gif-region": (
"Start GIF Region Recording",
"Record selected region as GIF",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-gif", "selection"),
),
"rec-gif-region": (
"Start GIF Region Recording",
"Record selected region as GIF",
screenrecord,
"media-record-symbolic",
lambda: self._run_script("record-gif", "selection"),
),
# Control commands
"stop": (
"Stop Recording",
"Stop the current screen recording",
stop,
"media-playback-stop-symbolic",
lambda: self._run_script("record", "stop"),
),
# Conversion commands
"convert-webm": (
"Convert Latest to WebM",
"Convert latest MKV recording to WebM format",
screenrecord,
"video-x-generic-symbolic",
lambda: self._run_script("convert", "webm"),
),
"conv-webm": (
"Convert Latest to WebM",
"Convert latest MKV recording to WebM format",
screenrecord,
"video-x-generic-symbolic",
lambda: self._run_script("convert", "webm"),
),
"convert-iphone": (
"Convert Latest for iPhone",
"Convert latest MKV recording for iPhone compatibility",
screenrecord,
"video-x-generic-symbolic",
lambda: self._run_script("convert", "iphone"),
),
"conv-iphone": (
"Convert Latest for iPhone",
"Convert latest MKV recording for iPhone compatibility",
screenrecord,
"video-x-generic-symbolic",
lambda: self._run_script("convert", "iphone"),
),
"convert-youtube": (
"Convert Latest for YouTube",
"Convert latest recording for YouTube upload",
screenrecord,
"video-x-generic-symbolic",
lambda: self._run_script("convert", "youtube"),
),
"conv-youtube": (
"Convert Latest for YouTube",
"Convert latest recording for YouTube upload",
screenrecord,
"video-x-generic-symbolic",
lambda: self._run_script("convert", "youtube"),
),
"convert-gif": (
"Convert Latest to GIF",
"Convert latest recording to GIF format",
screenrecord,
"image-x-generic-symbolic",
lambda: self._run_script("convert", "gif"),
),
"conv-gif": (
"Convert Latest to GIF",
"Convert latest recording to GIF format",
screenrecord,
"image-x-generic-symbolic",
lambda: self._run_script("convert", "gif"),
),
# File-based conversion commands (these will be handled specially)
"convert-webm-file": (
"Convert File to WebM",
"Type filename after command (e.g., convert-webm-file video.mkv)",
screenrecord,
"video-x-generic-symbolic",
None, # Will be handled in query method
),
"conv-webm-file": (
"Convert File to WebM",
"Type filename after command (e.g., conv-webm-file video.mkv)",
screenrecord,
"video-x-generic-symbolic",
None, # Will be handled in query method
),
"convert-iphone-file": (
"Convert File for iPhone",
"Type filename after command (e.g., convert-iphone-file video.mkv)",
screenrecord,
"video-x-generic-symbolic",
None, # Will be handled in query method
),
"conv-iphone-file": (
"Convert File for iPhone",
"Type filename after command (e.g., conv-iphone-file video.mkv)",
screenrecord,
"video-x-generic-symbolic",
None, # Will be handled in query method
),
"convert-youtube-file": (
"Convert File for YouTube",
"Type filename after command (e.g., convert-youtube-file video.mkv)",
screenrecord,
"video-x-generic-symbolic",
None, # Will be handled in query method
),
"conv-youtube-file": (
"Convert File for YouTube",
"Type filename after command (e.g., conv-youtube-file video.mkv)",
screenrecord,
"video-x-generic-symbolic",
None, # Will be handled in query method
),
"convert-gif-file": (
"Convert File to GIF",
"Type filename after command (e.g., convert-gif-file video.mkv)",
screenrecord,
"image-x-generic-symbolic",
None, # Will be handled in query method
),
"conv-gif-file": (
"Convert File to GIF",
"Type filename after command (e.g., conv-gif-file video.mkv)",
screenrecord,
"image-x-generic-symbolic",
None, # Will be handled in query method
),
}
@@ -415,7 +412,7 @@ class ScreencapturePlugin(PluginBase):
return Result(
title=title,
subtitle=subtitle,
icon_markup=icon,
icon_name=icon,
action=action,
relevance=1.0,
plugin_name=self.display_name,
@@ -424,7 +421,7 @@ class ScreencapturePlugin(PluginBase):
return Result(
title=title,
subtitle=subtitle,
icon_markup=icon,
icon_name=icon,
action=lambda: None, # No action for instruction
relevance=1.0,
plugin_name=self.display_name,
@@ -465,7 +462,11 @@ class ScreencapturePlugin(PluginBase):
Result(
title=f"Convert {file_param} to {format_type.upper()}",
subtitle=f"Convert specified file to {format_type} format",
icon_markup=screenrecord,
icon_name=(
"video-x-generic-symbolic"
if format_type != "gif"
else "image-x-generic-symbolic"
),
action=lambda fp=file_param, ft=format_type: self._run_script_with_file(
ft, fp
),
@@ -488,7 +489,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Stop Recording",
subtitle="Stop the current screen recording",
icon_markup=stop,
icon_name="media-playback-stop-symbolic",
action=lambda: self._run_script("record", "stop"),
relevance=2.0, # Highest relevance to appear at top
plugin_name=self.display_name,
@@ -501,7 +502,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Take Screenshot",
subtitle="Capture the entire screen (eDP-1)",
icon_markup=ssfull,
icon_name="camera-photo-symbolic",
action=lambda: self._run_script("screenshot", "eDP-1"),
relevance=1.0,
plugin_name=self.display_name,
@@ -509,7 +510,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Take Region Screenshot",
subtitle="Capture a selected region",
icon_markup=ssregion,
icon_name="camera-photo-symbolic",
action=lambda: self._run_script("screenshot", "selection"),
relevance=0.9,
plugin_name=self.display_name,
@@ -517,7 +518,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Take Screenshot (Both Displays)",
subtitle="Capture both displays combined",
icon_markup=screenshots,
icon_name="video-joined-displays-symbolic",
action=lambda: self._run_script("screenshot", "both"),
relevance=0.8,
plugin_name=self.display_name,
@@ -525,7 +526,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Take Screenshot (HDMI-A-1)",
subtitle="Capture HDMI display",
icon_markup=ssfull,
icon_name="video-display-symbolic",
action=lambda: self._run_script("screenshot", "HDMI-A-1"),
relevance=0.7,
plugin_name=self.display_name,
@@ -539,7 +540,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Start Recording (eDP-1)",
subtitle="Record the main display with audio",
icon_markup=screenrecord,
icon_name="media-record-symbolic",
action=lambda: self._run_script("record", "eDP-1"),
relevance=0.7,
plugin_name=self.display_name,
@@ -547,7 +548,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Start Region Recording",
subtitle="Record a selected region",
icon_markup=screenrecord,
icon_name="media-record-symbolic",
action=lambda: self._run_script("record", "selection"),
relevance=0.6,
plugin_name=self.display_name,
@@ -555,7 +556,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Start Recording (HDMI-A-1)",
subtitle="Record HDMI display with audio",
icon_markup=screenrecord,
icon_name="media-record-symbolic",
action=lambda: self._run_script("record", "HDMI-A-1"),
relevance=0.5,
plugin_name=self.display_name,
@@ -569,7 +570,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Start Recording No Audio (eDP-1)",
subtitle="Record the main display without audio",
icon_markup=screenrecord,
icon_name="media-record-symbolic",
action=lambda: self._run_script("record-noaudio", "eDP-1"),
relevance=0.65,
plugin_name=self.display_name,
@@ -577,7 +578,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Start Region Recording No Audio",
subtitle="Record a selected region without audio",
icon_markup=screenrecord,
icon_name="media-record-symbolic",
action=lambda: self._run_script("record-noaudio", "selection"),
relevance=0.55,
plugin_name=self.display_name,
@@ -585,7 +586,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Start Recording No Audio (HDMI-A-1)",
subtitle="Record HDMI display without audio",
icon_markup=screenrecord,
icon_name="media-record-symbolic",
action=lambda: self._run_script("record-noaudio", "HDMI-A-1"),
relevance=0.45,
plugin_name=self.display_name,
@@ -599,7 +600,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Start HQ Recording (eDP-1)",
subtitle="High-quality recording for YouTube",
icon_markup=screenrecord,
icon_name="media-record-symbolic",
action=lambda: self._run_script("record-hq", "eDP-1"),
relevance=0.4,
plugin_name=self.display_name,
@@ -607,7 +608,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Start HQ Region Recording",
subtitle="High-quality region recording",
icon_markup=screenrecord,
icon_name="media-record-symbolic",
action=lambda: self._run_script("record-hq", "selection"),
relevance=0.3,
plugin_name=self.display_name,
@@ -615,7 +616,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Start HQ Recording (HDMI-A-1)",
subtitle="High-quality HDMI recording",
icon_markup=screenrecord,
icon_name="media-record-symbolic",
action=lambda: self._run_script("record-hq", "HDMI-A-1"),
relevance=0.2,
plugin_name=self.display_name,
@@ -629,7 +630,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Start GIF Recording (eDP-1)",
subtitle="Record as optimized GIF",
icon_markup=screenrecord,
icon_name="media-record-symbolic",
action=lambda: self._run_script("record-gif", "eDP-1"),
relevance=0.1,
plugin_name=self.display_name,
@@ -637,7 +638,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Start GIF Region Recording",
subtitle="Record selected region as GIF",
icon_markup=screenrecord,
icon_name="media-record-symbolic",
action=lambda: self._run_script("record-gif", "selection"),
relevance=0.05,
plugin_name=self.display_name,
@@ -651,7 +652,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Convert Latest to WebM",
subtitle="Convert latest MKV recording to WebM format",
icon_markup=screenrecord,
icon_name="video-x-generic-symbolic",
action=lambda: self._run_script("convert", "webm"),
relevance=0.01,
plugin_name=self.display_name,
@@ -659,7 +660,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Convert Latest for iPhone",
subtitle="Convert latest MKV recording for iPhone compatibility",
icon_markup=screenrecord,
icon_name="video-x-generic-symbolic",
action=lambda: self._run_script("convert", "iphone"),
relevance=0.01,
plugin_name=self.display_name,
@@ -667,7 +668,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Convert Latest for YouTube",
subtitle="Convert latest recording for YouTube upload",
icon_markup=screenrecord,
icon_name="video-x-generic-symbolic",
action=lambda: self._run_script("convert", "youtube"),
relevance=0.01,
plugin_name=self.display_name,
@@ -675,7 +676,7 @@ class ScreencapturePlugin(PluginBase):
Result(
title="Convert Latest to GIF",
subtitle="Convert latest recording to GIF format",
icon_markup=screenrecord,
icon_name="image-x-generic-symbolic",
action=lambda: self._run_script("convert", "gif"),
relevance=0.01,
plugin_name=self.display_name,
+2 -5
View File
@@ -5,10 +5,8 @@ import threading
import time
from typing import List, Set, Union
from fabric.utils import exec_shell_command_async
import config.data as data
import utils.icons as icons
from fabric.utils import exec_shell_command_async
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
@@ -91,7 +89,6 @@ class SystemPlugin(PluginBase):
current_time - self._last_bin_update > self._bin_update_interval
or not self._bin_cache
):
if not self._cache_building:
self._cache_building = True
self._cache_thread = threading.Thread(
@@ -213,7 +210,7 @@ class SystemPlugin(PluginBase):
result = Result(
title=display_command,
subtitle=f"Execute: {display_command}",
icon_markup=icons.terminal,
icon_name="terminal",
action=self._create_action(command_to_execute),
relevance=relevance,
plugin_name=self.display_name,
+13 -11
View File
@@ -3,10 +3,8 @@ import threading
import time
from typing import List
from fabric.utils import exec_shell_command_async
import config.data as data
import utils.icons as icons
from fabric.utils import exec_shell_command_async
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
@@ -24,13 +22,15 @@ class TmuxPlugin(PluginBase):
# Cache for sessions to avoid repeated subprocess calls
self._sessions_cache = []
self._last_cache_update = 0
self._cache_ttl = 10 # Cache sessions for 10 seconds (increased from 2)
# Cache sessions for 10 seconds (increased from 2)
self._cache_ttl = 10
# Threading for auto-refresh - only when actively used
self.refresh_thread = None
self.stop_refresh = threading.Event()
self._last_query_time = 0
self._active_refresh_timeout = 30 # Stop refreshing after 30 seconds of inactivity
# Stop refreshing after 30 seconds of inactivity
self._active_refresh_timeout = 30
def initialize(self):
"""Initialize the tmux plugin."""
@@ -67,7 +67,7 @@ class TmuxPlugin(PluginBase):
self._sessions_cache = self._get_tmux_sessions()
self._last_cache_update = current_time
self.stop_refresh.wait(5)
self.stop_refresh.wait(5)
except Exception as e:
print(f"TmuxPlugin: Error in refresh thread: {e}")
self.stop_refresh.wait(10) # Wait longer on error
@@ -166,7 +166,7 @@ class TmuxPlugin(PluginBase):
return Result(
title=f"Attach to '{session_name}'",
subtitle=f"Connect to tmux session: {session_name}",
icon_markup=icons.terminal,
icon_name="terminal",
action=lambda: self._attach_to_session(session_name),
relevance=0.9,
data={"type": "attach", "session": session_name},
@@ -177,8 +177,10 @@ class TmuxPlugin(PluginBase):
display_name = session_name if session_name else "new session"
return Result(
title=f"Create '{display_name}'",
subtitle=f"Create new tmux session{f': {session_name}' if session_name else ''}",
icon_markup=icons.plus,
subtitle=f"Create new tmux session{
f': {session_name}' if session_name else ''
}",
icon_name="plus",
action=lambda: self._create_session(session_name),
relevance=0.8,
data={"type": "create", "session": session_name},
@@ -189,7 +191,7 @@ class TmuxPlugin(PluginBase):
return Result(
title=f"Kill '{session_name}'",
subtitle=f"Terminate tmux session: {session_name}",
icon_markup=icons.trash,
icon_name="trash",
action=lambda: self._kill_session(session_name),
relevance=0.7,
data={"type": "kill", "session": session_name},
@@ -200,7 +202,7 @@ class TmuxPlugin(PluginBase):
return Result(
title=f"Rename '{old_name}' to '{new_name}'",
subtitle=f"Rename tmux session from {old_name} to {new_name}",
icon_markup=icons.config,
icon_name="config",
action=lambda: self._rename_session(old_name, new_name),
relevance=0.6,
data={"type": "rename", "old_session": old_name, "new_session": new_name},
+26 -54
View File
@@ -8,12 +8,11 @@ import threading
import time
from typing import Dict, List, Optional
from fabric.utils.helpers import exec_shell_command_async
from gi.repository import GdkPixbuf
from PIL import Image
import config.data as data
import utils.icons as icons
from fabric.utils.helpers import exec_shell_command_async
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
@@ -124,9 +123,10 @@ class WallpaperPlugin(PluginBase):
"""Clear the launcher search query and reset to trigger."""
try:
# Try to access the launcher through the fabric Application
from fabric import Application
from gi.repository import GLib
from fabric import Application
app = Application.get_default()
if app and hasattr(app, "launcher"):
@@ -467,16 +467,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Random Wallpaper{indicator_text}",
subtitle=f"Set a random wallpaper • {status_text}",
icon_markup=random.choice(
[
icons.dice_1,
icons.dice_2,
icons.dice_3,
icons.dice_4,
icons.dice_5,
icons.dice_6,
]
),
icon_name="media-playlist-shuffle-symbolic",
action=lambda: self._set_random_wallpaper(),
relevance=1.0,
plugin_name=self.display_name,
@@ -493,16 +484,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Random Wallpaper{indicator_text}",
subtitle=f"Set a random wallpaper • {status_text}",
icon_markup=random.choice(
[
icons.dice_1,
icons.dice_2,
icons.dice_3,
icons.dice_4,
icons.dice_5,
icons.dice_6,
]
),
icon_name="media-playlist-shuffle-symbolic",
action=lambda: self._set_random_wallpaper(),
relevance=0.9,
plugin_name=self.display_name,
@@ -552,10 +534,9 @@ class WallpaperPlugin(PluginBase):
subtitle=f"Apply with {scheme_name} scheme • {
status_text
}",
icon_markup=icons.palette,
action=lambda c=hex_color, s=scheme: self._apply_hex_color_direct(
c, s
),
icon_name="color-picker-symbolic",
action=lambda c=hex_color,
s=scheme: self._apply_hex_color_direct(c, s),
relevance=1.0,
plugin_name=self.display_name,
data={
@@ -575,7 +556,7 @@ class WallpaperPlugin(PluginBase):
indicator_text
}",
subtitle="Matugen is enabled • Disable matugen to use hex colors",
icon_markup=icons.palette,
icon_name="color-picker-symbolic",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -594,7 +575,7 @@ class WallpaperPlugin(PluginBase):
subtitle=f"Apply with {scheme_name} scheme • {
status_text
}",
icon_markup=icons.palette,
icon_name="color-picker-symbolic",
action=lambda c=hex_color, s=scheme: (
self._apply_hex_color_direct(c, s)
if not matugen_enabled
@@ -617,7 +598,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Hex Color (incomplete): {hex_color}",
subtitle="Complete the 6-digit hex color to apply",
icon_markup=icons.palette,
icon_name="color-picker-symbolic",
action=lambda: None,
relevance=0.7,
plugin_name=self.display_name,
@@ -647,7 +628,7 @@ class WallpaperPlugin(PluginBase):
subtitle=f"Generate and apply random color with {
scheme_name
} scheme • {status_text}",
icon_markup=icons.palette,
icon_name="color-picker-symbolic",
action=lambda s=scheme: self._apply_hex_color_direct(
self._generate_random_hex_color(), s
),
@@ -667,7 +648,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Cannot Apply Random Color{indicator_text}",
subtitle="Matugen is enabled • Disable matugen to use hex colors",
icon_markup=icons.palette,
icon_name="color-picker-symbolic",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -683,7 +664,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Random Hex Color{indicator_text}",
subtitle=f"Generate and apply random color • {status_text}",
icon_markup=icons.palette,
icon_name="color-picker-symbolic",
action=lambda s=scheme: (
self._apply_hex_color_direct(
self._generate_random_hex_color(), s
@@ -707,7 +688,7 @@ class WallpaperPlugin(PluginBase):
Result(
title="Hex Color Commands",
subtitle="Use: color #FF5733, hex #00FF00, color random",
icon_markup=icons.palette,
icon_name="color-picker-symbolic",
action=lambda: None,
relevance=0.8,
plugin_name=self.display_name,
@@ -761,7 +742,7 @@ class WallpaperPlugin(PluginBase):
if not matugen_enabled
else ""
),
icon_markup=icons.palette,
icon_name="color-management-symbolic",
action=lambda s=scheme_id: self._set_current_scheme(s),
relevance=1.0 if scheme_id == current_scheme else 0.8,
plugin_name=self.display_name,
@@ -785,7 +766,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Enable Matugen{indicator_text}",
subtitle=f"Turn on dynamic color generation • {status_text}",
icon_markup=icons.palette,
icon_name="color-management-symbolic",
action=lambda: self._set_matugen_state(True),
relevance=0.9,
plugin_name=self.display_name,
@@ -802,7 +783,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Disable Matugen{indicator_text}",
subtitle=f"Turn off dynamic color generation • {status_text}",
icon_markup=icons.palette,
icon_name="color-management-symbolic",
action=lambda: self._set_matugen_state(False),
relevance=0.9,
plugin_name=self.display_name,
@@ -824,7 +805,7 @@ class WallpaperPlugin(PluginBase):
subtitle=f"Switch matugen to {
'enabled' if new_state else 'disabled'
} • {status_text}",
icon_markup=icons.palette,
icon_name="color-management-symbolic",
action=lambda: self._set_matugen_state(new_state),
relevance=0.9,
plugin_name=self.display_name,
@@ -843,7 +824,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Enable Matugen{indicator_text}",
subtitle=f"Turn on dynamic color generation • {status_text}",
icon_markup=icons.palette,
icon_name="color-management-symbolic",
action=lambda: self._set_matugen_state(True),
relevance=0.8,
plugin_name=self.display_name,
@@ -862,7 +843,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Disable Matugen{indicator_text}",
subtitle=f"Turn off dynamic color generation • {status_text}",
icon_markup=icons.palette,
icon_name="color-management-symbolic",
action=lambda: self._set_matugen_state(False),
relevance=0.8,
plugin_name=self.display_name,
@@ -879,7 +860,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Toggle Matugen{indicator_text}",
subtitle=f"Switch matugen state • {status_text}",
icon_markup=icons.palette,
icon_name="color-management-symbolic",
action=lambda: self._set_matugen_state(not current_state),
relevance=0.8,
plugin_name=self.display_name,
@@ -898,7 +879,7 @@ class WallpaperPlugin(PluginBase):
indicator_text
}",
subtitle=f"Dynamic colors • {status_text}",
icon_markup=icons.palette,
icon_name="color-management-symbolic",
action=lambda: None,
relevance=0.8,
plugin_name=self.display_name,
@@ -912,7 +893,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Wallpaper System Status{indicator_text}",
subtitle=status_text,
icon_markup=icons.palette,
icon_name="color-management-symbolic",
action=lambda: None,
relevance=1.0,
plugin_name=self.display_name,
@@ -925,16 +906,7 @@ class WallpaperPlugin(PluginBase):
Result(
title=f"Random Wallpaper{indicator_text}",
subtitle=f"Set a random wallpaper • {status_text}",
icon_markup=random.choice(
[
icons.dice_1,
icons.dice_2,
icons.dice_3,
icons.dice_4,
icons.dice_5,
icons.dice_6,
]
),
icon_name="media-playlist-shuffle-symbolic",
action=lambda: self._set_random_wallpaper(),
relevance=0.9,
plugin_name=self.display_name,
@@ -981,7 +953,7 @@ class WallpaperPlugin(PluginBase):
' • ' + status_text if not query else ''
}",
icon=icon,
icon_markup=icons.wallpapers if not icon else None,
icon_name="image-x-generic-symbolic" if not icon else None,
action=lambda w=wallpaper: self._set_wallpaper(w),
relevance=relevance,
plugin_name=self.display_name,
+12 -13
View File
@@ -2,7 +2,6 @@ import subprocess
import urllib.parse
from typing import List
import utils.icons as icons
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
@@ -23,49 +22,49 @@ class WebSearchPlugin(PluginBase):
"google": {
"name": "Google",
"url": "https://www.google.com/search?q={}",
"icon": icons.google,
"icon": "google-symbolic",
"description": "Search with Google",
},
"duckduckgo": {
"name": "DuckDuckGo",
"url": "https://duckduckgo.com/?q={}",
"icon": icons.duckduckgo,
"icon": "preferences-desktop-search",
"description": "Search with DuckDuckGo (privacy-focused)",
},
"youtube": {
"name": "YouTube",
"url": "https://www.youtube.com/results?search_query={}",
"icon": icons.youtube,
"icon": "youtube-symbolic",
"description": "Search videos on YouTube",
},
"github": {
"name": "GitHub",
"url": "https://github.com/search?q={}",
"icon": icons.github,
"icon": "github-desktop-symbolic",
"description": "Search repositories on GitHub",
},
"stackoverflow": {
"name": "Stack Overflow",
"url": "https://stackoverflow.com/search?q={}",
"icon": icons.stackoverflow,
"icon": "stack",
"description": "Search programming questions on Stack Overflow",
},
"wikipedia": {
"name": "Wikipedia",
"url": "https://en.wikipedia.org/wiki/Special:Search?search={}",
"icon": icons.wikipedia,
"icon": "search-menus-symbolic",
"description": "Search articles on Wikipedia",
},
"reddit": {
"name": "Reddit",
"url": "https://www.reddit.com/search/?q={}",
"icon": icons.reddit,
"icon": "reddit-symbolic",
"description": "Search discussions on Reddit",
},
"linkedin": {
"name": "LinkedIn",
"url": "https://www.linkedin.com/search/results/all/?keywords={}",
"icon": icons.linkedin,
"icon": "link",
"description": "Search professionals and jobs on LinkedIn",
},
}
@@ -166,7 +165,7 @@ class WebSearchPlugin(PluginBase):
return Result(
title=f"Open {url}",
subtitle="Open this URL in your default browser",
icon_markup=icons.world,
icon_name="link",
action=lambda u=url: self._open_url(u),
relevance=1.0,
plugin_name=self.display_name,
@@ -190,7 +189,7 @@ class WebSearchPlugin(PluginBase):
result = Result(
title=engine_info["name"],
subtitle=engine_info["description"],
icon_markup=engine_info["icon"],
icon_name=engine_info["icon"],
action=lambda e=engine_id: self._show_engine_help(e),
relevance=1.0 if engine_id == self.default_engine else 0.8,
plugin_name=self.display_name,
@@ -207,7 +206,7 @@ class WebSearchPlugin(PluginBase):
return Result(
title=f"Search '{query}' on {engine_info['name']}",
subtitle=f"{engine_info['description']} - {query}",
icon_markup=engine_info["icon"],
icon_name=engine_info["icon"],
action=lambda e=engine_id, q=query: self._perform_search(e, q),
relevance=1.0 if engine_id == self.default_engine else 0.9,
plugin_name=self.display_name,
@@ -221,7 +220,7 @@ class WebSearchPlugin(PluginBase):
return Result(
title=f"{engine_info['name']} Search",
subtitle=f"{engine_info['description']} - Type your search query",
icon_markup=engine_info["icon"],
icon_name=engine_info["icon"],
action=lambda: None, # No action for info result
relevance=1.0,
plugin_name=self.display_name,