forked from clan/clan-core
clan-vm-manager: Added clan icon to trayicon
This commit is contained in:
parent
7fe38a9a80
commit
4f7f34f9b4
@ -18,17 +18,21 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class VMAttr:
|
||||
def __init__(self, state_dir: Path) -> None:
|
||||
# These sockets here are just symlinks to the real sockets which
|
||||
# are created by the run.py file. The reason being that we run into
|
||||
# file path length issues on Linux. If no qemu process is running
|
||||
# the symlink will be dangling.
|
||||
self._qmp_socket: Path = state_dir / "qmp.sock"
|
||||
self._qga_socket: Path = state_dir / "qga.sock"
|
||||
self._qmp: QEMUMonitorProtocol | None = None
|
||||
|
||||
@contextmanager
|
||||
def qmp(self) -> Generator[QEMUMonitorProtocol, None, None]:
|
||||
def qmp_ctx(self) -> Generator[QEMUMonitorProtocol, None, None]:
|
||||
if self._qmp is None:
|
||||
log.debug(f"qmp_socket: {self._qmp_socket}")
|
||||
rpath = self._qmp_socket.resolve()
|
||||
if not rpath.exists():
|
||||
raise ClanError(f"qmp socket {rpath} does not exist")
|
||||
raise ClanError(f"qmp socket {rpath} does not exist. Is the VM running?")
|
||||
self._qmp = QEMUMonitorProtocol(str(rpath))
|
||||
self._qmp.connect()
|
||||
try:
|
||||
|
@ -43,7 +43,7 @@ def wait_vm_up(state_dir: Path) -> None:
|
||||
timeout: float = 300
|
||||
while True:
|
||||
if timeout <= 0:
|
||||
raise TimeoutError(f"qga socket {socket_file} not found")
|
||||
raise TimeoutError(f"qga socket {socket_file} not found. Is the VM running?")
|
||||
if socket_file.exists():
|
||||
break
|
||||
sleep(0.1)
|
||||
@ -56,7 +56,7 @@ def wait_vm_down(state_dir: Path) -> None:
|
||||
timeout: float = 300
|
||||
while socket_file.exists():
|
||||
if timeout <= 0:
|
||||
raise TimeoutError(f"qga socket {socket_file} still exists")
|
||||
raise TimeoutError(f"qga socket {socket_file} still exists. Is the VM down?")
|
||||
sleep(0.1)
|
||||
timeout -= 0.1
|
||||
|
||||
|
@ -11,6 +11,10 @@ GTK4 has a demo application showing all widgets. You can run it by executing:
|
||||
gtk4-widget-factory
|
||||
```
|
||||
|
||||
To find available icons execute:
|
||||
```bash
|
||||
gtk4-icon-browser
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -72,6 +72,24 @@ class MainApplication(Adw.Application):
|
||||
|
||||
return 0
|
||||
|
||||
def get_application_icon_path(self) -> None:
|
||||
self.icon_name = "lol.clan.vm.manager"
|
||||
if not self.icon_name:
|
||||
return None
|
||||
|
||||
icon_theme = Gtk.IconTheme.get_for_display(
|
||||
self.get_active_window().get_display()
|
||||
)
|
||||
# Use the correct method to look up an icon
|
||||
icon_lookup_flags = 16
|
||||
icon = icon_theme.lookup_icon(
|
||||
self.icon_name, 128, 1.0, Gtk.TextDirection.NONE, icon_lookup_flags
|
||||
)
|
||||
|
||||
if icon:
|
||||
return icon.get_file().get_path()
|
||||
return None
|
||||
|
||||
def on_shutdown(self, app: Gtk.Application) -> None:
|
||||
log.debug("Shutting down")
|
||||
|
||||
@ -84,9 +102,8 @@ class MainApplication(Adw.Application):
|
||||
assert self.window is not None
|
||||
if self.window.is_visible():
|
||||
self.window.hide()
|
||||
return
|
||||
|
||||
self.window.present()
|
||||
else:
|
||||
self.window.present()
|
||||
|
||||
def dummy_menu_entry(self) -> None:
|
||||
log.info("Dummy menu entry called")
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
@ -253,7 +253,7 @@ class VM(GObject.Object):
|
||||
log.info(f"Stopping VM {self.get_id()}")
|
||||
|
||||
try:
|
||||
with self.machine.vm.qmp() as qmp:
|
||||
with self.machine.vm.qmp_ctx() as qmp:
|
||||
qmp.command("system_powerdown")
|
||||
except ClanError as e:
|
||||
log.debug(e)
|
||||
|
@ -172,7 +172,7 @@ class BaseImplementation:
|
||||
self.application = application
|
||||
self.menu_items: dict[int, Any] = {}
|
||||
self.menu_item_id: int = 1
|
||||
self.activate_callback: Callable = application.on_window_hide_unhide
|
||||
self.activate_callback: Callable = lambda a, b: self.update_window_visibility
|
||||
self.is_visible: bool = True
|
||||
|
||||
self.create_menu()
|
||||
@ -213,16 +213,12 @@ class BaseImplementation:
|
||||
|
||||
def create_menu(self) -> None:
|
||||
self.show_hide_item = self.create_item(
|
||||
"default", self.application.dummy_menu_entry
|
||||
"default", self.application.on_window_hide_unhide
|
||||
)
|
||||
|
||||
self.connect_disconnect_item = self.create_item(
|
||||
"default", self.application.dummy_menu_entry
|
||||
)
|
||||
# self.create_item()
|
||||
|
||||
self.create_item()
|
||||
|
||||
self.create_item("_Quit", self.application.dummy_menu_entry)
|
||||
# self.create_item("_Quit", self.application.on_shutdown)
|
||||
|
||||
def update_window_visibility(self) -> None:
|
||||
if self.application.window is None:
|
||||
@ -237,14 +233,6 @@ class BaseImplementation:
|
||||
self.update_menu()
|
||||
|
||||
def update_user_status(self) -> None:
|
||||
sensitive = core.users.login_status != slskmessages.UserStatus.OFFLINE
|
||||
label = "_Disconnect" if sensitive else "_Connect"
|
||||
|
||||
# self.set_item_sensitive(self.away_item, sensitive)
|
||||
|
||||
self.set_item_text(self.connect_disconnect_item, label)
|
||||
# self.set_item_toggled(self.away_item, core.users.login_status == slskmessages.UserStatus.AWAY)
|
||||
|
||||
self.update_icon()
|
||||
self.update_menu()
|
||||
|
||||
@ -266,9 +254,9 @@ class BaseImplementation:
|
||||
# icon_name = "disconnect"
|
||||
|
||||
# icon_name = f"{pynicotine.__application_id__}-{icon_name}"
|
||||
# self.set_icon_name(icon_name)
|
||||
# self.set_icon(icon_name)
|
||||
|
||||
def set_icon_name(self, icon_name: str) -> None:
|
||||
def set_icon(self, icon_name: str) -> None:
|
||||
# Implemented in subclasses
|
||||
pass
|
||||
|
||||
@ -410,6 +398,7 @@ class StatusNotifierImplementation(BaseImplementation):
|
||||
):
|
||||
method = self.methods[method_name]
|
||||
result = method.callback(*parameters.unpack())
|
||||
|
||||
out_arg_types = "".join(method.out_args)
|
||||
return_value = None
|
||||
|
||||
@ -570,6 +559,11 @@ class StatusNotifierImplementation(BaseImplementation):
|
||||
)
|
||||
self.tray_icon.register()
|
||||
|
||||
from .assets import loc
|
||||
|
||||
icon_path = str(loc / "clan_white_notext.png")
|
||||
self.set_icon(icon_path)
|
||||
|
||||
self.bus.call_sync(
|
||||
bus_name="org.kde.StatusNotifierWatcher",
|
||||
object_path="/StatusNotifierWatcher",
|
||||
@ -617,38 +611,12 @@ class StatusNotifierImplementation(BaseImplementation):
|
||||
"""Returns an icon path to use for tray icons, or None to fall back to
|
||||
system-wide icons."""
|
||||
|
||||
self.custom_icons = False
|
||||
custom_icon_path = os.path.join(config.data_folder_path, ".nicotine-icon-theme")
|
||||
|
||||
if hasattr(sys, "real_prefix") or sys.base_prefix != sys.prefix:
|
||||
# Virtual environment
|
||||
local_icon_path = os.path.join(
|
||||
sys.prefix, "share", "icons", "hicolor", "scalable", "apps"
|
||||
)
|
||||
else:
|
||||
# Git folder
|
||||
local_icon_path = os.path.join(
|
||||
GTK_GUI_FOLDER_PATH, "icons", "hicolor", "scalable", "apps"
|
||||
)
|
||||
|
||||
for icon_name in ("away", "connect", "disconnect", "msg"):
|
||||
# Check if custom icons exist
|
||||
if self.check_icon_path(icon_name, custom_icon_path):
|
||||
self.custom_icons = True
|
||||
return custom_icon_path
|
||||
|
||||
# Check if local icons exist
|
||||
if self.check_icon_path(icon_name, local_icon_path):
|
||||
return local_icon_path
|
||||
# icon_path = self.application.get_application_icon_path()
|
||||
|
||||
return ""
|
||||
|
||||
def set_icon_name(self, icon_name):
|
||||
if self.custom_icons:
|
||||
# Use alternative icon names to enforce custom icons, since system-wide icons take precedence
|
||||
icon_name = icon_name.replace(pynicotine.__application_id__, "nplus-tray")
|
||||
|
||||
self.tray_icon.properties["IconName"].value = icon_name
|
||||
def set_icon(self, icon_path) -> None:
|
||||
self.tray_icon.properties["IconName"].value = icon_path
|
||||
self.tray_icon.emit_signal("NewIcon")
|
||||
|
||||
if not self.is_visible:
|
||||
@ -1064,7 +1032,7 @@ class Win32Implementation(BaseImplementation):
|
||||
self._menu, item_id, False, byref(item_info)
|
||||
)
|
||||
|
||||
def set_icon_name(self, icon_name):
|
||||
def set_icon(self, icon_name):
|
||||
self._update_notify_icon(icon_name=icon_name)
|
||||
|
||||
def show_notification(self, title, message):
|
||||
|
Loading…
Reference in New Issue
Block a user