aboutsummaryrefslogtreecommitdiff
path: root/src/usr/bin/logout-manager-gtk.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/bin/logout-manager-gtk.py')
-rwxr-xr-xsrc/usr/bin/logout-manager-gtk.py252
1 files changed, 252 insertions, 0 deletions
diff --git a/src/usr/bin/logout-manager-gtk.py b/src/usr/bin/logout-manager-gtk.py
new file mode 100755
index 0000000..553fc41
--- /dev/null
+++ b/src/usr/bin/logout-manager-gtk.py
@@ -0,0 +1,252 @@
+#!/usr/bin/env python3
+# File: logout-manager-gtk.py
+# License: CC-BY-SA 4.0
+# Author: bgstack15
+# Startdate: 2019-06-01
+# Title: GTK3 based logout manager
+# Purpose: Primarily for fluxbox, this tool provides a graphical menu for various session control commands like shutdown, logout, and reboot
+# History:
+# Usage:
+# This is a bit for reference, but also to provide myself a little shutdown options menu, like xfce4, because fluxbox doesn't really provide one.
+# Reference:
+# https://www.linuxquestions.org/questions/slackware-14/how-do-i-run-menu-and-logout-from-the-command-line-in-fluxbox-864919/
+# /mnt/public/work/python/hotplug2/
+# icon handling https://python-gtk-3-tutorial.readthedocs.io/en/latest/iconview.html
+# accelerator keys https://askubuntu.com/questions/655452/python-gtk3-keyboard-accelerators
+# gtk3 widget signals https://developer.gnome.org/gtk3/unstable/GtkWidget.html#GtkWidget-button-press-event
+# /usr/share/wicd/gtk/gui.py netentry.py wicd.ui
+# combined with next ref: scale down valid icon https://stackoverflow.com/questions/42800482/how-to-set-size-of-a-gtk-image-in-python
+# https://stackoverflow.com/questions/6090241/how-can-i-get-the-full-file-path-of-an-icon-name
+# use custom icon theme https://lazka.github.io/pgi-docs/Gtk-3.0/classes/IconTheme.html#Gtk.IconTheme.set_custom_theme
+# https://stackoverflow.com/questions/4090804/how-can-i-pass-variables-between-two-classes-windows-in-pygtk
+# Improve:
+# actually execute the commands
+# only show debug info when DEBUG=1 or similar.
+# support global conf file, and user conf file
+# far future: provide graphical way to change commands run
+# Dependencies:
+# Devuan: python3-dotenv
+# Documentation:
+
+import gi, os, platform, sys
+gi.require_version("Gtk", "3.0")
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository.GdkPixbuf import Pixbuf
+from pathlib import Path
+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
+
+# graphical classes and functions
+def get_scaled_icon(icon_name, size=24, fallback_icon_name = "", icon_theme = "default"):
+ # return a Gtk.Image.new_from_pixbuf
+
+ # ripped from https://stackoverflow.com/questions/42800482/how-to-set-size-of-a-gtk-image-in-python and combined with https://stackoverflow.com/questions/6090241/how-can-i-get-the-full-file-path-of-an-icon-name
+ # further ref for lookup_icon function: https://lazka.github.io/pgi-docs/Gtk-3.0/flags.html#Gtk.IconLookupFlags
+ # if a file exists by the specific name, use it.
+ if Path(icon_name).is_file():
+ iconfilename = icon_name
+ else:
+ if icon_theme != "default":
+ this_theme = Gtk.IconTheme.new()
+ this_theme.set_custom_theme(icon_theme)
+ else:
+ this_theme = Gtk.IconTheme.get_default()
+ try:
+ icon_info = this_theme.lookup_icon(icon_name, size, 0)
+ iconfilename = icon_info.get_filename()
+ except:
+ try:
+ icon_info = this_theme.lookup_icon(fallback_icon_name, size, 0)
+ iconfilename = icon_info.get_filename()
+ except:
+ # no icon in the current theme. Try a hard-coded fallback:
+ try:
+ # if debuglev 3
+ print("Error: could not find default icon for", icon_name+", so using fallback.")
+ this_theme = Gtk.IconTheme.new()
+ this_theme.set_custom_theme("Numix-Circle")
+ icon_info = this_theme.lookup_icon(icon_name, size, 0)
+ iconfilename = icon_info.get_filename()
+ except:
+ print("Error: Could not find any icon for", icon_name)
+ return None
+ #print(iconfilename)
+ return Gtk.Image.new_from_pixbuf(Pixbuf.new_from_file_at_scale(
+ filename=iconfilename,
+ width=size, height=size, preserve_aspect_ratio=True))
+
+class MainWindow(Gtk.Window):
+ def __init__(self, config, actions):
+ self.actions = actions
+ self.config = config
+ Gtk.Window.__init__(self, title="Log out options")
+ # for window icon
+ liststore = Gtk.ListStore(Pixbuf, str)
+ iconview = Gtk.IconView.new()
+ iconview.set_model(liststore)
+ iconview.set_pixbuf_column(0)
+ iconview.set_text_column(1)
+ pixbuf24 = Gtk.IconTheme.get_default().load_icon(config.application_icon, 24, 0)
+ pixbuf32 = Gtk.IconTheme.get_default().load_icon(config.application_icon, 32, 0)
+ pixbuf48 = Gtk.IconTheme.get_default().load_icon(config.application_icon, 48, 0)
+ pixbuf64 = Gtk.IconTheme.get_default().load_icon(config.application_icon, 64, 0)
+ pixbuf96 = Gtk.IconTheme.get_default().load_icon(config.application_icon, 96, 0)
+ self.set_icon_list([pixbuf24, pixbuf32, pixbuf48, pixbuf64, pixbuf96]);
+
+ # accel is for when you are not using the "set_use_underline" function.
+ #accel = Gtk.AccelGroup()
+ #accel.connect(Gdk.keyval_from_name('D'), Gdk.ModifierType.MOD1_MASK, 0, self.on_button2_accel)
+ #self.add_accel_group(accel)
+
+ # buttons
+ self.grid = Gtk.Grid()
+ self.add(self.grid)
+
+ self.button0 = Gtk.Button(label="Loc_k")
+ self.button0.connect("button-press-event", self.on_button0_press_event)
+ self.button0.connect("activate", self.on_button0_press_event) # activate covers ALT+L action and spacebar when selected
+ self.buttonicon0 = get_scaled_icon(config.get_lock_icon(), config.get_icon_size(), config.get_lock_fallback_icon(), config.get_icon_theme())
+ self.button0.set_image(self.buttonicon0)
+ self.button0.set_tooltip_text("Hide session and require authentication to return to it")
+ self.button0.set_always_show_image(True)
+ self.button0.set_use_underline(True)
+ self.grid.add(self.button0)
+
+ self.button1 = Gtk.Button(label="_Logout")
+ self.button1.connect("button-press-event", self.on_button1_press_event)
+ self.button1.connect("activate", self.on_button1_press_event) # activate covers ALT+L action and spacebar when selected
+ self.buttonicon1 = get_scaled_icon(config.get_logout_icon(), config.get_icon_size(), config.get_logout_fallback_icon(), config.get_icon_theme())
+ self.button1.set_image(self.buttonicon1)
+ self.button1.set_tooltip_text("Close the current user session")
+ self.button1.set_always_show_image(True)
+ self.button1.set_use_underline(True)
+ self.grid.add(self.button1)
+
+ self.buttonHibernate = Gtk.Button(label="_Hibernate")
+ self.buttonHibernate.connect("button-press-event", self.on_buttonHibernate_press_event)
+ self.buttonHibernate.connect("activate", self.on_buttonHibernate_press_event) # activate covers ALT+L action and spacebar when selected
+ #self.buttoniconHibernate = Gtk.Image()
+ #self.buttoniconHibernate.set_from_icon_name("system-hibernate", 24)
+ self.buttoniconHibernate = get_scaled_icon(config.get_hibernate_icon(), config.get_icon_size(), config.get_hibernate_fallback_icon(), config.get_icon_theme())
+ self.buttonHibernate.set_image(self.buttoniconHibernate)
+ self.buttonHibernate.set_tooltip_text("Save state to disk and power off")
+ self.buttonHibernate.set_always_show_image(True)
+ self.buttonHibernate.set_use_underline(True)
+ self.buttonHibernate.set_sensitive(True if config.get_can_hibernate() else False)
+ self.grid.add(self.buttonHibernate)
+
+ self.button2 = Gtk.Button(label="_Shutdown")
+ self.button2.connect("button-press-event", self.on_button2_press_event)
+ self.button2.connect("activate", self.on_button2_accel)
+ # unnecessary because the "activate" suffices above.
+ #self.button2.connect("mnemonic-activate", self.on_button2_accel)
+ self.buttonicon2 = Gtk.Image()
+ self.buttonicon2 = get_scaled_icon(config.get_shutdown_icon(), config.get_icon_size(), config.get_shutdown_fallback_icon(), config.get_icon_theme())
+ self.button2.set_image(self.buttonicon2)
+ self.button2.set_tooltip_text("Power off the computer")
+ self.button2.set_always_show_image(True)
+ self.button2.set_use_underline(True)
+ self.grid.add(self.button2)
+
+ self.button3 = Gtk.Button(label="_Reboot")
+ self.button3.connect("button-press-event", self.on_button3_press_event)
+ self.button3.connect("activate", self.on_button3_press_event)
+ self.buttonicon3 = Gtk.Image()
+ self.buttonicon3 = get_scaled_icon(config.get_reboot_icon(), config.get_icon_size(), config.get_reboot_fallback_icon(), config.get_icon_theme())
+ self.button3.set_image(self.buttonicon3)
+ self.button3.set_tooltip_text("Reboot the computer back to the login screen")
+ self.button3.set_always_show_image(True)
+ self.button3.set_use_underline(True)
+ self.grid.add(self.button3)
+
+ self.button4 = Gtk.Button(label="_Cancel")
+ self.button4.connect("button-press-event", self.on_button4_press_event)
+ self.button4.connect("activate", self.on_button4_press_event)
+ self.button4.set_tooltip_text("Do nothing; just close this window")
+ self.button4.set_use_underline(True)
+ self.grid.attach(self.button4, 0, 1, 8, 1)
+
+ # hibernate button
+ def on_buttonHibernate_press_event(self, *args):
+ self.do_hibernate(self.buttonHibernate)
+
+ # lock button
+ def on_button0_press_event(self, *args):
+ self.do_lock(self.button0)
+
+ # logout button
+ def on_button1_press_event(self, *args):
+ self.do_logout(self.button1)
+
+ # shutdown button
+ def on_button2_press_event(self, widget, event):
+ # check if left or right click
+ if event.type == Gdk.EventType.BUTTON_PRESS:
+ if event.button == 1:
+ self.do_shutdown(widget)
+ # eventbutton == 3 is the right-click, and its reference is my hello3.py
+ #elif event.button == 3:
+ # self.on_button1_right_clicked(widget)
+
+ # global accelerator key, when not using the set_use_underline function
+ ## shutdown button from accelerator key
+ #def on_button2_accel(self, *args):
+ # self.do_shutdown(self.button2)
+
+ # accelerator key from set_use_underline function
+ # shutdown button from accelerator key
+ def on_button2_accel(self, *args):
+ self.do_shutdown(self.button2)
+
+ # reboot button
+ def on_button3_press_event(self, *args):
+ self.do_reboot(self.button3)
+
+ # cancel button
+ def on_button4_press_event(self, *args):
+ self.cancel(self.button4)
+
+ def do_shutdown(self, *args):
+ #print(dir(self.props))
+ self.actions.shutdown(self.config)
+
+ def do_hibernate(self, widget):
+ self.actions.hibernate(self.config)
+
+ def do_lock(self, widget):
+ self.actions.lock(self.config)
+
+ def do_logout(self, widget):
+ self.actions.logout(self.config)
+
+ def do_reboot(self, widget):
+ self.actions.reboot(self.config)
+
+ def cancel(self, widget):
+ print("Cancel any logout action.")
+ Gtk.main_quit()
+
+# load configs
+config = lmlib.Initialize_config(os.environ['LOGOUT_MANAGER_CONF'])
+actions = lmlib.Actions
+
+# MAIN LOOP
+win = MainWindow(config, actions)
+win.connect("destroy", Gtk.main_quit)
+win.show_all()
+Gtk.main()
bgstack15