From c0d4662bb3ee8a9ab2cb85dc6870f00a478d64da Mon Sep 17 00:00:00 2001 From: B Stack Date: Fri, 20 Mar 2020 15:27:14 -0400 Subject: add lm trayicon, and fix #1 Add program, its menu entry, and xdg autostart entry (disabled) Fix #1: cli executes valid command but still shows help message --- src/Makefile | 6 +- .../xdg/autostart/logout-manager-trayicon.desktop | 13 ++ src/usr/bin/logout-manager-cli.py | 1 + src/usr/bin/logout-manager-trayicon | 163 +++++++++++++++++++++ .../applications/logout-manager-trayicon.desktop | 12 ++ 5 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 src/etc/xdg/autostart/logout-manager-trayicon.desktop create mode 100755 src/usr/bin/logout-manager-trayicon create mode 100644 src/usr/share/applications/logout-manager-trayicon.desktop diff --git a/src/Makefile b/src/Makefile index 96607d2..010b71e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -18,7 +18,7 @@ # Dependencies: APPNAME = logout-manager -APPVERSION = 0.0.1 +APPVERSION = 0.0.2 SRCDIR = $(CURDIR) prefix = /usr SYSCONFDIR = $(DESTDIR)/etc @@ -32,6 +32,7 @@ APPDIR = $(SHAREDIR)/$(APPNAME) APPSDIR = $(SHAREDIR)/applications BASHCDIR = $(SHAREDIR)/bash-completion/completions SUDOERSDIR = $(SYSCONFDIR)/sudoers.d +XDGAUTODIR = $(SYSCONFDIR)/xdg/autostart awkbin :=$(shell which awk) cpbin :=$(shell which cp) @@ -67,7 +68,7 @@ install: @${echobin} Installing files to ${DESTDIR} ${installbin} -d ${SYSCONFDIR} ${DEFAULTDIR} ${BINDIR} \ ${APPSDIR} ${APPDIR} ${DOCDIR} ${BASHCDIR} ${SUDOERSDIR} \ - ${LIBEXECDIR}/${APPNAME} + ${LIBEXECDIR}/${APPNAME} ${XDGAUTODIR} ${cpbin} -pr ${SRCDIR}/etc/*.* ${SYSCONFDIR} ${cpbin} -pr ${SRCDIR}/etc/sysconfig/* ${DEFAULTDIR} ${cpbin} -pr ${SRCDIR}/usr/bin/* ${BINDIR} @@ -77,6 +78,7 @@ install: ${installbin} -m 0644 -t ${BASHCDIR} ${SRCDIR}/usr/share/bash-completion/completions/* ${installbin} -m 0640 -t ${SUDOERSDIR} ${SRCDIR}/etc/sudoers.d/* ${installbin} -m 0755 -t ${LIBEXECDIR}/${APPNAME} ${SRCDIR}/usr/libexec/${APPNAME}/* + ${installbin} -m 0644 -t ${XDGAUTODIR} ${SRCDIR}/etc/xdg/autostart/* # symlink, when alternatives is not being used ${lnbin} -s logout-manager-gtk.py ${BINDIR}/logout-manager diff --git a/src/etc/xdg/autostart/logout-manager-trayicon.desktop b/src/etc/xdg/autostart/logout-manager-trayicon.desktop new file mode 100644 index 0000000..a1c5713 --- /dev/null +++ b/src/etc/xdg/autostart/logout-manager-trayicon.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Categories=Utility;TrayIcon; +Comment=Shows tray icon for easy logout options +Exec=/usr/bin/logout-manager-trayicon +GenericName=Logout menu on a tray icon +Icon=system-log-out +Keywords=shutdown;hibernate;lockscreen;logout;reboot; +Name=Logout manager tray icon +StartupNotify=true +Terminal=false +Type=Application +Version=1.0 +Hidden=true diff --git a/src/usr/bin/logout-manager-cli.py b/src/usr/bin/logout-manager-cli.py index 64ea133..8fd78b4 100755 --- a/src/usr/bin/logout-manager-cli.py +++ b/src/usr/bin/logout-manager-cli.py @@ -60,6 +60,7 @@ if config.can_hibernate: if args.action in allowed_actions: func = getattr(globals()['actions'],args.action) func(config) + sys.exit(0) elif args.action: eprint("Unable to take action: %s" % str(args.action)) sys.exit(1) diff --git a/src/usr/bin/logout-manager-trayicon b/src/usr/bin/logout-manager-trayicon new file mode 100755 index 0000000..b6471f9 --- /dev/null +++ b/src/usr/bin/logout-manager-trayicon @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 +# File: logout-manager-trayicon +# License: CC-BY-SA 4.0 +# Author: bgstack15 +# Reference: +# icon work https://stackoverflow.com/questions/45162862/how-do-i-set-an-icon-for-the-whole-application-using-pygobject +# button right click must be from "button-press-event" and import Gdk https://python-gtk-3-tutorial.readthedocs.io/en/latest/menus.html +# useful reference https://lazka.github.io/pgi-docs/Gtk-3.0/classes/Button.html#Gtk.Button +# systray info https://github.com/PiSupply/PiJuice/blob/master/Software/Source/src/pijuice_tray.py +# logout-manager-gtk.py +# how to determine double click https://stackoverflow.com/questions/60009648/is-there-a-better-way-to-handle-double-click-in-pygobject +# interactive python3 shell and help(Gdk.EventType) +# https://developer.gnome.org/gtk3/unstable/GtkWidget.html#GtkWidget-button-press-event +# find running processes https://thispointer.com/python-get-list-of-all-running-processes-and-sort-by-highest-memory-usage/ +# send signals https://stackoverflow.com/questions/15080500/how-can-i-send-a-signal-from-a-python-program +# https://docs.python.org/3.8/library/signal.html#module-signal +# Dependencies: +# dep-pip: psutil +# dep-devuan: python3-psutil + +import gi, os, platform, re, sys, psutil, signal +gi.require_version("Gtk","3.0") +from gi.repository import Gtk +from gi.repository import Gdk +from dotenv import load_dotenv + +# all this to load the libpath +try: + defaultdir="/etc/sysconfig" + thisplatform = platform.platform().lower() + if 'debian' in thisplatform or 'devuan' in thisplatform: + defaultdir="/etc/default" + # load_dotenv keeps existing environment variables as higher precedent + load_dotenv(os.path.join(defaultdir,"logout-manager")) +except: + pass +if 'LOGOUT_MANAGER_LIBPATH' in os.environ: + for i in os.environ['LOGOUT_MANAGER_LIBPATH'].split(":"): + sys.path.append(i) +import lmlib + +def is_dryrun(): + result = False + try: + if "DRYRUN" in os.environ and os.environ["DRYRUN"] != "": result = True + except: + pass + return result + +def run_or_kill_logout_manager(): + #print("Run or kill logout manager!") + _lm_is_running = False + lmregex = re.compile("logout-manager.*--from-trayicon") + lmprintregex = re.compile("logout-manager") + thisproc = None + for proc in psutil.process_iter(): + try: + cmdline = " ".join(proc.cmdline()) + #if lmprintregex.search(cmdline) != None: print("Checking \"" + cmdline + "\"") + if lmregex.search(cmdline) != None: + _lm_is_running = True + thisproc = proc + break + except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): + pass + + if _lm_is_running: + #print("Stopping the following process.") + #print(thisproc) + os.kill(thisproc.pid,signal.SIGHUP) + else: + # start new instance + #print("Please start a new instance") + + # this actually returns the new pid, and we could choose to signal only this pid. + # but we will not at this point. + newpid = os.spawnvp(os.P_NOWAIT,"logout-manager",["logout-manager","--from-trayicon"]) + print("spawned",newpid) + +class MainIcon(Gtk.StatusIcon): + def __init__(self,config,actions): + Gtk.StatusIcon.__init__(self) + self.config = config + self.actions = actions + self.set_from_icon_name(self.config.get_logout_icon()) + loggedin_str = "Logged in as " + str(os.environ["USER"]) + tooltiptext = loggedin_str + if is_dryrun(): + tooltiptext = "DRYRUN MODE: " + tooltiptext + self.set_tooltip_text(tooltiptext) + + self.traymenu = Gtk.Menu() + self.add_action_to_menu("Loc_k",self.config.get_lock_icon(),self.on_lock_menuitem) + self.add_action_to_menu("_Logout",self.config.get_logout_icon(),self.on_logout_menuitem) + self.add_action_to_menu("_Hibernate",self.config.get_hibernate_icon(),self.on_hibernate_menuitem) + self.add_action_to_menu("_Shutdown",self.config.get_shutdown_icon(),self.on_shutdown_menuitem) + self.add_action_to_menu("_Reboot",self.config.get_reboot_icon(),self.on_reboot_menuitem) + + # separator + i = Gtk.SeparatorMenuItem.new() + i.show() + self.traymenu.append(i) + + # logged in as + i = Gtk.MenuItem.new_with_label(tooltiptext) + i.set_sensitive(False) + i.show() + self.traymenu.append(i) + + # hide tray icon + i = Gtk.MenuItem.new_with_mnemonic("Hide _tray icon") + i.show() + i.connect("activate", self.exit) + self.traymenu.append(i) + + self.connect("button-press-event", self.on_button_press_event) + self.connect("popup-menu", self.show_menu) + + def on_button_press_event(self, b_unknown, event: Gdk.EventButton): + if Gdk.EventType._2BUTTON_PRESS == event.type: + run_or_kill_logout_manager() + + def exit(self, widget): + quit() + + def show_menu(self, widget, event_button, event_time): + self.traymenu.popup(None, None, + self.position_menu, + self, + event_button, + Gtk.get_current_event_time()) + + def on_lock_menuitem(self, widget): + self.actions.lock(self.config) + + def on_logout_menuitem(self, widget): + self.actions.logout(self.config) + + def on_hibernate_menuitem(self, widget): + self.actions.hibernate(self.config) + + def on_shutdown_menuitem(self, widget): + self.actions.shutdown(self.config) + + def on_reboot_menuitem(self, widget): + self.actions.reboot(self.config) + + def add_action_to_menu(self,label_str,icon_str,function_func): + i = Gtk.ImageMenuItem.new_with_mnemonic(label_str) + j = Gtk.Image.new_from_icon_name(icon_str,32) + j.show() + i.set_image(j) + i.set_always_show_image(True) + i.show() + i.connect("activate", function_func) + self.traymenu.append(i) + +# load configs +config = lmlib.Initialize_config(os.environ['LOGOUT_MANAGER_CONF']) +actions = lmlib.Actions + +icon = MainIcon(config,actions) +Gtk.main() diff --git a/src/usr/share/applications/logout-manager-trayicon.desktop b/src/usr/share/applications/logout-manager-trayicon.desktop new file mode 100644 index 0000000..0379a29 --- /dev/null +++ b/src/usr/share/applications/logout-manager-trayicon.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Categories=Utility;TrayIcon; +Comment=Shows tray icon for easy logout options +Exec=/usr/bin/logout-manager-trayicon +GenericName=Logout menu on a tray icon +Icon=system-log-out +Keywords=shutdown;hibernate;lockscreen;logout;reboot; +Name=Logout manager tray icon +StartupNotify=true +Terminal=false +Type=Application +Version=1.0 -- cgit